diff options
-rw-r--r-- | extras/scsi_id/ChangeLog | 64 | ||||
-rw-r--r-- | extras/scsi_id/Makefile | 24 | ||||
-rw-r--r-- | extras/scsi_id/README | 4 | ||||
-rw-r--r-- | extras/scsi_id/TODO | 21 | ||||
-rw-r--r-- | extras/scsi_id/VERSION | 1 | ||||
-rw-r--r-- | extras/scsi_id/scsi_id.8 | 118 | ||||
-rw-r--r-- | extras/scsi_id/scsi_id.c | 124 | ||||
-rw-r--r-- | extras/scsi_id/scsi_id.h | 21 | ||||
-rw-r--r-- | extras/scsi_id/scsi_serial.c | 34 |
9 files changed, 321 insertions, 90 deletions
diff --git a/extras/scsi_id/ChangeLog b/extras/scsi_id/ChangeLog new file mode 100644 index 0000000000..7f2317723d --- /dev/null +++ b/extras/scsi_id/ChangeLog @@ -0,0 +1,64 @@ +2003-dec-05: + * Makefile, scsi_id.8: Add a man page. + +2003-dec-04: + * Makefile: Set and use variables that might be passed down when + built under udev (with or without klibc), don't set LDFLAGS or + STRIP. + +2003-dec-04: + * scsi_id.c, scsi_id.h: Fix a bad bug - when parsing file options, + no space was allocated for the creation of the new argv[] + strings. + +2003-dec-04: + * scsi_id.c: Catch too long a line in the config file. + +2003-dec-02: + * scsi_id.h: Add u8 typedef to avoid ummm scsi.h kernel header + problem when built with klibc. + +2003-dec-02: + * scsi_id.h: Add define of makedev() if built with klibc. + +2003-dec-02: + * scsi_id.c: reset optind to 1 since klibc does not work if it is + reset to zero. + +2003-dec-02: + * scsi_id.c: remove fflush() as it is not needed, and is not + supported by klibc. + +2003-dec-02: + * scsi_serial.c: Make the functions do_scsi_page0_inquiry and + do_scsi_page80_inquiry static. + +2003-dec-01: + * scsi_id.c: Don't use syslog LOG_PID, as it is not supported by + klibc. + +2003-dec-01: + * scsi_id.c, scsi_serial.c: Hack - change include path to libsysfs + if built under klibc. + +2003-dec-01: + * Makefile: Use "override" for CFLAGS so we can pass CFLAGS values + down when built with udev + +2003-dec-01: + * scsi_id.c, Makefile: Use SCSI_ID_VERSION instead of VERSION. + +2003-nov-25: + * scsi_id.c: Remove getopt_long (long option names), as there + is no support for that in klibc. + +2003-nov-17: + * scsi_id.c: Patch from Brian King: check result of setting model, + not vendor in per_dev_options. + +2003-nov-03: + * scsi_id.c, scsi_serial.c: Use new and correct path to libsysfs.h. + +2003-nov-03: + * scsi_id.h: Fix scsi_id.h so var args in marcros works ok with + older gcc. diff --git a/extras/scsi_id/Makefile b/extras/scsi_id/Makefile index 5ad2bcf3e1..ead205682a 100644 --- a/extras/scsi_id/Makefile +++ b/extras/scsi_id/Makefile @@ -14,33 +14,45 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -VERSION=0.1 +SCSI_ID_VERSION=0.2 prefix = sbindir = ${prefix}/sbin +mandir = ${prefix}/usr/share/man INSTALL = /usr/bin/install -c INSTALL_PROGRAM = ${INSTALL} INSTALL_DATA = ${INSTALL} -m 644 -CFLAGS=-DVERSION=\"$(VERSION)\" $(DEBUG) -Wall +# Note some of the variables used here are set when built under udev, and +# otherwise might not be set. + +override CFLAGS+=-DSCSI_ID_VERSION=\"$(SCSI_ID_VERSION)\" $(DEBUG) -Wall PROG=scsi_id +SYSFS=-lsysfs -LIBSYSFS=-lsysfs -STRIP=-s -LDFLAGS=$(STRIP) --static +# +# Built static and stripped when built with udev. +# +# STRIP=-s +# LDFLAGS=$(STRIP) +LD=$(CC) OBJS= scsi_id.o \ scsi_serial.o \ all: $(PROG) +# XXX use a compressed man page? + install: all $(INSTALL_PROGRAM) -D $(PROG) $(sbindir)/$(PROG) + $(INSTALL_DATA) -D scsi_id.8 $(DESTDIR)$(mandir)/man8/scsi_id.8 uninstall: -rm $(sbindir)/$(PROG) + -rm $(mandir)/man8/scsi_id.8 $(OBJS): scsi_id.h scsi.h @@ -48,4 +60,4 @@ clean: rm -f $(PROG) $(OBJS) $(PROG): $(OBJS) - $(CC) $(OBJS) $(LDFLAGS) $(LIBSYSFS) -o $(PROG) + $(LD) $(LDFLAGS) -o $(PROG) $(CRT0) $(OBJS) $(SYSFS) $(LIB_OBJS) $(ARCH_LIB_OBJS) diff --git a/extras/scsi_id/README b/extras/scsi_id/README index b13cf1e50a..4281c318a2 100644 --- a/extras/scsi_id/README +++ b/extras/scsi_id/README @@ -5,9 +5,9 @@ used by a multi-path configuration tool that requires SCSI id's. Requires: -- Linux kernel 2.6 + - Linux kernel 2.6 -- libsysfs + - libsysfs No man page yet. diff --git a/extras/scsi_id/TODO b/extras/scsi_id/TODO index ba52101431..5d020c276a 100644 --- a/extras/scsi_id/TODO +++ b/extras/scsi_id/TODO @@ -1,16 +1,11 @@ -- Investigate shrinking build size: use klibc or uClibc, or copy whatever - udev does +- add information abou the config file to the man page -- write a man page +- change so non-KLIBC builds under udev don't use /usr/include/sysfs, + but instead use the sysfs included with udev (needs udev change and/or + sysfsutils changes). -- send in kernel patch for REQ_BLOCK_PC, to always set sd and sr set - retries (scmd->allowed) to <= 1 +- do something with callout code - remove or change to a tag? -- Pull SG_IO code into one .c file. - -- implement callout to device specific serial id code. The "-c prog" is - not implemented. - - This needs an implementation of a device specific callout before it can - be completed. Someone with hardware requiring this needs to send in a - patch. + This needs an implementation of a device specific callout or device + specific code (called via some special "tag" or such) before it can be + completed. Someone with such hardware to send in a patch. diff --git a/extras/scsi_id/VERSION b/extras/scsi_id/VERSION deleted file mode 100644 index 49d59571fb..0000000000 --- a/extras/scsi_id/VERSION +++ /dev/null @@ -1 +0,0 @@ -0.1 diff --git a/extras/scsi_id/scsi_id.8 b/extras/scsi_id/scsi_id.8 new file mode 100644 index 0000000000..a4fb881a05 --- /dev/null +++ b/extras/scsi_id/scsi_id.8 @@ -0,0 +1,118 @@ +.TH SCSI_ID 8 "December 2003" "" "Linux Administrator's Manual" +.SH NAME +scsi_id \- retrieve and generate a unique SCSI identifier +.SH SYNOPSIS +.BI scsi_id +[\fIoptions\fP] +.SH "DESCRIPTION" +.B scsi_id +queries a SCSI device via the SCSI INQUIRY vital product data (VPD) page 0x80 or +0x83 and uses the resulting data to generate a value that is unique across +all SCSI devices that properly support page 0x80 or page 0x83. + +If a result is generated it is sent to standard output, and the program +exits with a zero value. If no identifier is output, the program exits +with a non-zero value. + +\fBscsi_id\fP is primarily for use by other utilities such as \fBudev\fP +that require a unique SCSI identifier. + +By default all devices are assume black listed, the \fB-g\fP option must +be specified on the command line or in the config file for any useful +behaviour. + +SCSI commands are sent directly to the device via the SG_IO ioctl +interface. + +In order to generate unique values for either page 0x80 or page 0x83, the +serial numbers or world wide names are prefixed as follows. + +Identifiers based on page 0x80 are prefixed by the character 'S', the SCSI +vendor, the SCSI product (model) and then the the serial number returned +by page 0x80. For example: + +.sp +.nf +# scsi_id -p 0x80 -s /block/sdg +SIBM 3542 1T05078453 +.fi +.P + +Identifiers based on page 0x83 are prefixed by the identifier type +followed by the page 0x83 identifier. For example, a device with a NAA +(Name Address Authority) type of 3 (also in this case the page 0x83 +identifier starts with the NAA value of 6): + +.sp +.nf +# /sbin/scsi_id -p 0x83 -s /block/sdg +3600a0b80000b174b000000d63efc5c8c +.fi +.P + + +.SH OPTIONS +.TP +.BI \-b +The default behaviour - treat the device as black listed, and do nothing +unless a white listed device is found in the scsi_id config-file. +.TP +.BI \-d "\| device\^" +Instead +of determining and creating a device node based on a sysfs dev +entry as done for the \fB-s\fP, send SG_IO commands to +\fBdevice\fP, such as \fB/dev/sdc\fP. +.TP +.BI \-e +Send all output to standard error even if +.B scsi_id +is running in hotplug mode. +.TP +.BI \-f "\| config-file" +Read configuration and black/white list entries from +.B config-file +rather than the default +.B /etc/scsi_id.config +file. +.TP +.BI \-g +Treat the device as white listed. The \fB\-g\fP option must be specified +on the command line or in the scsi_id configuration file for +.B scsi_id +to generate any output. +.TP +.BI \-i +Prefix the identification string with the driver model (sysfs) bus id of +the SCSI device. +.TP +.BI \-p "\| 0x80 | 0x83" +Use SCSI INQUIRY VPD page code 0x80 or 0x83. The default behaviour is to +query the available VPD pages, and use page 0x83 if found, else page 0x80 +if found, else nothing. +.TP +.BI \-s "\|sysfs-device" +Generate an id for the +.B sysfs-device. +The sysfs mount point must not be included. For example, use /block/sd, +not /sys/block/sd. +.TP +.BI \-v +Generate verbose debugging output. +.TP +.BI \-V +Display version number and exit. +.RE +.SH "FILES" +.nf +.ft B +.ft +/etc/scsi_id.config configuration and black/white list entries +.fi +.LP +.SH "SEE ALSO" +.BR udev (8) +, especially the CALLOUT method. +.SH AUTHORS +Developed by Patrick Mansfield <patmans@us.ibm.com> based on SCSI ID +source included in earlier linux 2.5 kernels, sg_utils source, and SCSI +specifications. diff --git a/extras/scsi_id/scsi_id.c b/extras/scsi_id/scsi_id.c index d34d9284e5..df18271b48 100644 --- a/extras/scsi_id/scsi_id.c +++ b/extras/scsi_id/scsi_id.c @@ -23,7 +23,6 @@ #include <stdio.h> #include <stdlib.h> -#include <getopt.h> #include <unistd.h> #include <signal.h> #include <fcntl.h> @@ -33,12 +32,19 @@ #include <stdarg.h> #include <ctype.h> #include <sys/stat.h> -#include <sys/libsysfs.h> +#ifdef __KLIBC__ +/* + * Assume built under udev with KLIBC + */ +#include <libsysfs.h> +#else +#include <sysfs/libsysfs.h> +#endif #include "scsi_id.h" -#ifndef VERSION +#ifndef SCSI_ID_VERSION #warning No version -#define VERSION "unknown" +#define SCSI_ID_VERSION "unknown" #endif /* @@ -49,36 +55,11 @@ #define CONFIG_FILE "/etc/scsi_id.config" -#define MAX_NAME_LEN 72 - -#define MAX_SERIAL_LEN 128 - static const char short_options[] = "bc:d:ef:gip:s:vV"; -static const struct option long_options[] = { - {"broken", no_argument, NULL, 'b'}, /* also per dev */ - {"callout", required_argument, NULL, 'c'}, /* also per dev */ - {"device", required_argument, NULL, 'd'}, - {"stderr", no_argument, NULL, 'e'}, - {"file", required_argument, NULL, 'f'}, - {"good", no_argument, NULL, 'g'}, /* also per dev */ - {"busid", no_argument, NULL, 'i'}, /* also per dev */ - {"page", required_argument, NULL, 'p'}, /* also per dev */ - {"devpath", required_argument, NULL, 's'}, - {"verbose", no_argument, NULL, 'v'}, - {"version", no_argument, NULL, 'V'}, - {0, 0, 0, 0} -}; /* * Just duplicate per dev options. */ static const char dev_short_options[] = "bc:gp:"; -static const struct option dev_long_options[] = { - {"broken", no_argument, NULL, 'b'}, /* also per dev */ - {"callout", required_argument, NULL, 'c'}, /* also per dev */ - {"good", no_argument, NULL, 'g'}, /* also per dev */ - {"page", required_argument, NULL, 'p'}, /* also per dev */ - {0, 0, 0, 0} -}; char sysfs_mnt_path[SYSFS_PATH_MAX]; @@ -105,8 +86,13 @@ 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) { - openlog ("scsi_id", LOG_PID, LOG_DAEMON); + /* + * klibc does not have LOG_PID. + */ + snprintf(logname, 32, "scsi_id[%d]", getpid()); + openlog (logname, 0, LOG_DAEMON); logging_init = 1; } @@ -295,7 +281,7 @@ static int argc_count(char *opts) static int get_file_options(char *vendor, char *model, int *argc, char ***newargv) { - char buffer[256]; + char *buffer; FILE *fd; char *buf; char *str1; @@ -303,7 +289,6 @@ static int get_file_options(char *vendor, char *model, int *argc, int lineno; int c; int retval = 0; - static char *prog_string = "arg0"; dprintf("vendor='%s'; model='%s'\n", vendor, model); fd = fopen(config_file, "r"); @@ -318,16 +303,31 @@ static int get_file_options(char *vendor, char *model, int *argc, } } + /* + * Allocate a buffer rather than put it on the stack so we can + * keep it around to parse any options (any allocated newargv + * points into this buffer for its strings). + */ + buffer = malloc(MAX_BUFFER_LEN); + if (!buffer) { + log_message(LOG_WARNING, "Can't allocate memory.\n"); + return -1; + } + *newargv = NULL; lineno = 0; - while (1) { vendor_in = model_in = options_in = NULL; - buf = fgets(buffer, sizeof(buffer), fd); + buf = fgets(buffer, MAX_BUFFER_LEN, fd); if (buf == NULL) break; lineno++; + if (buf[strlen(buffer) - 1] != '\n') { + log_message(LOG_WARNING, + "Config file line %d too long.\n", lineno); + break; + } while (isspace(*buf)) buf++; @@ -419,18 +419,24 @@ static int get_file_options(char *vendor, char *model, int *argc, * Something matched. Allocate newargv, and store * values found in options_in. */ - c = argc_count(options_in) + 2; + strcpy(buffer, options_in); + c = argc_count(buffer) + 2; *newargv = calloc(c, sizeof(**newargv)); if (!*newargv) { log_message(LOG_WARNING, - "Can't allocate memory\n"); + "Can't allocate memory.\n"); retval = -1; } else { *argc = c; c = 0; - (*newargv)[c] = prog_string; /* nothing */ + /* + * argv[0] at 0 is skipped by getopt, but + * store the buffer address there for + * alter freeing. + */ + (*newargv)[c] = buffer; for (c = 1; c < *argc; c++) - (*newargv)[c] = strsep(&options_in, " "); + (*newargv)[c] = strsep(&buffer, " "); } } else { /* @@ -439,26 +445,26 @@ static int get_file_options(char *vendor, char *model, int *argc, retval = 1; } } + if (retval != 0) + free(buffer); fclose(fd); return retval; } static int set_options(int argc, char **argv, const char *short_opts, - const struct option *long_opts, char *target, - char *maj_min_dev) + char *target, char *maj_min_dev) { int option; - int option_ind; /* - * optind is a global extern used by getopt_long. Since we can - * call set_options twice (once for command line, and once for - * config file) we have to reset this back to 0. + * 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.] */ - optind = 0; + optind = 1; while (1) { - option = getopt_long(argc, argv, short_options, long_options, - &option_ind); + option = getopt(argc, argv, short_options); if (option == -1) break; @@ -521,7 +527,7 @@ static int set_options(int argc, char **argv, const char *short_opts, case 'V': log_message(LOG_WARNING, "scsi_id version: %s\n", - VERSION); + SCSI_ID_VERSION); exit(0); break; @@ -544,8 +550,6 @@ static int per_dev_options(struct sysfs_class_device *scsi_dev, int *good_bad, char *vendor; char *model; int option; - int option_ind; - *good_bad = all_good; *page_code = default_page_code; @@ -562,7 +566,7 @@ static int per_dev_options(struct sysfs_class_device *scsi_dev, int *good_bad, } model = sysfs_get_attr(scsi_dev, "model"); - if (!vendor) { + if (!model) { log_message(LOG_WARNING, "%s: no model attribute\n", scsi_dev->name); return -1; @@ -570,10 +574,9 @@ static int per_dev_options(struct sysfs_class_device *scsi_dev, int *good_bad, retval = get_file_options(vendor, model, &newargc, &newargv); - optind = 0; /* global extern, reset to 0 */ + optind = 1; /* reset this global extern */ while (retval == 0) { - option = getopt_long(newargc, newargv, dev_short_options, - dev_long_options, &option_ind); + option = getopt(newargc, newargv, dev_short_options); if (option == -1) break; @@ -616,8 +619,10 @@ static int per_dev_options(struct sysfs_class_device *scsi_dev, int *good_bad, } } - if (newargv) + if (newargv) { + free(newargv[0]); free(newargv); + } return retval; } @@ -747,7 +752,6 @@ static int scsi_id(const char *target_path, char *maj_min_dev) dprintf("%s\n", serial); retval = 0; } - fflush(stdout); sysfs_close_class_device(scsi_dev); if (!dev_specified) @@ -797,8 +801,8 @@ int main(int argc, char **argv) strncpy(target_path, sysfs_mnt_path, MAX_NAME_LEN); strncat(target_path, devpath, MAX_NAME_LEN); } else { - if (set_options(argc, argv, short_options, long_options, - target_path, maj_min_dev) < 0) + if (set_options(argc, argv, short_options, target_path, + maj_min_dev) < 0) exit(1); } @@ -811,8 +815,8 @@ int main(int argc, char **argv) if (retval < 0) { exit(1); } else if (newargv && (retval == 0)) { - if (set_options(newargc, newargv, short_options, long_options, - target_path, maj_min_dev) < 0) + if (set_options(newargc, newargv, short_options, target_path, + maj_min_dev) < 0) exit(1); free(newargv); } diff --git a/extras/scsi_id/scsi_id.h b/extras/scsi_id/scsi_id.h index 8be492b75a..eb9498ab71 100644 --- a/extras/scsi_id/scsi_id.h +++ b/extras/scsi_id/scsi_id.h @@ -22,11 +22,23 @@ */ #define dprintf(format, arg...) \ - log_message(LOG_DEBUG, "%s: " format, __FUNCTION__, ## arg) + log_message(LOG_DEBUG, "%s: " format, __FUNCTION__ , ## arg) #define MAX_NAME_LEN 72 #define OFFSET (2 * sizeof(unsigned int)) +/* + * MAX_SERIAL_LEN: the maximum length of the serial number, including + * added prefixes such as vendor and product (model) strings. + */ +#define MAX_SERIAL_LEN 128 + +/* + * MAX_BUFFER_LEN: maximum buffer size and line length used while reading + * the config file. + */ +#define MAX_BUFFER_LEN 256 + static inline char *sysfs_get_attr(struct sysfs_class_device *dev, const char *attr) { @@ -40,3 +52,10 @@ extern int scsi_get_serial (struct sysfs_class_device *scsi_dev, extern void log_message (int level, const char *format, ...) __attribute__ ((format (printf, 2, 3))); +#ifdef __KLIBC__ +#define makedev(major, minor) ((major) << 8) | (minor) +#endif + +#ifndef u8 +typedef unsigned char u8; +#endif diff --git a/extras/scsi_id/scsi_serial.c b/extras/scsi_id/scsi_serial.c index 302429c0d4..18cd290817 100644 --- a/extras/scsi_id/scsi_serial.c +++ b/extras/scsi_id/scsi_serial.c @@ -31,7 +31,14 @@ #include <unistd.h> #include <syslog.h> #include <scsi/sg.h> -#include <sys/libsysfs.h> +#ifdef __KLIBC__ +/* + * Assume built under udev with KLIBC + */ +#include <libsysfs.h> +#else +#include <sysfs/libsysfs.h> +#endif #include "scsi_id.h" #include "scsi.h" @@ -348,6 +355,11 @@ resend: retval = scsi_dump(scsi_dev, &io_hdr); } + /* + * XXX where is the length checked? That is, was our request + * buffer long enough? + */ + if (!retval) { retval = buflen; memcpy(buf, buffer, retval); @@ -369,8 +381,8 @@ resend: * Ending here. */ -int do_scsi_page0_inquiry(struct sysfs_class_device *scsi_dev, int fd, - char *buffer, int len) +static int do_scsi_page0_inquiry(struct sysfs_class_device *scsi_dev, int fd, + char *buffer, int len) { int retval; char *vendor; @@ -527,8 +539,10 @@ static int check_fill_0x83_id(struct sysfs_class_device *scsi_dev, serial[0] = hex_str[id_search->id_type]; /* - * Prepend the vendor and model before the id since if it is not - * unique across all vendors and models. + * For SCSI_ID_VENDOR_SPECIFIC prepend the vendor and model before + * the id since it is not unique across all vendors and models, + * this differs from SCSI_ID_T10_VENDOR, where the vendor is + * included in the identifier. */ if (id_search->id_type == SCSI_ID_VENDOR_SPECIFIC) if (prepend_vendor_model(scsi_dev, &serial[1]) < 0) { @@ -575,6 +589,12 @@ static int do_scsi_page83_inquiry(struct sysfs_class_device *scsi_dev, int fd, scsi_dev->name); return 1; } + + /* + * XXX Some devices (IBM 3542) return all spaces for an identifier if + * the LUN is not actually configured. This leads to identifers of + * the form: "1 ". + */ /* * Search for a match in the prioritized id_search_list. @@ -609,8 +629,8 @@ static int do_scsi_page83_inquiry(struct sysfs_class_device *scsi_dev, int fd, return 1; } -int do_scsi_page80_inquiry(struct sysfs_class_device *scsi_dev, int fd, - char *serial, int max_len) +static int do_scsi_page80_inquiry(struct sysfs_class_device *scsi_dev, int fd, + char *serial, int max_len) { int retval; int ser_ind; |