X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=extras%2Fscsi_id%2Fscsi_id.c;h=538108717dcfc8ac3f195b99734a5704e8d9c649;hp=2ffc95fbfed69605ad8caf15315f6a8b5857b703;hb=803ac7a6d8d06787305a01a068c2e0ca47e2536d;hpb=3d94fb8742847afe8396f6dd38b16ff4e836611d diff --git a/extras/scsi_id/scsi_id.c b/extras/scsi_id/scsi_id.c index 2ffc95fbf..538108717 100644 --- a/extras/scsi_id/scsi_id.c +++ b/extras/scsi_id/scsi_id.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include "../../udev.h" @@ -34,7 +35,25 @@ #define TMP_DIR "/dev" #define TMP_PREFIX "tmp-scsi" -static const char short_options[] = "abd:f:gip:s:uvVx"; +static const struct option options[] = { + { "device", 1, NULL, 'd' }, + { "config", 1, NULL, 'f' }, + { "page", 1, NULL, 'p' }, + { "devpath", 1, NULL, 's' }, + { "fallback-to-sysfs", 0, NULL, 'a' }, + { "blacklisted", 0, NULL, 'b' }, + { "whitelisted", 0, NULL, 'g' }, + { "prefix-bus-id", 0, NULL, 'i' }, + { "replace-whitespace", 0, NULL, 'u' }, + { "ignore-sysfs", 0, NULL, 'n' }, + { "verbose", 0, NULL, 'v' }, + { "version", 0, NULL, 'V' }, + { "export", 0, NULL, 'x' }, + { "help", 0, NULL, 'h' }, + {} +}; + +static const char short_options[] = "abd:f:ghinp:s:uvVx"; static const char dev_short_options[] = "bgp:"; static int all_good; @@ -48,6 +67,7 @@ static int use_stderr; static int debug; static int hotplug_mode; static int reformat_serial; +static int ignore_sysfs; static int export; static char vendor_str[64]; static char model_str[64]; @@ -154,25 +174,25 @@ static int create_tmp_dev(const char *devpath, char *tmpdev, int dev_type) unsigned int maj, min; const char *attr; - dbg("%s", devpath); + dbg("%s\n", devpath); attr = sysfs_attr_get_value(devpath, "dev"); if (attr == NULL) { - dbg("%s: could not get dev attribute: %s", devpath, strerror(errno)); + dbg("%s: could not get dev attribute: %s\n", devpath, strerror(errno)); return -1; } - dbg("dev value %s", attr); + dbg("dev value %s\n", attr); if (sscanf(attr, "%u:%u", &maj, &min) != 2) { - err("%s: invalid dev major/minor", devpath); + err("%s: invalid dev major/minor\n", devpath); return -1; } snprintf(tmpdev, MAX_PATH_LEN, "%s/%s-maj%d-min%d-%u", TMP_DIR, TMP_PREFIX, maj, min, getpid()); - dbg("tmpdev '%s'", tmpdev); + dbg("tmpdev '%s'\n", tmpdev); if (mknod(tmpdev, 0600 | dev_type, makedev(maj, min))) { - err("mknod failed: %s", strerror(errno)); + err("mknod failed: %s\n", strerror(errno)); return -1; } return 0; @@ -253,7 +273,7 @@ static int get_file_options(const char *vendor, const char *model, if (errno == ENOENT) { return 1; } else { - err("can't open %s: %s", config_file, strerror(errno)); + err("can't open %s: %s\n", config_file, strerror(errno)); return -1; } } @@ -265,7 +285,7 @@ static int get_file_options(const char *vendor, const char *model, */ buffer = malloc(MAX_BUFFER_LEN); if (!buffer) { - err("Can't allocate memory."); + err("can't allocate memory\n"); return -1; } @@ -279,7 +299,7 @@ static int get_file_options(const char *vendor, const char *model, break; lineno++; if (buf[strlen(buffer) - 1] != '\n') { - info("Config file line %d too long.\n", lineno); + info("Config file line %d too long\n", lineno); break; } @@ -324,14 +344,14 @@ static int get_file_options(const char *vendor, const char *model, } options_in = str1; } - dbg("config file line %d:" + dbg("config file line %d:\n" " vendor '%s'; model '%s'; options '%s'\n", lineno, vendor_in, model_in, options_in); /* * Only allow: [vendor=foo[,model=bar]]options=stuff */ if (!options_in || (!vendor_in && model_in)) { - info("Error parsing config file line %d '%s'", lineno, buffer); + info("Error parsing config file line %d '%s'\n", lineno, buffer); retval = -1; break; } @@ -369,7 +389,7 @@ static int get_file_options(const char *vendor, const char *model, c = argc_count(buffer) + 2; *newargv = calloc(c, sizeof(**newargv)); if (!*newargv) { - err("Can't allocate memory."); + err("can't allocate memory\n"); retval = -1; } else { *argc = c; @@ -377,11 +397,11 @@ static int get_file_options(const char *vendor, const char *model, /* * argv[0] at 0 is skipped by getopt, but * store the buffer address there for - * alter freeing. + * later freeing */ (*newargv)[c] = buffer; for (c = 1; c < *argc; c++) - (*newargv)[c] = strsep(&buffer, " "); + (*newargv)[c] = strsep(&buffer, " \t"); } } else { /* No matches */ @@ -402,12 +422,11 @@ static int set_options(int argc, char **argv, const char *short_opts, /* * optind is a global extern used by getopt. Since we can call * set_options twice (once for command line, and once for config - * file) we have to reset this back to 1. [Note glibc handles - * setting this to 0, but klibc does not.] + * file) we have to reset this back to 1. */ optind = 1; while (1) { - option = getopt(argc, argv, short_opts); + option = getopt_long(argc, argv, short_opts, options, NULL); if (option == -1) break; @@ -443,6 +462,24 @@ static int set_options(int argc, char **argv, const char *short_opts, all_good = 1; break; + case 'h': + printf("Usage: scsi_id OPTIONS \n" + " --device device node for SG_IO commands\n" + " --devpath sysfs devpath\n" + " --config location of config file\n" + " --page SCSI page (0x80, 0x83, pre-spc3-83)\n" + " --fallback-to-sysfs print sysfs values if inquiry fails\n" + " --ignore-sysfs ignore sysfs entries\n" + " --blacklisted threat device as blacklisted\n" + " --whitelisted threat device as whitelisted\n" + " --prefix-bus-id prefix SCSI bus id\n" + " --replace-whitespace replace all whitespaces by underscores\n" + " --verbose verbose logging\n" + " --version print version\n" + " --export print values as environment keys\n" + " --help print this help text\n\n"); + exit(0); + case 'i': display_bus_id = 1; break; @@ -455,11 +492,15 @@ static int set_options(int argc, char **argv, const char *short_opts, } else if (strcmp(optarg, "pre-spc3-83") == 0) { default_page_code = PAGE_83_PRE_SPC3; } else { - info("Unknown page code '%s'", optarg); + info("Unknown page code '%s'\n", optarg); return -1; } break; + case 'n': + ignore_sysfs = 1; + break; + case 's': sys_specified = 1; strncpy(target, optarg, MAX_PATH_LEN); @@ -479,13 +520,12 @@ static int set_options(int argc, char **argv, const char *short_opts, break; case 'V': - info("scsi_id version: %s\n", SCSI_ID_VERSION); + printf("%s\n", SCSI_ID_VERSION); exit(0); break; default: - info("Unknown or bad option '%c' (0x%x)", option, option); - return -1; + exit(1); } } return 0; @@ -496,45 +536,16 @@ static int per_dev_options(struct sysfs_device *dev_scsi, int *good_bad, int *pa int retval; int newargc; char **newargv = NULL; - const char *vendor, *model, *type; int option; *good_bad = all_good; *page_code = default_page_code; - vendor = sysfs_attr_get_value(dev_scsi->devpath, "vendor"); - if (!vendor) { - info("%s: cannot get vendor attribute", dev_scsi->devpath); - return -1; - } - set_str(vendor_str, vendor, sizeof(vendor_str)-1); - - model = sysfs_attr_get_value(dev_scsi->devpath, "model"); - if (!model) { - info("%s: cannot get model attribute\n", dev_scsi->devpath); - return -1; - } - set_str(model_str, model, sizeof(model_str)-1); - - type = sysfs_attr_get_value(dev_scsi->devpath, "type"); - if (!type) { - info("%s: cannot get type attribute", dev_scsi->devpath); - return -1; - } - set_type(type_str, type, sizeof(type_str)); - - type = sysfs_attr_get_value(dev_scsi->devpath, "rev"); - if (!type) { - info("%s: cannot get type attribute\n", dev_scsi->devpath); - return -1; - } - set_str(revision_str, type, sizeof(revision_str)-1); - - retval = get_file_options(vendor, model, &newargc, &newargv); + retval = get_file_options(vendor_str, model_str, &newargc, &newargv); optind = 1; /* reset this global extern */ while (retval == 0) { - option = getopt(newargc, newargv, dev_short_options); + option = getopt_long(newargc, newargv, dev_short_options, options, NULL); if (option == -1) break; @@ -560,13 +571,13 @@ static int per_dev_options(struct sysfs_device *dev_scsi, int *good_bad, int *pa } else if (strcmp(optarg, "pre-spc3-83") == 0) { *page_code = PAGE_83_PRE_SPC3; } else { - info("Unknown page code '%s'", optarg); + info("Unknown page code '%s'\n", optarg); retval = -1; } break; default: - info("Unknown or bad option '%c' (0x%x)", option, option); + info("Unknown or bad option '%c' (0x%x)\n", option, option); retval = -1; break; } @@ -579,6 +590,58 @@ static int per_dev_options(struct sysfs_device *dev_scsi, int *good_bad, int *pa return retval; } +static int set_sysfs_values(struct sysfs_device *dev_scsi) +{ + const char *vendor, *model, *type; + + vendor = sysfs_attr_get_value(dev_scsi->devpath, "vendor"); + if (!vendor) { + info("%s: cannot get vendor attribute\n", dev_scsi->devpath); + return -1; + } + set_str(vendor_str, vendor, sizeof(vendor_str)-1); + + model = sysfs_attr_get_value(dev_scsi->devpath, "model"); + if (!model) { + info("%s: cannot get model attribute\n", dev_scsi->devpath); + return -1; + } + set_str(model_str, model, sizeof(model_str)-1); + + type = sysfs_attr_get_value(dev_scsi->devpath, "type"); + if (!type) { + info("%s: cannot get type attribute\n", dev_scsi->devpath); + return -1; + } + set_type(type_str, type, sizeof(type_str)); + + type = sysfs_attr_get_value(dev_scsi->devpath, "rev"); + if (!type) { + info("%s: cannot get type attribute\n", dev_scsi->devpath); + return -1; + } + set_str(revision_str, type, sizeof(revision_str)-1); + + return 0; +} + +static int set_inq_values(struct sysfs_device *dev_scsi, const char *path) +{ + int retval; + char vendor[8], model[16], type[4], rev[4]; + + retval = scsi_std_inquiry(dev_scsi, path, vendor, model, rev, type); + if (retval) + return retval; + + set_str(vendor_str, vendor, 8); + set_str(model_str, model, 16); + set_type(type_str, type, sizeof(type_str) - 1); + set_str(revision_str, rev, sizeof(revision_str) -1); + + return 0; +} + /* * format_serial: replace to whitespaces by underscores for calling * programs that use the serial for device naming (multipath, Suse @@ -615,17 +678,19 @@ static int scsi_id(const char *devpath, char *maj_min_dev) { int retval; int dev_type = 0; - char *serial, *unaligned_buf; struct sysfs_device *dev; - struct sysfs_device *dev_scsi; + struct sysfs_device *dev_scsi = NULL; int good_dev; int page_code; + char serial[MAX_SERIAL_LEN] = ""; + char serial_short[MAX_SERIAL_LEN] = ""; + const char *bus_str = NULL; dbg("devpath %s\n", devpath); dev = sysfs_device_get(devpath); if (dev == NULL) { - err("unable to access '%s'", devpath); + err("unable to access '%s'\n", devpath); return 1; } @@ -634,53 +699,57 @@ static int scsi_id(const char *devpath, char *maj_min_dev) else dev_type = S_IFCHR; - /* get scsi parent device */ - dev_scsi = sysfs_device_get_parent_with_subsystem(dev, "scsi"); - if (dev_scsi == NULL) { - err("unable to access parent device of '%s'", devpath); - return 1; - } - /* mknod a temp dev to communicate with the device */ if (!dev_specified && create_tmp_dev(dev->devpath, maj_min_dev, dev_type)) { dbg("create_tmp_dev failed\n"); return 1; } + if (!ignore_sysfs) { + /* get scsi parent device */ + dev_scsi = sysfs_device_get_parent_with_subsystem(dev, "scsi"); + if (dev_scsi == NULL) { + err("unable to access parent device of '%s'\n", devpath); + return 1; + } + set_sysfs_values(dev_scsi); + bus_str = "scsi"; + } else { + dev_scsi = dev; + set_inq_values(dev_scsi, maj_min_dev); + } + /* get per device (vendor + model) options from the config file */ retval = per_dev_options(dev_scsi, &good_dev, &page_code); - dbg("per dev options: good %d; page code 0x%x", good_dev, page_code); - -#define ALIGN 512 - unaligned_buf = malloc(MAX_SERIAL_LEN + ALIGN); - serial = (char*) (((unsigned long) unaligned_buf + (ALIGN - 1)) - & ~(ALIGN - 1)); - dbg("buffer unaligned 0x%p; aligned 0x%p\n", unaligned_buf, serial); -#undef ALIGN + dbg("per dev options: good %d; page code 0x%x\n", good_dev, page_code); if (!good_dev) { retval = 1; } else if (scsi_get_serial(dev_scsi, maj_min_dev, page_code, - serial, MAX_SERIAL_LEN)) { + serial, serial_short, MAX_SERIAL_LEN)) { retval = always_info?0:1; } else { retval = 0; } if (!retval) { if (export) { - static char serial_str[64]; + char serial_str[MAX_SERIAL_LEN]; + 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); + set_str(serial_str, serial_short, sizeof(serial_str)); + printf("ID_SERIAL_SHORT=%s\n", serial_str); printf("ID_TYPE=%s\n", type_str); - printf("ID_BUS=scsi\n"); + if (bus_str != NULL) + printf("ID_BUS=%s\n", bus_str); } else { if (reformat_serial) format_serial(serial); if (display_bus_id) - printf("%s: ", dev_scsi->kernel_name); + printf("%s: ", dev_scsi->kernel); printf("%s\n", serial); } dbg("%s\n", serial); @@ -748,7 +817,7 @@ int main(int argc, char **argv) exit(1); if (!sys_specified) { - info("-s must be specified\n"); + info("--devpath= must be specified\n"); retval = 1; goto exit; }