[PATCH] update udev extras/scsi_id to version 0.2

This patch updates scsi_id under udev from version 0.1 to version 0.2.
This commit is contained in:
patmans@us.ibm.com 2003-12-07 08:55:40 -08:00 committed by Greg KH
parent a652254ddb
commit 1bed1db499
9 changed files with 321 additions and 90 deletions

64
extras/scsi_id/ChangeLog Normal file
View File

@ -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.

View File

@ -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)

View File

@ -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.

View File

@ -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.

View File

@ -1 +0,0 @@
0.1

118
extras/scsi_id/scsi_id.8 Normal file
View File

@ -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.

View File

@ -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);
}

View File

@ -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

View File

@ -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;