chiark / gitweb /
*_id: fix zero length in set_str()
[elogind.git] / extras / scsi_id / scsi_id.c
index 86b84bee30e6337e4c04680d75771b98fa3003f9..a86b004709a219c4fa8cb68125a2c7ff05b63e3a 100644 (file)
@@ -52,7 +52,7 @@
  * options are not supported, but other code is still left in place for
  * now.
  */
-static const char short_options[] = "bd:f:gip:s:uvVx";
+static const char short_options[] = "abd:f:gip:s:uvVx";
 /*
  * Just duplicate per dev options.
  */
@@ -61,6 +61,7 @@ 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;
@@ -74,6 +75,8 @@ 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, ...)
 {
@@ -98,32 +101,74 @@ void log_message (int level, const char *format, ...)
        return;
 }
 
-static void set_str(char *to, const unsigned char *from, int count)
+static void set_str(char *to, const char *from, size_t count)
 {
-       int i, j;
-       int len;
+       size_t i, j, len;
 
+       /* strip trailing whitespace */
        len = strnlen(from, count);
-       while (isspace(from[len-1]))
+       while (len && isspace(from[len-1]))
                len--;
 
+       /* strip leading whitespace */
        i = 0;
        while (isspace(from[i]) && (i < len))
                i++;
 
        j = 0;
        while (i < len) {
-               switch(from[i]) {
-               case '/':
-               case ' ':
+               /* 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:
-                       to[j++] = from[i];
+                       break;
                }
-               i++;
        }
-       to[j] = '\0';
+       strncpy(to, type, len);
+       to[len-1] = '\0';
 }
 
 static int get_major_minor(struct sysfs_class_device *class_dev, int *maj,
@@ -430,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;
 
@@ -440,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;
@@ -521,7 +569,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;
@@ -547,6 +595,22 @@ static int per_dev_options(struct sysfs_device *scsi_dev, int *good_bad,
        }
        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);
 
@@ -616,7 +680,6 @@ static void format_serial(char *serial)
                        *p = '_';
                p++;
        }
-return;
 }
 
 /*
@@ -750,7 +813,7 @@ 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;
        }
@@ -759,8 +822,11 @@ static int scsi_id(const char *target_path, char *maj_min_dev)
                        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);