chiark / gitweb /
[PATCH] klibc: version 1.0.7
[elogind.git] / extras / scsi_id / scsi_id.c
index e893987868cf2f7a7ddb5674b0d6dda975c764d5..32a96d8adb7150aaeb88b630dcb76b434ccc571d 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:vV";
+static const char short_options[] = "bd:f:gip:s:uvV";
 /*
  * Just duplicate per dev options.
  */
@@ -70,6 +70,7 @@ static int default_page_code;
 static int use_stderr;
 static int debug;
 static int hotplug_mode;
+static int reformat_serial;
 
 void log_message (int level, const char *format, ...)
 {
@@ -99,23 +100,13 @@ void log_message (int level, const char *format, ...)
        return;
 }
 
-int sysfs_get_attr(const char *devpath, const char *attr, char *value,
-                  size_t bufsize)
+static int get_major_minor(struct sysfs_class_device *class_dev, int *maj,
+                          int *min)
 {
-       char attr_path[SYSFS_PATH_MAX];
+       struct sysfs_attribute *dev_attr;
 
-       strncpy(attr_path, devpath, SYSFS_PATH_MAX);
-       strncat(attr_path, "/", SYSFS_PATH_MAX);
-       strncat(attr_path, attr,  SYSFS_PATH_MAX);
-       dprintf("%s\n", attr_path);
-       return sysfs_read_attribute_value(attr_path, value, SYSFS_NAME_LEN);
-}
-
-static int get_major_minor(const char *devpath, int *maj, int *min)
-{
-       char dev_value[MAX_ATTR_LEN];
-
-       if (sysfs_get_attr(devpath, "dev", dev_value, MAX_ATTR_LEN)) {
+       dev_attr = sysfs_get_classdev_attr(class_dev, "dev");
+       if (!dev_attr) {
                /*
                 * XXX This happens a lot, since sg has no dev attr.
                 * And now sysfsutils does not set a meaningful errno
@@ -124,27 +115,28 @@ static int get_major_minor(const char *devpath, int *maj, int *min)
                 * it separately.
                 */
                log_message(LOG_DEBUG, "%s: could not get dev attribute: %s\n",
-                       devpath, strerror(errno));
+                       class_dev->name, strerror(errno));
                return -1;
        }
 
-       dprintf("dev value %s", dev_value); /* dev_value has a trailing \n */
-       if (sscanf(dev_value, "%u:%u", maj, min) != 2) {
+       dprintf("dev value %s", dev_attr->value); /* value has a trailing \n */
+       if (sscanf(dev_attr->value, "%u:%u", maj, min) != 2) {
                log_message(LOG_WARNING, "%s: invalid dev major/minor\n",
-                           devpath);
+                           class_dev->name);
                return -1;
        }
 
        return 0;
 }
 
-static int create_tmp_dev(const char *devpath, char *tmpdev, int dev_type)
+static int create_tmp_dev(struct sysfs_class_device *class_dev, char *tmpdev,
+                         int dev_type)
 {
        int maj, min;
 
-       dprintf("(%s)\n", devpath);
+       dprintf("(%s)\n", class_dev->name);
 
-       if (get_major_minor(devpath, &maj, &min))
+       if (get_major_minor(class_dev, &maj, &min))
                return -1;
        snprintf(tmpdev, MAX_NAME_LEN, "%s/%s-maj%d-min%d-%u",
                 TMP_DIR, TMP_PREFIX, maj, min, getpid());
@@ -469,6 +461,10 @@ static int set_options(int argc, char **argv, const char *short_opts,
                        strncat(target, optarg, MAX_NAME_LEN);
                        break;
 
+               case 'u':
+                       reformat_serial = 1;
+                       break;
+
                case 'v':
                        debug++;
                        break;
@@ -495,8 +491,7 @@ static int per_dev_options(struct sysfs_device *scsi_dev, int *good_bad,
        int retval;
        int newargc;
        char **newargv = NULL;
-       char vendor[MAX_ATTR_LEN];
-       char model[MAX_ATTR_LEN];
+       struct sysfs_attribute *vendor, *model;
        int option;
 
        *good_bad = all_good;
@@ -506,19 +501,22 @@ static int per_dev_options(struct sysfs_device *scsi_dev, int *good_bad,
        else
                callout[0] = '\0';
 
-       if (sysfs_get_attr(scsi_dev->path, "vendor", vendor, MAX_ATTR_LEN)) {
+       vendor = sysfs_get_device_attr(scsi_dev, "vendor");
+       if (!vendor) {
                log_message(LOG_WARNING, "%s: cannot get vendor attribute\n",
                            scsi_dev->name);
                return -1;
        }
 
-       if (sysfs_get_attr(scsi_dev->path, "model", model, MAX_ATTR_LEN)) {
+       model = sysfs_get_device_attr(scsi_dev, "model");
+       if (!model) {
                log_message(LOG_WARNING, "%s: cannot get model attribute\n",
                            scsi_dev->name);
                return -1;
        }
 
-       retval = get_file_options(vendor, model, &newargc, &newargv);
+       retval = get_file_options(vendor->value, model->value, &newargc,
+                                 &newargv);
 
        optind = 1; /* reset this global extern */
        while (retval == 0) {
@@ -572,6 +570,23 @@ static int per_dev_options(struct sysfs_device *scsi_dev, int *good_bad,
        return retval;
 }
 
+/*
+ * format_serial: replace to whitespaces by underscores for calling
+ * programs that use the serial for device naming (multipath, Suse
+ * naming, etc...)
+ */
+static void format_serial(char *serial)
+{
+       char *p = serial;
+
+       while (*p != '\0') {
+               if (isspace(*p))
+                       *p = '_';
+               p++;
+       }
+       return;
+}
+
 /*
  * scsi_id: try to get an id, if one is found, printf it to stdout.
  * returns a value passed to exit() - 0 if printed an id, else 1. This
@@ -583,7 +598,7 @@ static int scsi_id(const char *target_path, char *maj_min_dev)
 {
        int retval;
        int dev_type = 0;
-       char serial[MAX_SERIAL_LEN];
+       char *serial, *unaligned_buf;
        struct sysfs_class_device *class_dev; /* of target_path */
        struct sysfs_class_device *class_dev_parent; /* for partitions */
        struct sysfs_device *scsi_dev; /* the scsi_device */
@@ -672,10 +687,8 @@ static int scsi_id(const char *target_path, char *maj_min_dev)
 
        /*
         * mknod a temp dev to communicate with the device.
-        *
-        * XXX pass down class_dev or class_dev_parent.
         */
-       if (!dev_specified && create_tmp_dev(target_path, maj_min_dev,
+       if (!dev_specified && create_tmp_dev(class_dev, maj_min_dev,
                                             dev_type)) {
                dprintf("create_tmp_dev failed\n");
                return 1;
@@ -689,6 +702,13 @@ static int scsi_id(const char *target_path, char *maj_min_dev)
        dprintf("per dev options: good %d; page code 0x%x; callout '%s'\n",
                good_dev, page_code, callout);
 
+#define ALIGN   512
+       unaligned_buf = malloc(MAX_SERIAL_LEN + ALIGN);
+       serial = (char*) (((unsigned long) unaligned_buf + (ALIGN - 1))
+                         & ~(ALIGN - 1));
+       dprintf("buffer unaligned 0x%p; aligned 0x%p\n", unaligned_buf, serial);
+#undef ALIGN
+
        if (!good_dev) {
                retval = 1;
        } else if (callout[0] != '\0') {
@@ -703,11 +723,11 @@ static int scsi_id(const char *target_path, char *maj_min_dev)
                retval = 0;
        }
        if (!retval) {
+               if (reformat_serial)
+                       format_serial(serial);
                if (display_bus_id)
                        printf("%s: ", scsi_dev->name);
-               printf("%s", serial);
-               if (!hotplug_mode)
-                       printf("\n");
+               printf("%s\n", serial);
                dprintf("%s\n", serial);
                retval = 0;
        }
@@ -731,11 +751,6 @@ int main(int argc, char **argv)
        if (getenv("DEBUG"))
                debug++;
 
-       if ((argc == 2) && (argv[1][0] != '-')) {
-               hotplug_mode = 1;
-               dprintf("hotplug assumed\n");
-       }
-
        dprintf("argc is %d\n", argc);
        if (sysfs_get_mnt_path(sysfs_mnt_path, MAX_NAME_LEN)) {
                log_message(LOG_WARNING, "sysfs_get_mnt_path failed: %s\n",
@@ -743,27 +758,19 @@ int main(int argc, char **argv)
                exit(1);
        }
 
-       if (hotplug_mode) {
+       devpath = getenv("DEVPATH");
+       if (devpath) {
                /*
-                * There is a kernel race creating attributes, if called
-                * directly, uncomment the sleep.
+                * This implies that we were invoked via udev or hotplug.
                 */
-               /* sleep(1); */
-
-               devpath = getenv("DEVPATH");
-               if (!devpath) {
-                       log_message(LOG_WARNING, "DEVPATH is not set\n");
-                       exit(1);
-               }
+               hotplug_mode = 1;
                sys_specified = 1;
-
                strncpy(target_path, sysfs_mnt_path, MAX_NAME_LEN);
                strncat(target_path, devpath, MAX_NAME_LEN);
        }
 
        /*
-        * Override any command line options set via the config file. This
-        * is the only way to set options when in hotplug mode.
+        * Get config file options.
         */
        newargv = NULL;
        retval = get_file_options(NULL, NULL, &newargc, &newargv);
@@ -775,11 +782,13 @@ int main(int argc, char **argv)
                        exit(1);
                free(newargv);
        }
-       if (!hotplug_mode) {
-               if (set_options(argc, argv, short_options, target_path,
-                               maj_min_dev) < 0)
+       /*
+        * Get command line options (overriding any config file or DEVPATH
+        * settings).
+        */
+       if (set_options(argc, argv, short_options, target_path,
+                       maj_min_dev) < 0)
                exit(1);
-       }
 
        if (!sys_specified) {
                log_message(LOG_WARNING, "-s must be specified\n");