summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--extras/scsi_id/ChangeLog64
-rw-r--r--extras/scsi_id/Makefile24
-rw-r--r--extras/scsi_id/README4
-rw-r--r--extras/scsi_id/TODO21
-rw-r--r--extras/scsi_id/VERSION1
-rw-r--r--extras/scsi_id/scsi_id.8118
-rw-r--r--extras/scsi_id/scsi_id.c124
-rw-r--r--extras/scsi_id/scsi_id.h21
-rw-r--r--extras/scsi_id/scsi_serial.c34
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;