diff options
Diffstat (limited to 'extras/volume_id/udev_volume_id.c')
-rw-r--r-- | extras/volume_id/udev_volume_id.c | 206 |
1 files changed, 160 insertions, 46 deletions
diff --git a/extras/volume_id/udev_volume_id.c b/extras/volume_id/udev_volume_id.c index 88779ccd36..18915cb62b 100644 --- a/extras/volume_id/udev_volume_id.c +++ b/extras/volume_id/udev_volume_id.c @@ -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 @@ -24,21 +24,75 @@ #include <stdio.h> #include <stdlib.h> #include <unistd.h> +#include <ctype.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; +} +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"; + int option; + 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; + int rc = 1; while (1) { option = getopt(argc, argv, short_options); @@ -46,29 +100,18 @@ int main(int argc, char *argv[]) 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 +120,115 @@ 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; + } + + 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; } - rc = volume_id_probe(vid, ALL); - if (rc != 0) { - printf("error probing volume\n"); - exit(1); + switch(probe) { + case 'p' : + /* open block device */ + vid = open_classdev(class_dev); + if (vid == NULL) + goto exit; + if (volume_id_probe(vid, ALL) == 0) + goto print; + break; + case 'd' : + /* if we are on a partition, close it and open main block device */ + class_dev_parent = sysfs_get_classdev_parent(class_dev); + if (class_dev_parent != NULL) { + volume_id_close(vid); + 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->fs_name = "dasd"; + strncpy(vid->label_string, dasd_label, 6); + vid->label_string[6] = '\0'; + goto print; + } + break; } + printf("unknown volume type\n"); + goto exit; + + +print: + len = strnlen(vid->label_string, VOLUME_ID_LABEL_SIZE); + + /* remove trailing spaces */ + while (len > 0 && isspace(vid->label_string[len-1])) + len--; + name[len] = '\0'; + + /* substitute chars */ + i = 0; + j = 0; + while (j < len) { + switch(vid->label_string[j]) { + case '/' : + break; + case ' ' : + name[i++] = '_'; + break; + default : + name[i++] = vid->label_string[j]; + } + j++; + } + name[i] = '\0'; + switch (print) { case 't': printf("%s\n", vid->fs_name); break; case 'l': - if (vid->label_string[0] == '\0') - exit(2); - printf("%s\n", vid->label_string); + if (name[0] == '\0') { + rc = 2; + goto exit; + } + printf("%s\n", name); break; case 'u': - if (vid->uuid_string[0] == '\0') - exit(2); + if (vid->uuid_string[0] == '\0') { + rc = 2; + goto exit; + } printf("%s\n", vid->uuid_string); break; - default: + case 'a': printf("T:%s\n", vid->fs_name); printf("L:%s\n", vid->label_string); + printf("N:%s\n", name); printf("U:%s\n", vid->uuid_string); } + 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); } |