chiark / gitweb /
[PATCH] update udev_volume_id
[elogind.git] / extras / volume_id / udev_volume_id.c
index 88779ccd36889ce096bc43ef6b67e4a7fb62a723..e88445054b22eecc3d2b194ff154dd383faa3752 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
  *
  *     sample udev rule for creation of a symlink with the filsystem uuid:
- *     KERNEL="sd*", PROGRAM="/sbin/udev_volume_id -M%M -m%m -u", SYMLINK="%c"
+ *     KERNEL="sd*", PROGRAM="/sbin/udev_volume_id -u", SYMLINK="%c"
  *
  *     This program is free software; you can redistribute it and/or modify it
  *     under the terms of the GNU General Public License as published by the
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
+#include <ctype.h>
+#include <linux/fs.h>
+#include <sys/ioctl.h>
 
+#include "../../libsysfs/sysfs/libsysfs.h"
+#include "../../udev_lib.h"
+#include "../../logging.h"
 #include "volume_id.h"
+#include "dasdlabel.h"
 
-int main(int argc, char *argv[])
+#ifdef LOG
+unsigned char logname[LOGNAME_SIZE];
+void log_message(int level, const char *format, ...)
+{
+       va_list args;
+
+       va_start(args, format);
+       vsyslog(level, format, args);
+       va_end(args);
+}
+#endif
+
+static struct volume_id *open_classdev(struct sysfs_class_device *class_dev)
 {
        struct volume_id *vid;
-       const char help[] = "usage: udev_volume_id -m<minor> -M<major> [-t|-l|-u]\n";
-       int major = -1;
-       int minor = -1;
-       char *tail;
-       static const char short_options[] = "M:m:htlu";
-       int option;
-       char print = '\0';
-       int rc;
+       struct sysfs_attribute *attr;
+       int major, minor;
+
+       attr = sysfs_get_classdev_attr(class_dev, "dev");
+
+       if (attr == NULL) {
+               printf("error reading 'dev' attribute\n");
+               return NULL;
+       }
+
+       if (sscanf(attr->value, "%u:%u", &major, &minor) != 2) {
+               printf("error getting major/minor number\n");
+               return NULL;
+       }
+
+       vid = volume_id_open_dev_t(makedev(major, minor));
+       if (vid == NULL) {
+               printf("error open volume\n");
+               return NULL;
+       }
 
+       return vid;
+}
+
+static unsigned long long get_size(struct volume_id *vid)
+{
+       unsigned long long size;
+
+       if (ioctl(vid->fd, BLKGETSIZE64, &size) != 0)
+               size = 0;
+
+       return size;
+}
+
+static char *usage_id_name(enum volume_id_usage usage)
+{
+       switch(usage) {
+       case VOLUME_ID_UNUSED:
+               return "unused";
+       case VOLUME_ID_UNPROBED:
+               return "unprobed";
+       case VOLUME_ID_OTHER:
+               return "other";
+       case VOLUME_ID_PARTITIONTABLE:
+               return "partitiontable";
+       case VOLUME_ID_FILESYSTEM:
+               return "filesystem";
+       case VOLUME_ID_RAID:
+               return "raid";
+       default:
+               return "unknown type_id";
+       }
+}
+
+int main(int argc, char *argv[])
+{
+       const char help[] = "usage: udev_volume_id [-t|-l|-u|-d]\n"
+                           "       -t filesystem type\n"
+                           "       -l filesystem label\n"
+                           "       -u filesystem uuid\n"
+                           "       -d disk label from main device\n"
+                           "\n";
+       static const char short_options[] = "htlud";
+       char sysfs_path[SYSFS_PATH_MAX];
+       char dev_path[SYSFS_PATH_MAX];
+       struct sysfs_class_device *class_dev = NULL;
+       struct sysfs_class_device *class_dev_parent = NULL;
+       struct volume_id *vid = NULL;
+       char *devpath;
+       char probe = 'p';
+       char print = 'a';
+       char dasd_label[7];
+       static char name[VOLUME_ID_LABEL_SIZE];
+       int len, i, j;
+       unsigned long long size;
+       int rc = 1;
 
        while (1) {
+               int option;
+
                option = getopt(argc, argv, short_options);
                if (option == -1)
                        break;
 
                switch (option) {
-               case 'M':
-                       major = (int) strtoul(optarg, &tail, 10);
-                       if (tail[0] != '\0') {
-                               printf("invalid major\n");
-                               exit(1);
-                       }
-                       break;
-               case 'm':
-                       minor = (int) strtoul(optarg, &tail, 10);
-                       if (tail[0] != '\0') {
-                               printf("invalid minor\n");
-                               exit(1);
-                       }
-                       break;
                case 't':
                        print = 't';
-                       break;
+                       continue;
                case 'l':
                        print = 'l';
-                       break;
+                       continue;
                case 'u':
                        print = 'u';
-                       break;
+                       continue;
+               case 'd':
+                       probe = 'd';
+                       continue;
                case 'h':
                case '?':
                default:
@@ -77,44 +154,119 @@ int main(int argc, char *argv[])
                }
        }
 
-       if (major == -1 || minor == -1) {
-               printf(help);
-               exit(1);
+       devpath = getenv("DEVPATH");
+       if (devpath == NULL) {
+               printf("error DEVPATH empty\n");
+               goto exit;
        }
 
-       vid = volume_id_open_dev_t(makedev(major, minor));
-       if (vid == NULL) {
-               printf("error open volume\n");
-               exit(1);
+       if (sysfs_get_mnt_path(sysfs_path, SYSFS_PATH_MAX) != 0) {
+               printf("error getting sysfs mount path\n");
+               goto exit;
        }
 
-       rc = volume_id_probe(vid, ALL);
-       if (rc != 0) {
-               printf("error probing volume\n");
-               exit(1);
+       strfieldcpy(dev_path, sysfs_path);
+       strfieldcat(dev_path, devpath);
+
+       class_dev = sysfs_open_class_device_path(dev_path);
+       if (class_dev == NULL) {
+               printf("error getting class device\n");
+               goto exit;
        }
 
+       switch(probe) {
+       case 'p' :
+               /* open block device */
+               vid = open_classdev(class_dev);
+               if (vid == NULL)
+                       goto exit;
+
+               size = get_size(vid);
+
+               if (volume_id_probe(vid, VOLUME_ID_ALL, 0, size) == 0)
+                       goto print;
+               break;
+       case 'd' :
+               /* if we are on a partition, open main block device instead */
+               class_dev_parent = sysfs_get_classdev_parent(class_dev);
+               if (class_dev_parent != NULL)
+                       vid = open_classdev(class_dev_parent);
+               else
+                       vid = open_classdev(class_dev_parent);
+               if (vid == NULL)
+                       goto exit;
+
+               if (probe_ibm_partition(vid->fd, dasd_label) == 0) {
+                       vid->type = "dasd";
+                       strncpy(vid->label, dasd_label, 6);
+                       vid->label[6] = '\0';
+                       goto print;
+               }
+               break;
+       }
+
+       printf("unknown volume type\n");
+       goto exit;
+
+
+print:
+       len = strnlen(vid->label, VOLUME_ID_LABEL_SIZE);
+
+       /* remove trailing spaces */
+       while (len > 0 && isspace(vid->label[len-1]))
+               len--;
+       name[len] = '\0';
+
+       /* substitute chars */
+       i = 0;
+       j = 0;
+       while (j < len) {
+               switch(vid->label[j]) {
+               case '/' :
+                       break;
+               case ' ' :
+                       name[i++] = '_';
+                       break;
+               default :
+                       name[i++] = vid->label[j];
+               }
+               j++;
+       }
+       name[i] = '\0';
+
        switch (print) {
        case 't':
-               printf("%s\n", vid->fs_name);
+               printf("%s\n", vid->type);
                break;
        case 'l':
-               if (vid->label_string[0] == '\0')
-                       exit(2);
-               printf("%s\n", vid->label_string);
+               if (name[0] == '\0' || vid->usage_id != VOLUME_ID_FILESYSTEM) {
+                       rc = 2;
+                       goto exit;
+               }
+               printf("%s\n", name);
                break;
        case 'u':
-               if (vid->uuid_string[0] == '\0')
-                       exit(2);
-               printf("%s\n", vid->uuid_string);
+               if (vid->uuid[0] == '\0' || vid->usage_id != VOLUME_ID_FILESYSTEM) {
+                       rc = 2;
+                       goto exit;
+               }
+               printf("%s\n", vid->uuid);
                break;
-       default:
-               printf("T:%s\n", vid->fs_name);
-               printf("L:%s\n", vid->label_string);
-               printf("U:%s\n", vid->uuid_string);
+       case 'a':
+               printf("F:%s\n", usage_id_name(vid->usage_id));
+               printf("T:%s\n", vid->type);
+               printf("V:%s\n", vid->type_version);
+               printf("L:%s\n", vid->label);
+               printf("N:%s\n", name);
+               printf("U:%s\n", vid->uuid);
        }
+       rc = 0;
 
-       volume_id_close(vid);
+exit:
+       if (class_dev != NULL)
+               sysfs_close_class_device(class_dev);
+       if (vid != NULL)
+               volume_id_close(vid);
 
-       exit(0);
+       exit(rc);
 }