2003-11-13 17:34:36 +03:00
/*
* scsi_id . c
*
* Main section of the scsi_id program
*
* Copyright ( C ) IBM Corp . 2003
2006-01-28 18:42:49 +03:00
* Copyright ( C ) SUSE Linux Products GmbH , 2006
2003-11-13 17:34:36 +03:00
*
2006-01-28 18:42:49 +03:00
* Author :
* Patrick Mansfield < patmans @ us . ibm . com >
2003-11-13 17:34:36 +03:00
*
2006-01-28 18:42:49 +03:00
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation version 2 of the License .
2003-11-13 17:34:36 +03:00
*/
# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# include <signal.h>
# include <fcntl.h>
# include <errno.h>
# include <string.h>
# include <syslog.h>
# include <stdarg.h>
# include <ctype.h>
2007-05-25 19:37:47 +04:00
# include <getopt.h>
2003-11-13 17:34:36 +03:00
# include <sys/stat.h>
2008-07-30 03:45:23 +04:00
# include "../../udev/udev.h"
2006-01-09 23:18:00 +03:00
# include "scsi_id.h"
2003-11-13 17:34:36 +03:00
2007-05-25 19:37:47 +04:00
static const struct option options [ ] = {
2008-10-02 18:49:05 +04:00
{ " device " , required_argument , NULL , ' d ' } ,
{ " config " , required_argument , NULL , ' f ' } ,
{ " page " , required_argument , NULL , ' p ' } ,
{ " blacklisted " , no_argument , NULL , ' b ' } ,
{ " whitelisted " , no_argument , NULL , ' g ' } ,
{ " replace-whitespace " , no_argument , NULL , ' u ' } ,
{ " sg-version " , required_argument , NULL , ' s ' } ,
{ " verbose " , no_argument , NULL , ' v ' } ,
{ " version " , no_argument , NULL , ' V ' } ,
{ " export " , no_argument , NULL , ' x ' } ,
{ " help " , no_argument , NULL , ' h ' } ,
2007-05-25 19:37:47 +04:00
{ }
} ;
2008-05-14 15:42:41 +04:00
static const char short_options [ ] = " d:f:ghip:uvVx " ;
2004-02-28 12:00:36 +03:00
static const char dev_short_options [ ] = " bgp: " ;
2003-11-13 17:34:36 +03:00
static int all_good ;
static int dev_specified ;
2008-07-30 03:45:23 +04:00
static char config_file [ MAX_PATH_LEN ] = SYSCONFDIR " /scsi_id.config " ;
2005-09-14 22:23:48 +04:00
static enum page_code default_page_code ;
2008-05-14 17:02:17 +04:00
static int sg_version = 4 ;
2003-11-13 17:34:36 +03:00
static int use_stderr ;
static int debug ;
2004-10-06 08:30:54 +04:00
static int reformat_serial ;
2005-06-27 04:51:49 +04:00
static int export ;
static char vendor_str [ 64 ] ;
static char model_str [ 64 ] ;
2005-06-27 19:04:56 +04:00
static char revision_str [ 16 ] ;
static char type_str [ 16 ] ;
2003-11-13 17:34:36 +03:00
2008-09-06 17:45:31 +04:00
static void log_fn ( struct udev * udev , int priority ,
const char * file , int line , const char * fn ,
const char * format , va_list args )
2003-11-13 17:34:36 +03:00
{
2006-01-09 23:18:00 +03:00
vsyslog ( priority , format , args ) ;
2003-11-13 17:34:36 +03:00
}
2005-08-01 03:33:36 +04:00
static void set_str ( char * to , const char * from , size_t count )
2005-06-27 04:51:49 +04:00
{
2005-08-01 03:33:36 +04:00
size_t i , j , len ;
2005-06-27 04:51:49 +04:00
2005-06-27 19:04:56 +04:00
/* strip trailing whitespace */
2005-06-27 04:51:49 +04:00
len = strnlen ( from , count ) ;
2005-08-22 13:37:12 +04:00
while ( len & & isspace ( from [ len - 1 ] ) )
2005-06-27 04:51:49 +04:00
len - - ;
2005-06-27 19:04:56 +04:00
/* strip leading whitespace */
2005-06-27 04:51:49 +04:00
i = 0 ;
while ( isspace ( from [ i ] ) & & ( i < len ) )
i + + ;
j = 0 ;
while ( i < len ) {
2005-06-27 19:04:56 +04:00
/* substitute multiple whitespace */
if ( isspace ( from [ i ] ) ) {
while ( isspace ( from [ i ] ) )
i + + ;
2005-06-27 04:51:49 +04:00
to [ j + + ] = ' _ ' ;
2005-06-27 19:04:56 +04:00
}
/* skip chars */
if ( from [ i ] = = ' / ' ) {
i + + ;
continue ;
}
to [ j + + ] = from [ i + + ] ;
}
to [ j ] = ' \0 ' ;
}
2005-08-13 02:18:44 +04:00
static void set_type ( char * to , const char * from , size_t len )
2005-06-27 19:04:56 +04:00
{
int type_num ;
char * eptr ;
2005-08-13 02:18:44 +04:00
char * type = " generic " ;
2005-06-27 19:04:56 +04:00
type_num = strtoul ( from , & eptr , 0 ) ;
if ( eptr ! = from ) {
switch ( type_num ) {
case 0 :
2005-08-13 02:18:44 +04:00
type = " disk " ;
2005-06-27 19:04:56 +04:00
break ;
case 1 :
2005-08-13 02:18:44 +04:00
type = " tape " ;
2005-06-27 19:04:56 +04:00
break ;
case 4 :
2005-08-13 02:18:44 +04:00
type = " optical " ;
2005-06-27 19:04:56 +04:00
break ;
case 5 :
2005-08-13 02:18:44 +04:00
type = " cd " ;
2005-06-27 19:04:56 +04:00
break ;
case 7 :
2005-08-13 02:18:44 +04:00
type = " optical " ;
2005-06-27 19:04:56 +04:00
break ;
case 0xe :
2005-08-13 02:18:44 +04:00
type = " disk " ;
2005-06-27 19:04:56 +04:00
break ;
case 0xf :
2005-08-13 02:18:44 +04:00
type = " optical " ;
2005-06-27 04:51:49 +04:00
break ;
default :
2005-06-27 19:04:56 +04:00
break ;
2005-06-27 04:51:49 +04:00
}
}
2008-10-22 01:42:15 +04:00
util_strlcpy ( to , type , len ) ;
2005-06-27 04:51:49 +04:00
}
2003-11-13 17:34:36 +03:00
/*
* get_value :
*
* buf points to an ' = ' followed by a quoted string ( " foo " ) or a string ending
* with a space or ' , ' .
*
* Return a pointer to the NUL terminated string , returns NULL if no
* matches .
*/
static char * get_value ( char * * buffer )
{
static char * quote_string = " \" \n " ;
static char * comma_string = " , \n " ;
char * val ;
char * end ;
if ( * * buffer = = ' " ' ) {
/*
* skip leading quote , terminate when quote seen
*/
( * buffer ) + + ;
end = quote_string ;
} else {
end = comma_string ;
}
val = strsep ( buffer , end ) ;
if ( val & & end = = quote_string )
/*
* skip trailing quote
*/
( * buffer ) + + ;
while ( isspace ( * * buffer ) )
( * buffer ) + + ;
return val ;
}
static int argc_count ( char * opts )
{
int i = 0 ;
while ( * opts ! = ' \0 ' )
if ( * opts + + = = ' ' )
i + + ;
return i ;
}
/*
* get_file_options :
*
* If vendor = = NULL , find a line in the config file with only " OPTIONS= " ;
* if vendor and model are set find the first OPTIONS line in the config
* file that matches . Set argc and argv to match the OPTIONS string .
*
* vendor and model can end in ' \n ' .
*/
2008-09-06 17:45:31 +04:00
static int get_file_options ( struct udev * udev ,
const char * vendor , const char * model ,
2006-01-09 23:18:00 +03:00
int * argc , char * * * newargv )
2003-11-13 17:34:36 +03:00
{
2003-12-07 19:55:40 +03:00
char * buffer ;
2003-11-13 17:34:36 +03:00
FILE * fd ;
char * buf ;
char * str1 ;
char * vendor_in , * model_in , * options_in ; /* read in from file */
int lineno ;
int c ;
int retval = 0 ;
2008-09-06 17:45:31 +04:00
dbg ( udev , " vendor='%s'; model='%s' \n " , vendor , model ) ;
2003-11-13 17:34:36 +03:00
fd = fopen ( config_file , " r " ) ;
if ( fd = = NULL ) {
2008-09-06 17:45:31 +04:00
dbg ( udev , " can't open %s \n " , config_file ) ;
2003-11-13 17:34:36 +03:00
if ( errno = = ENOENT ) {
return 1 ;
} else {
2008-09-06 17:45:31 +04:00
err ( udev , " can't open %s: %s \n " , config_file , strerror ( errno ) ) ;
2003-11-13 17:34:36 +03:00
return - 1 ;
}
}
2003-12-07 19:55:40 +03:00
/*
* 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 ) {
2008-09-06 17:45:31 +04:00
err ( udev , " can't allocate memory \n " ) ;
2003-12-07 19:55:40 +03:00
return - 1 ;
}
2003-11-13 17:34:36 +03:00
* newargv = NULL ;
lineno = 0 ;
while ( 1 ) {
vendor_in = model_in = options_in = NULL ;
2003-12-07 19:55:40 +03:00
buf = fgets ( buffer , MAX_BUFFER_LEN , fd ) ;
2003-11-13 17:34:36 +03:00
if ( buf = = NULL )
break ;
lineno + + ;
2003-12-07 19:55:40 +03:00
if ( buf [ strlen ( buffer ) - 1 ] ! = ' \n ' ) {
2008-09-06 17:45:31 +04:00
err ( udev , " Config file line %d too long \n " , lineno ) ;
2003-12-07 19:55:40 +03:00
break ;
}
2003-11-13 17:34:36 +03:00
while ( isspace ( * buf ) )
buf + + ;
2006-01-09 23:18:00 +03:00
/* blank or all whitespace line */
2003-11-13 17:34:36 +03:00
if ( * buf = = ' \0 ' )
continue ;
2006-01-09 23:18:00 +03:00
/* comment line */
2003-11-13 17:34:36 +03:00
if ( * buf = = ' # ' )
continue ;
2008-09-29 21:03:08 +04:00
dbg ( udev , " lineno %d: '%s' \n " , lineno , buf ) ;
2003-11-13 17:34:36 +03:00
str1 = strsep ( & buf , " = " ) ;
if ( str1 & & strcasecmp ( str1 , " VENDOR " ) = = 0 ) {
str1 = get_value ( & buf ) ;
if ( ! str1 ) {
retval = - 1 ;
break ;
}
vendor_in = str1 ;
str1 = strsep ( & buf , " = " ) ;
if ( str1 & & strcasecmp ( str1 , " MODEL " ) = = 0 ) {
str1 = get_value ( & buf ) ;
if ( ! str1 ) {
retval = - 1 ;
break ;
}
model_in = str1 ;
str1 = strsep ( & buf , " = " ) ;
}
}
if ( str1 & & strcasecmp ( str1 , " OPTIONS " ) = = 0 ) {
str1 = get_value ( & buf ) ;
if ( ! str1 ) {
retval = - 1 ;
break ;
}
options_in = str1 ;
}
2008-09-29 21:03:08 +04:00
dbg ( udev , " config file line %d: \n "
2003-11-13 17:34:36 +03:00
" 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 ) ) {
2008-09-06 17:45:31 +04:00
err ( udev , " Error parsing config file line %d '%s' \n " , lineno , buffer ) ;
2003-11-13 17:34:36 +03:00
retval = - 1 ;
break ;
}
if ( vendor = = NULL ) {
if ( vendor_in = = NULL ) {
2008-09-29 21:03:08 +04:00
dbg ( udev , " matched global option \n " ) ;
2003-11-13 17:34:36 +03:00
break ;
}
} else if ( ( vendor_in & & strncmp ( vendor , vendor_in ,
strlen ( vendor_in ) ) = = 0 ) & &
( ! model_in | | ( strncmp ( model , model_in ,
strlen ( model_in ) ) = = 0 ) ) ) {
/*
* Matched vendor and optionally model .
*
* Note : a short vendor_in or model_in can
* give a partial match ( that is FOO
* matches FOOBAR ) .
*/
2008-09-29 21:03:08 +04:00
dbg ( udev , " matched vendor/model \n " ) ;
2003-11-13 17:34:36 +03:00
break ;
} else {
2008-09-29 21:03:08 +04:00
dbg ( udev , " no match \n " ) ;
2003-11-13 17:34:36 +03:00
}
}
if ( retval = = 0 ) {
if ( vendor_in ! = NULL | | model_in ! = NULL | |
options_in ! = NULL ) {
/*
* Something matched . Allocate newargv , and store
* values found in options_in .
*/
2003-12-07 19:55:40 +03:00
strcpy ( buffer , options_in ) ;
c = argc_count ( buffer ) + 2 ;
2003-11-13 17:34:36 +03:00
* newargv = calloc ( c , sizeof ( * * newargv ) ) ;
if ( ! * newargv ) {
2008-09-06 17:45:31 +04:00
err ( udev , " can't allocate memory \n " ) ;
2003-11-13 17:34:36 +03:00
retval = - 1 ;
} else {
* argc = c ;
c = 0 ;
2003-12-07 19:55:40 +03:00
/*
* argv [ 0 ] at 0 is skipped by getopt , but
* store the buffer address there for
2007-02-26 00:14:14 +03:00
* later freeing
2003-12-07 19:55:40 +03:00
*/
( * newargv ) [ c ] = buffer ;
2003-11-13 17:34:36 +03:00
for ( c = 1 ; c < * argc ; c + + )
2007-02-26 00:14:14 +03:00
( * newargv ) [ c ] = strsep ( & buffer , " \t " ) ;
2003-11-13 17:34:36 +03:00
}
} else {
2006-01-09 23:18:00 +03:00
/* No matches */
2003-11-13 17:34:36 +03:00
retval = 1 ;
}
}
2003-12-07 19:55:40 +03:00
if ( retval ! = 0 )
free ( buffer ) ;
2003-11-13 17:34:36 +03:00
fclose ( fd ) ;
return retval ;
}
2008-09-06 17:45:31 +04:00
static int set_options ( struct udev * udev ,
int argc , char * * argv , const char * short_opts ,
2008-05-14 15:42:41 +04:00
char * maj_min_dev )
2003-11-13 17:34:36 +03:00
{
int option ;
/*
2003-12-07 19:55:40 +03:00
* optind is a global extern used by getopt . Since we can call
* set_options twice ( once for command line , and once for config
2006-08-05 02:35:05 +04:00
* file ) we have to reset this back to 1.
2003-11-13 17:34:36 +03:00
*/
2003-12-07 19:55:40 +03:00
optind = 1 ;
2003-11-13 17:34:36 +03:00
while ( 1 ) {
2007-05-25 19:37:47 +04:00
option = getopt_long ( argc , argv , short_opts , options , NULL ) ;
2003-11-13 17:34:36 +03:00
if ( option = = - 1 )
break ;
if ( optarg )
2008-09-06 17:45:31 +04:00
dbg ( udev , " option '%c' arg '%s' \n " , option , optarg ) ;
2003-11-13 17:34:36 +03:00
else
2008-09-06 17:45:31 +04:00
dbg ( udev , " option '%c' \n " , option ) ;
2003-11-13 17:34:36 +03:00
switch ( option ) {
case ' b ' :
all_good = 0 ;
break ;
case ' d ' :
dev_specified = 1 ;
2008-10-22 01:42:15 +04:00
util_strlcpy ( maj_min_dev , optarg , MAX_PATH_LEN ) ;
2003-11-13 17:34:36 +03:00
break ;
case ' e ' :
use_stderr = 1 ;
break ;
case ' f ' :
2008-10-22 01:42:15 +04:00
util_strlcpy ( config_file , optarg , MAX_PATH_LEN ) ;
2003-11-13 17:34:36 +03:00
break ;
case ' g ' :
all_good = 1 ;
break ;
2007-05-25 19:37:47 +04:00
case ' h ' :
printf ( " Usage: scsi_id OPTIONS <device> \n "
2008-05-14 17:02:17 +04:00
" --device= device node for SG_IO commands \n "
" --config= location of config file \n "
" --page=0x80|0x83|pre-spc3-83 SCSI page (0x80, 0x83, pre-spc3-83) \n "
" --sg-version=3|4 use SGv3 or SGv4 \n "
" --blacklisted threat device as blacklisted \n "
" --whitelisted threat device as whitelisted \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 " ) ;
2007-05-25 19:37:47 +04:00
exit ( 0 ) ;
2003-11-13 17:34:36 +03:00
case ' p ' :
if ( strcmp ( optarg , " 0x80 " ) = = 0 ) {
2005-09-14 22:23:48 +04:00
default_page_code = PAGE_80 ;
2003-11-13 17:34:36 +03:00
} else if ( strcmp ( optarg , " 0x83 " ) = = 0 ) {
2005-09-14 22:23:48 +04:00
default_page_code = PAGE_83 ;
} else if ( strcmp ( optarg , " pre-spc3-83 " ) = = 0 ) {
default_page_code = PAGE_83_PRE_SPC3 ;
2003-11-13 17:34:36 +03:00
} else {
2008-09-06 17:45:31 +04:00
err ( udev , " Unknown page code '%s' \n " , optarg ) ;
2008-05-14 17:02:17 +04:00
return - 1 ;
}
break ;
case ' s ' :
sg_version = atoi ( optarg ) ;
if ( sg_version < 3 | | sg_version > 4 ) {
2008-09-06 17:45:31 +04:00
err ( udev , " Unknown SG version '%s' \n " , optarg ) ;
2003-11-13 17:34:36 +03:00
return - 1 ;
}
break ;
2004-10-06 08:30:54 +04:00
case ' u ' :
reformat_serial = 1 ;
break ;
2005-06-27 04:51:49 +04:00
case ' x ' :
export = 1 ;
break ;
2003-11-13 17:34:36 +03:00
case ' v ' :
debug + + ;
break ;
case ' V ' :
2008-07-30 03:45:23 +04:00
printf ( " %s \n " , VERSION ) ;
2003-11-13 17:34:36 +03:00
exit ( 0 ) ;
break ;
default :
2007-05-25 19:37:47 +04:00
exit ( 1 ) ;
2003-11-13 17:34:36 +03:00
}
}
2008-05-14 15:42:41 +04:00
if ( optind < argc & & ! dev_specified ) {
dev_specified = 1 ;
2008-10-22 01:42:15 +04:00
util_strlcpy ( maj_min_dev , argv [ optind ] , MAX_PATH_LEN ) ;
2008-05-14 15:42:41 +04:00
}
2003-11-13 17:34:36 +03:00
return 0 ;
}
2008-09-06 17:45:31 +04:00
static int per_dev_options ( struct udev * udev ,
struct scsi_id_device * dev_scsi , int * good_bad , int * page_code )
2003-11-13 17:34:36 +03:00
{
int retval ;
int newargc ;
char * * newargv = NULL ;
int option ;
* good_bad = all_good ;
* page_code = default_page_code ;
2008-09-06 17:45:31 +04:00
retval = get_file_options ( udev , vendor_str , model_str , & newargc , & newargv ) ;
2003-11-13 17:34:36 +03:00
2003-12-07 19:55:40 +03:00
optind = 1 ; /* reset this global extern */
2003-11-13 17:34:36 +03:00
while ( retval = = 0 ) {
2007-05-25 19:37:47 +04:00
option = getopt_long ( newargc , newargv , dev_short_options , options , NULL ) ;
2003-11-13 17:34:36 +03:00
if ( option = = - 1 )
break ;
if ( optarg )
2008-09-06 17:45:31 +04:00
dbg ( udev , " option '%c' arg '%s' \n " , option , optarg ) ;
2003-11-13 17:34:36 +03:00
else
2008-09-06 17:45:31 +04:00
dbg ( udev , " option '%c' \n " , option ) ;
2003-11-13 17:34:36 +03:00
switch ( option ) {
case ' b ' :
* good_bad = 0 ;
break ;
case ' g ' :
* good_bad = 1 ;
break ;
case ' p ' :
if ( strcmp ( optarg , " 0x80 " ) = = 0 ) {
2005-09-14 22:23:48 +04:00
* page_code = PAGE_80 ;
2003-11-13 17:34:36 +03:00
} else if ( strcmp ( optarg , " 0x83 " ) = = 0 ) {
2005-09-14 22:23:48 +04:00
* page_code = PAGE_83 ;
} else if ( strcmp ( optarg , " pre-spc3-83 " ) = = 0 ) {
* page_code = PAGE_83_PRE_SPC3 ;
2003-11-13 17:34:36 +03:00
} else {
2008-09-06 17:45:31 +04:00
err ( udev , " Unknown page code '%s' \n " , optarg ) ;
2003-11-13 17:34:36 +03:00
retval = - 1 ;
}
break ;
default :
2008-09-06 17:45:31 +04:00
err ( udev , " Unknown or bad option '%c' (0x%x) \n " , option , option ) ;
2003-11-13 17:34:36 +03:00
retval = - 1 ;
break ;
}
}
2003-12-07 19:55:40 +03:00
if ( newargv ) {
free ( newargv [ 0 ] ) ;
2003-11-13 17:34:36 +03:00
free ( newargv ) ;
2003-12-07 19:55:40 +03:00
}
2003-11-13 17:34:36 +03:00
return retval ;
}
2008-09-06 17:45:31 +04:00
static int set_inq_values ( struct udev * udev , struct scsi_id_device * dev_scsi , const char * path )
2007-05-25 16:48:08 +04:00
{
int retval ;
2008-05-14 17:02:17 +04:00
dev_scsi - > use_sg = sg_version ;
2008-05-14 15:55:49 +04:00
2008-09-06 17:45:31 +04:00
retval = scsi_std_inquiry ( udev , dev_scsi , path ) ;
2007-05-25 16:48:08 +04:00
if ( retval )
2008-07-11 00:22:10 +04:00
return retval ;
2007-05-25 16:48:08 +04:00
2008-05-14 17:02:17 +04:00
set_str ( vendor_str , dev_scsi - > vendor , sizeof ( vendor_str ) ) ;
set_str ( model_str , dev_scsi - > model , sizeof ( model_str ) ) ;
set_type ( type_str , dev_scsi - > type , sizeof ( type_str ) ) ;
set_str ( revision_str , dev_scsi - > revision , sizeof ( revision_str ) ) ;
2007-05-25 16:48:08 +04:00
return 0 ;
}
2004-10-06 08:30:54 +04:00
/*
* format_serial : replace to whitespaces by underscores for calling
* programs that use the serial for device naming ( multipath , Suse
* naming , etc . . . )
*/
static void format_serial ( char * serial )
{
2005-12-15 14:22:42 +03:00
char * p = serial , * q ;
2004-10-06 08:30:54 +04:00
2005-12-15 14:22:42 +03:00
q = p ;
2004-10-06 08:30:54 +04:00
while ( * p ! = ' \0 ' ) {
2005-12-15 14:22:42 +03:00
if ( isspace ( * p ) ) {
if ( q > serial & & q [ - 1 ] ! = ' _ ' ) {
* q = ' _ ' ;
q + + ;
}
} else {
* q = * p ;
q + + ;
}
2004-10-06 08:30:54 +04:00
p + + ;
}
2005-12-15 14:22:42 +03:00
* q = ' \0 ' ;
2004-10-06 08:30:54 +04:00
}
2003-11-13 17:34:36 +03:00
/*
* scsi_id : try to get an id , if one is found , printf it to stdout .
* returns a value passed to exit ( ) - 0 if printed an id , else 1. This
* could be expanded , for example , if we want to report a failure like no
* memory etc . return 2 , and return 1 for expected cases ( like broken
* device found ) that do not print an id .
*/
2008-09-06 17:45:31 +04:00
static int scsi_id ( struct udev * udev , char * maj_min_dev )
2003-11-13 17:34:36 +03:00
{
int retval ;
2008-05-14 15:42:41 +04:00
struct scsi_id_device dev_scsi ;
2003-11-13 17:34:36 +03:00
int good_dev ;
int page_code ;
2008-10-26 04:31:54 +03:00
char serial_short [ MAX_SERIAL_LEN ] ;
2003-11-13 17:34:36 +03:00
2008-10-26 04:31:54 +03:00
serial_short [ 0 ] = ' \0 ' ;
2008-09-06 17:45:31 +04:00
set_inq_values ( udev , & dev_scsi , maj_min_dev ) ;
2007-05-25 16:48:08 +04:00
2006-01-09 23:18:00 +03:00
/* get per device (vendor + model) options from the config file */
2008-09-06 17:45:31 +04:00
retval = per_dev_options ( udev , & dev_scsi , & good_dev , & page_code ) ;
2008-09-29 21:03:08 +04:00
dbg ( udev , " per dev options: good %d; page code 0x%x \n " , good_dev , page_code ) ;
2003-11-13 17:34:36 +03:00
if ( ! good_dev ) {
retval = 1 ;
2008-09-06 17:45:31 +04:00
} else if ( scsi_get_serial ( udev ,
& dev_scsi , maj_min_dev , page_code ,
2008-05-14 15:42:41 +04:00
serial_short , MAX_SERIAL_LEN ) ) {
retval = 1 ;
2003-11-13 17:34:36 +03:00
} else {
retval = 0 ;
}
if ( ! retval ) {
2005-06-27 04:51:49 +04:00
if ( export ) {
2006-10-10 18:56:09 +04:00
char serial_str [ MAX_SERIAL_LEN ] ;
2005-06-27 04:51:49 +04:00
printf ( " ID_VENDOR=%s \n " , vendor_str ) ;
printf ( " ID_MODEL=%s \n " , model_str ) ;
2005-06-27 19:04:56 +04:00
printf ( " ID_REVISION=%s \n " , revision_str ) ;
2008-05-14 15:42:41 +04:00
set_str ( serial_str , dev_scsi . serial , sizeof ( serial_str ) ) ;
2005-06-27 04:51:49 +04:00
printf ( " ID_SERIAL=%s \n " , serial_str ) ;
2006-10-10 18:56:09 +04:00
set_str ( serial_str , serial_short , sizeof ( serial_str ) ) ;
printf ( " ID_SERIAL_SHORT=%s \n " , serial_str ) ;
2005-06-27 19:04:56 +04:00
printf ( " ID_TYPE=%s \n " , type_str ) ;
2005-06-27 04:51:49 +04:00
} else {
if ( reformat_serial )
2008-05-14 15:42:41 +04:00
format_serial ( dev_scsi . serial ) ;
printf ( " %s \n " , dev_scsi . serial ) ;
2005-06-27 04:51:49 +04:00
}
2008-09-29 21:03:08 +04:00
dbg ( udev , " %s \n " , dev_scsi . serial ) ;
2003-11-13 17:34:36 +03:00
retval = 0 ;
}
return retval ;
}
int main ( int argc , char * * argv )
{
2008-09-06 17:45:31 +04:00
struct udev * udev ;
2006-01-09 23:18:00 +03:00
int retval = 0 ;
2006-01-18 06:24:48 +03:00
char maj_min_dev [ MAX_PATH_LEN ] ;
2003-11-13 17:34:36 +03:00
int newargc ;
char * * newargv ;
2008-09-06 17:45:31 +04:00
udev = udev_new ( ) ;
if ( udev = = NULL )
goto exit ;
2006-01-09 23:18:00 +03:00
logging_init ( " scsi_id " ) ;
2008-09-06 17:45:31 +04:00
udev_set_log_fn ( udev , log_fn ) ;
2003-11-13 17:34:36 +03:00
/*
2005-02-12 05:30:01 +03:00
* Get config file options .
2003-11-13 17:34:36 +03:00
*/
newargv = NULL ;
2008-09-06 17:45:31 +04:00
retval = get_file_options ( udev , NULL , NULL , & newargc , & newargv ) ;
2003-11-13 17:34:36 +03:00
if ( retval < 0 ) {
2006-01-09 23:18:00 +03:00
retval = 1 ;
goto exit ;
}
if ( newargv & & ( retval = = 0 ) ) {
2008-09-06 17:45:31 +04:00
if ( set_options ( udev , newargc , newargv , short_options , maj_min_dev ) < 0 ) {
2006-01-09 23:18:00 +03:00
retval = 2 ;
goto exit ;
}
2003-11-13 17:34:36 +03:00
free ( newargv ) ;
}
2006-01-09 23:18:00 +03:00
2005-02-12 05:30:01 +03:00
/*
2008-05-14 15:42:41 +04:00
* Get command line options ( overriding any config file settings ) .
2005-02-12 05:30:01 +03:00
*/
2008-09-06 17:45:31 +04:00
if ( set_options ( udev , argc , argv , short_options , maj_min_dev ) < 0 )
2004-06-26 12:18:17 +04:00
exit ( 1 ) ;
2003-11-13 17:34:36 +03:00
2008-05-14 15:42:41 +04:00
if ( ! dev_specified ) {
2008-09-06 17:45:31 +04:00
err ( udev , " no device specified \n " ) ;
2006-01-09 23:18:00 +03:00
retval = 1 ;
goto exit ;
2003-11-13 17:34:36 +03:00
}
2008-09-06 17:45:31 +04:00
retval = scsi_id ( udev , maj_min_dev ) ;
2006-01-09 23:18:00 +03:00
exit :
2008-09-06 17:45:31 +04:00
udev_unref ( udev ) ;
2006-01-09 23:18:00 +03:00
logging_close ( ) ;
return retval ;
2003-11-13 17:34:36 +03:00
}