/*
* temporary names for mknod.
*/
-#define TMP_DIR "/tmp"
-#define TMP_PREFIX "scsi"
+#define TMP_DIR "/dev"
+#define TMP_PREFIX "tmp-scsi"
/*
* XXX Note the 'e' (send output to stderr in all cases), and 'c' (callout)
* options are not supported, but other code is still left in place for
* now.
*/
-static const char short_options[] = "bd:f:gip:s:uvV";
+static const char short_options[] = "abd:f:gip:s:uvVx";
/*
* Just duplicate per dev options.
*/
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;
static char config_file[MAX_NAME_LEN] = SCSI_ID_CONFIG_FILE;
static int display_bus_id;
-static int default_page_code;
+static enum page_code default_page_code;
static int use_stderr;
static int debug;
static int hotplug_mode;
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, ...)
{
vfprintf(stderr, format, args);
} else {
static int logging_init = 0;
- static unsigned char logname[32];
if (!logging_init) {
- /*
- * klibc does not have LOG_PID.
- */
- snprintf(logname, 32, "scsi_id[%d]", getpid());
- openlog (logname, 0, LOG_DAEMON);
+ openlog ("scsi_id", LOG_PID, LOG_DAEMON);
logging_init = 1;
}
return;
}
-int sysfs_get_attr(const char *devpath, const char *attr, char *value,
- size_t bufsize)
+static void set_str(char *to, const char *from, size_t count)
{
- char attr_path[SYSFS_PATH_MAX];
+ size_t i, j, len;
+
+ /* strip trailing whitespace */
+ len = strnlen(from, count);
+ while (len && isspace(from[len-1]))
+ len--;
+
+ /* strip leading whitespace */
+ i = 0;
+ while (isspace(from[i]) && (i < len))
+ i++;
+
+ j = 0;
+ while (i < len) {
+ /* 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';
+}
- 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 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:
+ break;
+ }
+ }
+ strncpy(to, type, len);
+ to[len-1] = '\0';
}
-static int get_major_minor(const char *devpath, int *maj, int *min)
+static int get_major_minor(struct sysfs_class_device *class_dev, int *maj,
+ int *min)
{
- char dev_value[MAX_ATTR_LEN];
+ struct sysfs_attribute *dev_attr;
- 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
* 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());
*/
optind = 1;
while (1) {
- option = getopt(argc, argv, short_options);
+ option = getopt(argc, argv, short_opts);
if (option == -1)
break;
dprintf("option '%c'\n", option);
switch (option) {
+ case 'a':
+ always_info = 1;
+ break;
case 'b':
all_good = 0;
break;
case 'p':
if (strcmp(optarg, "0x80") == 0) {
- default_page_code = 0x80;
+ default_page_code = PAGE_80;
} else if (strcmp(optarg, "0x83") == 0) {
- default_page_code = 0x83;
+ default_page_code = PAGE_83;
+ } else if (strcmp(optarg, "pre-spc3-83") == 0) {
+ default_page_code = PAGE_83_PRE_SPC3;
} else {
log_message(LOG_WARNING,
"Unknown page code '%s'\n", optarg);
reformat_serial = 1;
break;
+ case 'x':
+ export = 1;
+ break;
+
case 'v':
debug++;
break;
int retval;
int newargc;
char **newargv = NULL;
- char vendor[MAX_ATTR_LEN];
- char model[MAX_ATTR_LEN];
+ struct sysfs_attribute *vendor, *model, *type;
int option;
*good_bad = all_good;
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;
}
+ set_str(vendor_str, vendor->value, sizeof(vendor_str)-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;
}
+ 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, model, &newargc, &newargv);
+ retval = get_file_options(vendor->value, model->value, &newargc,
+ &newargv);
optind = 1; /* reset this global extern */
while (retval == 0) {
case 'p':
if (strcmp(optarg, "0x80") == 0) {
- *page_code = 0x80;
+ *page_code = PAGE_80;
} else if (strcmp(optarg, "0x83") == 0) {
- *page_code = 0x83;
+ *page_code = PAGE_83;
+ } else if (strcmp(optarg, "pre-spc3-83") == 0) {
+ *page_code = PAGE_83_PRE_SPC3;
} else {
log_message(LOG_WARNING,
"Unknown page code '%s'\n", optarg);
*p = '_';
p++;
}
- return;
}
/*
/*
* 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;
#define ALIGN 512
unaligned_buf = malloc(MAX_SERIAL_LEN + ALIGN);
- serial = (char*) (((int) unaligned_buf + (ALIGN - 1)) & ~(ALIGN - 1));
+ serial = (char*) (((unsigned long) unaligned_buf + (ALIGN - 1))
+ & ~(ALIGN - 1));
dprintf("buffer unaligned 0x%p; aligned 0x%p\n", unaligned_buf, serial);
#undef ALIGN
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;
}
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");
+ if (export) {
+ 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);
+ if (display_bus_id)
+ printf("%s: ", scsi_dev->name);
+ printf("%s\n", serial);
+ }
dprintf("%s\n", serial);
retval = 0;
}
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",
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);
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");