chiark / gitweb /
fold multiple consecutive whitespace chars into single '_'
[elogind.git] / extras / scsi_id / scsi_id.c
index 32a96d8adb7150aaeb88b630dcb76b434ccc571d..aa1b16009e9f989cd301dfe9d78acd16391de767 100644 (file)
 /*
  * temporary names for mknod.
  */
-#define TMP_DIR        "/tmp"
-#define TMP_PREFIX "scsi"
+#define TMP_DIR        "/dev"
+#define TMP_PREFIX "tmp-scsi"
 
 /*
  * XXX Note the 'e' (send output to stderr in all cases), and 'c' (callout)
  * options are not supported, but other code is still left in place for
  * now.
  */
-static const char short_options[] = "bd:f:gip:s:uvV";
+static const char short_options[] = "abd:f:gip:s:uvVx";
 /*
  * Just duplicate per dev options.
  */
@@ -61,16 +61,22 @@ static const char dev_short_options[] = "bgp:";
 char sysfs_mnt_path[SYSFS_PATH_MAX];
 
 static int all_good;
+static int always_info;
 static char *default_callout;
 static int dev_specified;
 static int sys_specified;
 static char config_file[MAX_NAME_LEN] = SCSI_ID_CONFIG_FILE;
 static int display_bus_id;
-static int default_page_code;
+static enum page_code default_page_code;
 static int use_stderr;
 static int debug;
 static int hotplug_mode;
 static int reformat_serial;
+static int export;
+static char vendor_str[64];
+static char model_str[64];
+static char revision_str[16];
+static char type_str[16];
 
 void log_message (int level, const char *format, ...)
 {
@@ -84,13 +90,8 @@ void log_message (int level, const char *format, ...)
                vfprintf(stderr, format, args);
        } else {
                static int logging_init = 0;
-               static unsigned char logname[32];
                if (!logging_init) {
-                       /*
-                        * klibc does not have LOG_PID.
-                        */
-                       snprintf(logname, 32, "scsi_id[%d]", getpid());
-                       openlog (logname, 0, LOG_DAEMON);
+                       openlog ("scsi_id", LOG_PID, LOG_DAEMON);
                        logging_init = 1;
                }
 
@@ -100,6 +101,76 @@ void log_message (int level, const char *format, ...)
        return;
 }
 
+static void set_str(char *to, const char *from, size_t count)
+{
+       size_t i, j, len;
+
+       /* strip trailing whitespace */
+       len = strnlen(from, count);
+       while (len && isspace(from[len-1]))
+               len--;
+
+       /* strip leading whitespace */
+       i = 0;
+       while (isspace(from[i]) && (i < len))
+               i++;
+
+       j = 0;
+       while (i < len) {
+               /* substitute multiple whitespace */
+               if (isspace(from[i])) {
+                       while (isspace(from[i]))
+                               i++;
+                       to[j++] = '_';
+               }
+               /* skip chars */
+               if (from[i] == '/') {
+                       i++;
+                       continue;
+               }
+               to[j++] = from[i++];
+       }
+       to[j] = '\0';
+}
+
+static void set_type(char *to, const char *from, size_t len)
+{
+       int type_num;
+       char *eptr;
+       char *type = "generic";
+
+       type_num = strtoul(from, &eptr, 0);
+       if (eptr != from) {
+               switch (type_num) {
+               case 0:
+                       type = "disk";
+                       break;
+               case 1:
+                       type = "tape";
+                       break;
+               case 4:
+                       type = "optical";
+                       break;
+               case 5:
+                       type = "cd";
+                       break;
+               case 7:
+                       type = "optical";
+                       break;
+               case 0xe:
+                       type = "disk";
+                       break;
+               case 0xf:
+                       type = "optical";
+                       break;
+               default:
+                       break;
+               }
+       }
+       strncpy(to, type, len);
+       to[len-1] = '\0';
+}
+
 static int get_major_minor(struct sysfs_class_device *class_dev, int *maj,
                           int *min)
 {
@@ -404,7 +475,7 @@ static int set_options(int argc, char **argv, const char *short_opts,
         */
        optind = 1;
        while (1) {
-               option = getopt(argc, argv, short_options);
+               option = getopt(argc, argv, short_opts);
                if (option == -1)
                        break;
 
@@ -414,6 +485,9 @@ static int set_options(int argc, char **argv, const char *short_opts,
                        dprintf("option '%c'\n", option);
 
                switch (option) {
+               case 'a':
+                       always_info = 1;
+                       break;
                case 'b':
                        all_good = 0;
                        break;
@@ -445,9 +519,11 @@ static int set_options(int argc, char **argv, const char *short_opts,
 
                case 'p':
                        if (strcmp(optarg, "0x80") == 0) {
-                               default_page_code = 0x80;
+                               default_page_code = PAGE_80;
                        } else if (strcmp(optarg, "0x83") == 0) {
-                               default_page_code = 0x83;
+                               default_page_code = PAGE_83;
+                       } else if (strcmp(optarg, "pre-spc3-83") == 0) {
+                               default_page_code = PAGE_83_PRE_SPC3; 
                        } else {
                                log_message(LOG_WARNING,
                                            "Unknown page code '%s'\n", optarg);
@@ -465,6 +541,10 @@ static int set_options(int argc, char **argv, const char *short_opts,
                        reformat_serial = 1;
                        break;
 
+               case 'x':
+                       export = 1;
+                       break;
+
                case 'v':
                        debug++;
                        break;
@@ -491,7 +571,7 @@ static int per_dev_options(struct sysfs_device *scsi_dev, int *good_bad,
        int retval;
        int newargc;
        char **newargv = NULL;
-       struct sysfs_attribute *vendor, *model;
+       struct sysfs_attribute *vendor, *model, *type;
        int option;
 
        *good_bad = all_good;
@@ -507,6 +587,7 @@ static int per_dev_options(struct sysfs_device *scsi_dev, int *good_bad,
                            scsi_dev->name);
                return -1;
        }
+       set_str(vendor_str, vendor->value, sizeof(vendor_str)-1);
 
        model = sysfs_get_device_attr(scsi_dev, "model");
        if (!model) {
@@ -514,6 +595,23 @@ static int per_dev_options(struct sysfs_device *scsi_dev, int *good_bad,
                            scsi_dev->name);
                return -1;
        }
+       set_str(model_str, model->value, sizeof(model_str)-1);
+
+       type = sysfs_get_device_attr(scsi_dev, "type");
+       if (!type) {
+               log_message(LOG_WARNING, "%s: cannot get type attribute\n",
+                           scsi_dev->name);
+               return -1;
+       }
+       set_type(type_str, type->value, sizeof(type_str));
+
+       type = sysfs_get_device_attr(scsi_dev, "rev");
+       if (!type) {
+               log_message(LOG_WARNING, "%s: cannot get type attribute\n",
+                           scsi_dev->name);
+               return -1;
+       }
+       set_str(revision_str, type->value, sizeof(revision_str)-1);
 
        retval = get_file_options(vendor->value, model->value, &newargc,
                                  &newargv);
@@ -544,9 +642,11 @@ static int per_dev_options(struct sysfs_device *scsi_dev, int *good_bad,
 
                case 'p':
                        if (strcmp(optarg, "0x80") == 0) {
-                               *page_code = 0x80;
+                               *page_code = PAGE_80;
                        } else if (strcmp(optarg, "0x83") == 0) {
-                               *page_code = 0x83;
+                               *page_code = PAGE_83;
+                       } else if (strcmp(optarg, "pre-spc3-83") == 0) {
+                               *page_code = PAGE_83_PRE_SPC3; 
                        } else {
                                log_message(LOG_WARNING,
                                            "Unknown page code '%s'\n", optarg);
@@ -577,14 +677,22 @@ static int per_dev_options(struct sysfs_device *scsi_dev, int *good_bad,
  */
 static void format_serial(char *serial)
 {
-       char *p = serial;
+       char *p = serial, *q;
 
+       q = p;
        while (*p != '\0') {
-               if (isspace(*p))
-                       *p = '_';
+               if (isspace(*p)) {
+                       if (q > serial && q[-1] != '_') {
+                               *q = '_';
+                               q++;
+                       }
+               } else {
+                       *q = *p;
+                       q++;
+               }
                p++;
        }
-       return;
+       *q = '\0';
 }
 
 /*
@@ -718,16 +826,27 @@ static int scsi_id(const char *target_path, char *maj_min_dev)
                retval = 1;
        } else if (scsi_get_serial(scsi_dev, maj_min_dev, page_code,
                                   serial, MAX_SERIAL_LEN)) {
-               retval = 1;
+               retval = always_info?0:1;
        } else {
                retval = 0;
        }
        if (!retval) {
-               if (reformat_serial)
-                       format_serial(serial);
-               if (display_bus_id)
-                       printf("%s: ", scsi_dev->name);
-               printf("%s\n", serial);
+               if (export) {
+                       static char serial_str[64];
+                       printf("ID_VENDOR=%s\n", vendor_str);
+                       printf("ID_MODEL=%s\n", model_str);
+                       printf("ID_REVISION=%s\n", revision_str);
+                       set_str(serial_str, serial, sizeof(serial_str));
+                       printf("ID_SERIAL=%s\n", serial_str);
+                       printf("ID_TYPE=%s\n", type_str);
+                       printf("ID_BUS=scsi\n");
+               } else {
+                       if (reformat_serial)
+                               format_serial(serial);
+                       if (display_bus_id)
+                               printf("%s: ", scsi_dev->name);
+                       printf("%s\n", serial);
+               }
                dprintf("%s\n", serial);
                retval = 0;
        }