2005-07-04 19:02:25 +04:00
/*
2007-10-15 22:38:20 +04:00
* usb_id - identify an USB device
2005-07-04 19:02:25 +04:00
*
* Copyright ( c ) 2005 SUSE Linux Products GmbH , Germany
2005-09-27 18:27:35 +04:00
*
2010-06-25 13:39:21 +04:00
* Author : Hannes Reinecke < hare @ suse . de >
2005-07-04 19:02:25 +04:00
*
2010-06-25 13:39:21 +04: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 , either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
2005-07-04 19:02:25 +04:00
*/
# include <stdio.h>
# include <stdlib.h>
# include <stdarg.h>
# include <unistd.h>
# include <string.h>
# include <ctype.h>
2009-02-26 19:05:58 +03:00
# include <fcntl.h>
2005-07-04 19:02:25 +04:00
# include <errno.h>
2007-03-21 15:55:48 +03:00
# include <getopt.h>
2005-07-04 19:02:25 +04:00
2009-06-10 00:47:48 +04:00
# include "libudev.h"
# include "libudev-private.h"
2005-07-04 19:02:25 +04:00
2008-10-02 23:20:18 +04:00
int debug ;
2005-07-04 19:02:25 +04: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 )
2005-07-04 19:02:25 +04:00
{
2008-10-02 23:20:18 +04:00
if ( debug ) {
fprintf ( stderr , " %s: " , fn ! = NULL ? fn : file ) ;
vfprintf ( stderr , format , args ) ;
} else {
vsyslog ( priority , format , args ) ;
}
2005-07-04 19:02:25 +04:00
}
static char vendor_str [ 64 ] ;
2009-03-25 23:24:21 +03:00
static char vendor_str_enc [ 256 ] ;
static const char * vendor_id = " " ;
2005-07-04 19:02:25 +04:00
static char model_str [ 64 ] ;
2009-02-17 22:15:17 +03:00
static char model_str_enc [ 256 ] ;
2009-03-25 23:24:21 +03:00
static const char * product_id = " " ;
2008-10-02 23:20:18 +04:00
static char serial_str [ UTIL_NAME_SIZE ] ;
2009-02-26 19:05:58 +03:00
static char packed_if_str [ UTIL_NAME_SIZE ] ;
2007-03-21 15:55:48 +03:00
static char revision_str [ 64 ] ;
static char type_str [ 64 ] ;
static char instance_str [ 64 ] ;
2009-03-25 23:24:21 +03:00
static const char * ifnum ;
static const char * driver ;
2005-07-04 19:02:25 +04:00
static int use_usb_info ;
2005-07-08 05:29:19 +04:00
static int use_num_info ;
2005-07-04 19:02:25 +04:00
2006-01-23 21:09:17 +03:00
static void set_usb_iftype ( char * to , int if_class_num , size_t len )
2005-07-04 19:02:25 +04:00
{
2005-08-13 02:18:44 +04:00
char * type = " generic " ;
2005-07-04 19:02:25 +04:00
2006-01-23 21:09:17 +03:00
switch ( if_class_num ) {
case 1 :
type = " audio " ;
break ;
2008-12-29 07:54:44 +03:00
case 2 : /* CDC-Control */
break ;
2006-01-23 21:09:17 +03:00
case 3 :
type = " hid " ;
break ;
2008-12-29 07:54:44 +03:00
case 5 : /* Physical */
break ;
case 6 :
2009-01-05 05:44:28 +03:00
type = " media " ;
2008-12-29 07:54:44 +03:00
break ;
2006-01-23 21:09:17 +03:00
case 7 :
type = " printer " ;
break ;
case 8 :
2007-03-21 15:55:48 +03:00
type = " storage " ;
2006-01-23 21:09:17 +03:00
break ;
2008-12-29 07:54:44 +03:00
case 9 :
type = " hub " ;
2008-11-26 15:38:49 +03:00
break ;
2006-01-23 21:09:17 +03:00
case 0x0a : /* CDC-Data */
2008-11-26 15:38:49 +03:00
break ;
2006-01-23 21:09:17 +03:00
case 0x0b : /* Chip/Smart Card */
2008-11-26 15:38:49 +03:00
break ;
2006-01-23 21:09:17 +03:00
case 0x0d : /* Content Security */
2008-11-26 15:31:37 +03:00
break ;
2008-11-20 04:26:13 +03:00
case 0x0e :
type = " video " ;
break ;
2006-01-23 21:09:17 +03:00
case 0xdc : /* Diagnostic Device */
2008-11-26 15:38:49 +03:00
break ;
2006-01-23 21:09:17 +03:00
case 0xe0 : /* Wireless Controller */
2008-11-26 15:38:49 +03:00
break ;
2008-12-29 07:54:44 +03:00
case 0xfe : /* Application-specific */
2008-11-26 15:38:49 +03:00
break ;
2006-01-23 21:09:17 +03:00
case 0xff : /* Vendor-specific */
break ;
default :
break ;
2005-07-04 19:02:25 +04:00
}
2005-08-13 02:18:44 +04:00
strncpy ( to , type , len ) ;
to [ len - 1 ] = ' \0 ' ;
2005-07-04 19:02:25 +04:00
}
2006-01-23 21:09:17 +03:00
static int set_usb_mass_storage_ifsubtype ( char * to , const char * from , size_t len )
2005-07-04 19:02:25 +04:00
{
int type_num = 0 ;
char * eptr ;
2005-08-13 02:18:44 +04:00
char * type = " generic " ;
2005-07-04 19:02:25 +04:00
type_num = strtoul ( from , & eptr , 0 ) ;
if ( eptr ! = from ) {
switch ( type_num ) {
case 2 :
2009-01-22 21:23:33 +03:00
type = " atapi " ;
2005-07-04 19:02:25 +04:00
break ;
case 3 :
2005-08-13 02:18:44 +04:00
type = " tape " ;
2005-07-04 19:02:25 +04:00
break ;
case 4 : /* UFI */
case 5 : /* SFF-8070i */
2005-08-13 02:18:44 +04:00
type = " floppy " ;
2005-07-04 19:02:25 +04:00
break ;
case 1 : /* RBC devices */
2008-11-05 21:02:56 +03:00
type = " rbc " ;
break ;
2005-07-04 19:02:25 +04:00
case 6 : /* Transparent SPC-2 devices */
2008-11-05 21:02:56 +03:00
type = " scsi " ;
2005-08-13 02:18:44 +04:00
break ;
default :
2005-07-04 19:02:25 +04:00
break ;
}
}
2009-05-20 19:57:52 +04:00
util_strscpy ( to , len , type ) ;
2005-07-04 19:02:25 +04:00
return type_num ;
}
2007-03-21 15:55:48 +03:00
static void set_scsi_type ( char * to , const char * from , size_t len )
2005-07-04 19:02:25 +04:00
{
int type_num ;
char * eptr ;
2007-03-21 15:55:48 +03:00
char * type = " generic " ;
2005-07-04 19:02:25 +04:00
type_num = strtoul ( from , & eptr , 0 ) ;
if ( eptr ! = from ) {
switch ( type_num ) {
case 0 :
2007-03-21 15:55:48 +03:00
case 0xe :
type = " disk " ;
2005-07-04 19:02:25 +04:00
break ;
case 1 :
2007-03-21 15:55:48 +03:00
type = " tape " ;
2005-07-04 19:02:25 +04:00
break ;
case 4 :
case 7 :
case 0xf :
2007-03-21 15:55:48 +03:00
type = " optical " ;
break ;
case 5 :
type = " cd " ;
2005-07-04 19:02:25 +04:00
break ;
default :
break ;
}
}
2009-05-20 19:57:52 +04:00
util_strscpy ( to , len , type ) ;
2005-07-04 19:02:25 +04:00
}
2009-02-26 19:05:58 +03:00
# define USB_DT_DEVICE 0x01
# define USB_DT_INTERFACE 0x04
static int dev_if_packed_info ( struct udev_device * dev , char * ifs_str , size_t len )
{
char * filename = NULL ;
int fd ;
ssize_t size ;
unsigned char buf [ 18 + 65535 ] ;
unsigned int pos , strpos ;
struct usb_interface_descriptor {
u_int8_t bLength ;
u_int8_t bDescriptorType ;
u_int8_t bInterfaceNumber ;
u_int8_t bAlternateSetting ;
u_int8_t bNumEndpoints ;
u_int8_t bInterfaceClass ;
u_int8_t bInterfaceSubClass ;
u_int8_t bInterfaceProtocol ;
u_int8_t iInterface ;
} __attribute__ ( ( packed ) ) ;
2009-02-26 19:58:22 +03:00
int err = 0 ;
2009-02-26 19:05:58 +03:00
if ( asprintf ( & filename , " %s/descriptors " , udev_device_get_syspath ( dev ) ) < 0 ) {
err = - 1 ;
goto out ;
}
fd = open ( filename , O_RDONLY ) ;
if ( fd < 0 ) {
fprintf ( stderr , " error opening USB device 'descriptors' file \n " ) ;
err = - 1 ;
goto out ;
}
size = read ( fd , buf , sizeof ( buf ) ) ;
close ( fd ) ;
if ( size < 18 | | size = = sizeof ( buf ) ) {
err = - 1 ;
goto out ;
}
pos = 0 ;
strpos = 0 ;
while ( pos < sizeof ( buf ) & & strpos + 7 < len ) {
struct usb_interface_descriptor * desc ;
char if_str [ 8 ] ;
desc = ( struct usb_interface_descriptor * ) & buf [ pos ] ;
if ( desc - > bLength < 3 )
break ;
pos + = desc - > bLength ;
if ( desc - > bDescriptorType ! = USB_DT_INTERFACE )
continue ;
if ( snprintf ( if_str , 8 , " %02x%02x%02x: " ,
desc - > bInterfaceClass ,
desc - > bInterfaceSubClass ,
desc - > bInterfaceProtocol ) ! = 7 )
continue ;
if ( strstr ( ifs_str , if_str ) ! = NULL )
continue ;
memcpy ( & ifs_str [ strpos ] , if_str , 8 ) ,
strpos + = 7 ;
}
out :
free ( filename ) ;
2009-02-26 19:58:22 +03:00
return err ;
2009-02-26 19:05:58 +03:00
}
2005-07-04 19:02:25 +04:00
/*
* A unique USB identification is generated like this :
*
2009-02-27 00:10:40 +03:00
* 1. ) Get the USB device type from InterfaceClass and InterfaceSubClass
2005-07-04 19:02:25 +04:00
* 2. ) If the device type is ' Mass - Storage / SPC - 2 ' or ' Mass - Storage / RBC '
* use the SCSI vendor and model as USB - Vendor and USB - model .
* 3. ) Otherwise use the USB manufacturer and product as
* USB - Vendor and USB - model . Any non - printable characters
* in those strings will be skipped ; a slash ' / ' will be converted
* into a full stop ' . ' .
* 4. ) If that fails , too , we will use idVendor and idProduct
* as USB - Vendor and USB - model .
* 5. ) The USB identification is the USB - vendor and USB - model
* string concatenated with an underscore ' _ ' .
* 6. ) If the device supplies a serial number , this number
* is concatenated with the identification with an underscore ' _ ' .
*/
2008-10-02 23:20:18 +04:00
static int usb_id ( struct udev_device * dev )
2005-07-04 19:02:25 +04:00
{
2008-10-02 23:20:18 +04:00
struct udev * udev = udev_device_get_udev ( dev ) ;
2009-02-26 19:58:22 +03:00
struct udev_device * dev_interface = NULL ;
struct udev_device * dev_usb = NULL ;
2006-01-09 23:18:00 +03:00
const char * if_class , * if_subclass ;
2005-07-04 19:02:25 +04:00
int if_class_num ;
int protocol = 0 ;
2008-10-02 23:20:18 +04:00
dbg ( udev , " syspath %s \n " , udev_device_get_syspath ( dev ) ) ;
2005-07-04 19:02:25 +04:00
2009-02-27 00:10:40 +03:00
/* shortcut, if we are called directly for a "usb_device" type */
2009-02-26 22:57:48 +03:00
if ( udev_device_get_devtype ( dev ) ! = NULL & & strcmp ( udev_device_get_devtype ( dev ) , " usb_device " ) = = 0 ) {
2009-02-26 19:58:22 +03:00
dev_if_packed_info ( dev , packed_if_str , sizeof ( packed_if_str ) ) ;
dev_usb = dev ;
goto fallback ;
}
2005-07-04 19:02:25 +04:00
/* usb interface directory */
2009-01-03 17:26:34 +03:00
dev_interface = udev_device_get_parent_with_subsystem_devtype ( dev , " usb " , " usb_interface " ) ;
2006-01-09 23:18:00 +03:00
if ( dev_interface = = NULL ) {
2008-10-02 23:20:18 +04:00
info ( udev , " unable to access usb_interface device of '%s' \n " ,
udev_device_get_syspath ( dev ) ) ;
2005-07-04 19:02:25 +04:00
return 1 ;
}
2005-07-19 22:36:34 +04:00
2009-03-25 23:24:21 +03:00
ifnum = udev_device_get_sysattr_value ( dev_interface , " bInterfaceNumber " ) ;
driver = udev_device_get_sysattr_value ( dev_interface , " driver " ) ;
2008-10-20 20:12:36 +04:00
if_class = udev_device_get_sysattr_value ( dev_interface , " bInterfaceClass " ) ;
2005-07-04 19:02:25 +04:00
if ( ! if_class ) {
2008-10-02 23:20:18 +04:00
info ( udev , " %s: cannot get bInterfaceClass attribute \n " ,
udev_device_get_sysname ( dev ) ) ;
2005-07-08 05:29:19 +04:00
return 1 ;
2005-07-04 19:02:25 +04:00
}
2009-01-22 21:23:33 +03:00
2006-01-09 23:18:00 +03:00
if_class_num = strtoul ( if_class , NULL , 16 ) ;
2006-01-23 21:09:17 +03:00
if ( if_class_num = = 8 ) {
2009-01-22 21:23:33 +03:00
/* mass storage */
2008-10-20 20:12:36 +04:00
if_subclass = udev_device_get_sysattr_value ( dev_interface , " bInterfaceSubClass " ) ;
2006-01-23 21:09:17 +03:00
if ( if_subclass ! = NULL )
protocol = set_usb_mass_storage_ifsubtype ( type_str , if_subclass , sizeof ( type_str ) - 1 ) ;
2008-10-02 23:20:18 +04:00
} else {
2006-01-23 21:09:17 +03:00
set_usb_iftype ( type_str , if_class_num , sizeof ( type_str ) - 1 ) ;
2008-10-02 23:20:18 +04:00
}
2006-01-23 21:09:17 +03:00
2008-10-02 23:20:18 +04:00
info ( udev , " %s: if_class %d protocol %d \n " ,
udev_device_get_syspath ( dev_interface ) , if_class_num , protocol ) ;
2006-01-23 21:09:17 +03:00
/* usb device directory */
2009-01-03 17:26:34 +03:00
dev_usb = udev_device_get_parent_with_subsystem_devtype ( dev_interface , " usb " , " usb_device " ) ;
2006-01-23 21:09:17 +03:00
if ( ! dev_usb ) {
2008-10-02 23:20:18 +04:00
info ( udev , " unable to find parent 'usb' device of '%s' \n " ,
udev_device_get_syspath ( dev ) ) ;
2006-01-23 21:09:17 +03:00
return 1 ;
2005-07-04 19:02:25 +04:00
}
2009-02-26 19:05:58 +03:00
/* all interfaces of the device in a single string */
dev_if_packed_info ( dev_usb , packed_if_str , sizeof ( packed_if_str ) ) ;
2009-01-22 21:23:33 +03:00
/* mass storage : SCSI or ATAPI */
if ( ( protocol = = 6 | | protocol = = 2 ) & & ! use_usb_info ) {
2008-10-02 23:20:18 +04:00
struct udev_device * dev_scsi ;
2007-10-15 22:38:20 +04:00
const char * scsi_model , * scsi_vendor , * scsi_type , * scsi_rev ;
2007-03-21 15:55:48 +03:00
int host , bus , target , lun ;
2006-01-23 21:09:17 +03:00
/* get scsi device */
2009-01-03 17:26:34 +03:00
dev_scsi = udev_device_get_parent_with_subsystem_devtype ( dev , " scsi " , " scsi_device " ) ;
2006-01-23 21:09:17 +03:00
if ( dev_scsi = = NULL ) {
2008-10-02 23:20:18 +04:00
info ( udev , " unable to find parent 'scsi' device of '%s' \n " ,
udev_device_get_syspath ( dev ) ) ;
2006-01-23 21:09:17 +03:00
goto fallback ;
}
2008-10-02 23:20:18 +04:00
if ( sscanf ( udev_device_get_sysname ( dev_scsi ) , " %d:%d:%d:%d " , & host , & bus , & target , & lun ) ! = 4 ) {
info ( udev , " invalid scsi device '%s' \n " , udev_device_get_sysname ( dev_scsi ) ) ;
2007-03-21 15:55:48 +03:00
goto fallback ;
}
2006-01-23 21:09:17 +03:00
2005-07-04 19:02:25 +04:00
/* Generic SPC-2 device */
2008-10-20 20:12:36 +04:00
scsi_vendor = udev_device_get_sysattr_value ( dev_scsi , " vendor " ) ;
2005-07-04 19:02:25 +04:00
if ( ! scsi_vendor ) {
2008-10-02 23:20:18 +04:00
info ( udev , " %s: cannot get SCSI vendor attribute \n " ,
udev_device_get_sysname ( dev_scsi ) ) ;
2006-01-23 21:09:17 +03:00
goto fallback ;
2005-07-04 19:02:25 +04:00
}
2009-02-17 22:15:17 +03:00
udev_util_encode_string ( scsi_vendor , vendor_str_enc , sizeof ( vendor_str_enc ) ) ;
2008-11-05 23:49:52 +03:00
udev_util_replace_whitespace ( scsi_vendor , vendor_str , sizeof ( vendor_str ) - 1 ) ;
2008-11-20 04:44:08 +03:00
udev_util_replace_chars ( vendor_str , NULL ) ;
2005-07-04 19:02:25 +04:00
2008-10-20 20:12:36 +04:00
scsi_model = udev_device_get_sysattr_value ( dev_scsi , " model " ) ;
2005-07-04 19:02:25 +04:00
if ( ! scsi_model ) {
2008-10-02 23:20:18 +04:00
info ( udev , " %s: cannot get SCSI model attribute \n " ,
udev_device_get_sysname ( dev_scsi ) ) ;
2006-01-23 21:09:17 +03:00
goto fallback ;
2005-07-04 19:02:25 +04:00
}
2009-02-17 22:15:17 +03:00
udev_util_encode_string ( scsi_model , model_str_enc , sizeof ( model_str_enc ) ) ;
2008-11-05 23:49:52 +03:00
udev_util_replace_whitespace ( scsi_model , model_str , sizeof ( model_str ) - 1 ) ;
2008-11-20 04:44:08 +03:00
udev_util_replace_chars ( model_str , NULL ) ;
2005-07-04 19:02:25 +04:00
2008-10-20 20:12:36 +04:00
scsi_type = udev_device_get_sysattr_value ( dev_scsi , " type " ) ;
2005-07-04 19:02:25 +04:00
if ( ! scsi_type ) {
2008-10-02 23:20:18 +04:00
info ( udev , " %s: cannot get SCSI type attribute \n " ,
udev_device_get_sysname ( dev_scsi ) ) ;
2006-01-23 21:09:17 +03:00
goto fallback ;
2005-07-04 19:02:25 +04:00
}
2006-01-09 23:18:00 +03:00
set_scsi_type ( type_str , scsi_type , sizeof ( type_str ) - 1 ) ;
2005-07-04 19:02:25 +04:00
2008-10-20 20:12:36 +04:00
scsi_rev = udev_device_get_sysattr_value ( dev_scsi , " rev " ) ;
2005-07-04 19:02:25 +04:00
if ( ! scsi_rev ) {
2008-10-02 23:20:18 +04:00
info ( udev , " %s: cannot get SCSI revision attribute \n " ,
udev_device_get_sysname ( dev_scsi ) ) ;
2006-01-23 21:09:17 +03:00
goto fallback ;
2005-07-04 19:02:25 +04:00
}
2008-11-05 23:49:52 +03:00
udev_util_replace_whitespace ( scsi_rev , revision_str , sizeof ( revision_str ) - 1 ) ;
2008-11-20 04:44:08 +03:00
udev_util_replace_chars ( revision_str , NULL ) ;
2007-03-21 15:55:48 +03:00
/*
* some broken devices have the same identifiers
* for all luns , export the target : lun number
*/
sprintf ( instance_str , " %d:%d " , target , lun ) ;
2005-07-04 19:02:25 +04:00
}
2006-01-23 21:09:17 +03:00
fallback :
2009-03-25 23:24:21 +03:00
vendor_id = udev_device_get_sysattr_value ( dev_usb , " idVendor " ) ;
product_id = udev_device_get_sysattr_value ( dev_usb , " idProduct " ) ;
2007-10-15 22:38:20 +04:00
/* fallback to USB vendor & device */
2005-07-04 19:02:25 +04:00
if ( vendor_str [ 0 ] = = ' \0 ' ) {
2007-10-15 22:38:20 +04:00
const char * usb_vendor = NULL ;
2005-07-08 05:29:19 +04:00
if ( ! use_num_info )
2008-10-20 20:12:36 +04:00
usb_vendor = udev_device_get_sysattr_value ( dev_usb , " manufacturer " ) ;
2007-10-15 22:38:20 +04:00
if ( ! usb_vendor )
2009-03-25 23:24:21 +03:00
usb_vendor = vendor_id ;
2005-07-08 05:29:19 +04:00
2005-07-04 19:02:25 +04:00
if ( ! usb_vendor ) {
2008-09-06 17:45:31 +04:00
info ( udev , " No USB vendor information available \n " ) ;
2007-10-15 22:38:20 +04:00
return 1 ;
2005-07-04 19:02:25 +04:00
}
2009-02-17 22:15:17 +03:00
udev_util_encode_string ( usb_vendor , vendor_str_enc , sizeof ( vendor_str_enc ) ) ;
2008-11-05 23:49:52 +03:00
udev_util_replace_whitespace ( usb_vendor , vendor_str , sizeof ( vendor_str ) - 1 ) ;
2008-11-20 04:44:08 +03:00
udev_util_replace_chars ( vendor_str , NULL ) ;
2005-07-04 19:02:25 +04:00
}
2007-10-15 22:38:20 +04:00
2005-07-04 19:02:25 +04:00
if ( model_str [ 0 ] = = ' \0 ' ) {
2007-10-15 22:38:20 +04:00
const char * usb_model = NULL ;
2005-07-08 05:29:19 +04:00
if ( ! use_num_info )
2008-10-20 20:12:36 +04:00
usb_model = udev_device_get_sysattr_value ( dev_usb , " product " ) ;
2007-10-15 22:38:20 +04:00
if ( ! usb_model )
2009-03-25 23:24:21 +03:00
usb_model = product_id ;
2007-10-15 22:38:20 +04:00
2005-07-04 19:02:25 +04:00
if ( ! usb_model ) {
2008-09-29 21:03:08 +04:00
dbg ( udev , " No USB model information available \n " ) ;
2007-10-15 22:38:20 +04:00
return 1 ;
2005-07-04 19:02:25 +04:00
}
2009-02-17 22:15:17 +03:00
udev_util_encode_string ( usb_model , model_str_enc , sizeof ( model_str_enc ) ) ;
2008-11-05 23:49:52 +03:00
udev_util_replace_whitespace ( usb_model , model_str , sizeof ( model_str ) - 1 ) ;
2008-11-20 04:44:08 +03:00
udev_util_replace_chars ( model_str , NULL ) ;
2005-07-04 19:02:25 +04:00
}
if ( revision_str [ 0 ] = = ' \0 ' ) {
2007-10-15 22:38:20 +04:00
const char * usb_rev ;
2008-10-20 20:12:36 +04:00
usb_rev = udev_device_get_sysattr_value ( dev_usb , " bcdDevice " ) ;
2008-11-20 04:44:08 +03:00
if ( usb_rev ) {
2008-11-05 23:49:52 +03:00
udev_util_replace_whitespace ( usb_rev , revision_str , sizeof ( revision_str ) - 1 ) ;
2008-11-20 04:44:08 +03:00
udev_util_replace_chars ( revision_str , NULL ) ;
}
2005-07-04 19:02:25 +04:00
}
if ( serial_str [ 0 ] = = ' \0 ' ) {
2007-10-15 22:38:20 +04:00
const char * usb_serial ;
2008-10-20 20:12:36 +04:00
usb_serial = udev_device_get_sysattr_value ( dev_usb , " serial " ) ;
2008-11-20 04:44:08 +03:00
if ( usb_serial ) {
2008-11-05 23:49:52 +03:00
udev_util_replace_whitespace ( usb_serial , serial_str , sizeof ( serial_str ) - 1 ) ;
2008-11-20 04:44:08 +03:00
udev_util_replace_chars ( serial_str , NULL ) ;
}
2005-07-04 19:02:25 +04:00
}
return 0 ;
}
int main ( int argc , char * * argv )
{
2007-03-21 15:55:48 +03:00
static const struct option options [ ] = {
2008-10-02 18:49:05 +04:00
{ " usb-info " , no_argument , NULL , ' u ' } ,
{ " num-info " , no_argument , NULL , ' n ' } ,
{ " export " , no_argument , NULL , ' x ' } ,
2008-10-02 23:20:18 +04:00
{ " debug " , no_argument , NULL , ' d ' } ,
2008-10-02 18:49:05 +04:00
{ " help " , no_argument , NULL , ' h ' } ,
2007-03-21 15:55:48 +03:00
{ }
} ;
2008-10-02 23:20:18 +04:00
struct udev * udev ;
2008-10-24 11:37:37 +04:00
struct udev_device * dev = NULL ;
2008-10-02 23:20:18 +04:00
static int export ;
int retval = 0 ;
2006-01-09 23:18:00 +03:00
2008-09-06 17:45:31 +04:00
udev = udev_new ( ) ;
if ( udev = = NULL )
goto exit ;
2009-06-10 00:47:48 +04:00
udev_log_init ( " usb_id " ) ;
2008-09-06 17:45:31 +04:00
udev_set_log_fn ( udev , log_fn ) ;
2007-05-01 16:18:36 +04:00
2007-03-21 15:55:48 +03:00
while ( 1 ) {
int option ;
2008-10-02 23:20:18 +04:00
option = getopt_long ( argc , argv , " dnuxh " , options , NULL ) ;
2007-03-21 15:55:48 +03:00
if ( option = = - 1 )
break ;
2005-07-04 19:02:25 +04:00
switch ( option ) {
2008-10-02 23:20:18 +04:00
case ' d ' :
debug = 1 ;
if ( udev_get_log_priority ( udev ) < LOG_INFO )
udev_set_log_priority ( udev , LOG_INFO ) ;
break ;
2005-07-08 05:29:19 +04:00
case ' n ' :
2006-01-09 23:18:00 +03:00
use_num_info = 1 ;
use_usb_info = 1 ;
2005-07-08 05:29:19 +04:00
break ;
2005-07-04 19:02:25 +04:00
case ' u ' :
2006-01-09 23:18:00 +03:00
use_usb_info = 1 ;
2005-07-04 19:02:25 +04:00
break ;
case ' x ' :
2006-01-09 23:18:00 +03:00
export = 1 ;
2005-07-04 19:02:25 +04:00
break ;
2007-03-21 15:55:48 +03:00
case ' h ' :
2010-03-17 19:42:35 +03:00
printf ( " Usage: usb_id [--usb-info] [--num-info] [--export] [--help] [<devpath>] \n "
2007-03-21 15:55:48 +03:00
" --usb-info use usb strings instead \n "
" --num-info use numerical values \n "
2009-01-06 21:43:01 +03:00
" --export print values as environment keys \n "
2007-03-21 15:55:48 +03:00
" --help print this help text \n \n " ) ;
2005-07-04 19:02:25 +04:00
default :
2005-07-08 05:29:19 +04:00
retval = 1 ;
2007-03-21 15:55:48 +03:00
goto exit ;
2005-07-04 19:02:25 +04:00
}
}
2010-03-17 19:42:35 +03:00
dev = udev_device_new_from_environment ( udev ) ;
2008-10-02 23:20:18 +04:00
if ( dev = = NULL ) {
2010-03-17 19:42:35 +03:00
char syspath [ UTIL_PATH_SIZE ] ;
const char * devpath ;
devpath = argv [ optind ] ;
if ( devpath = = NULL ) {
fprintf ( stderr , " missing device \n " ) ;
retval = 1 ;
goto exit ;
}
util_strscpyl ( syspath , sizeof ( syspath ) , udev_get_sys_path ( udev ) , devpath , NULL ) ;
dev = udev_device_new_from_syspath ( udev , syspath ) ;
if ( dev = = NULL ) {
err ( udev , " unable to access '%s' \n " , devpath ) ;
retval = 1 ;
goto exit ;
return 1 ;
}
2008-10-02 23:20:18 +04:00
}
2005-07-04 19:02:25 +04:00
2008-10-02 23:20:18 +04:00
retval = usb_id ( dev ) ;
2005-07-08 05:29:19 +04:00
if ( retval = = 0 ) {
2007-03-21 15:55:48 +03:00
char serial [ 256 ] ;
2009-05-20 19:57:52 +04:00
size_t l ;
char * s ;
s = serial ;
l = util_strpcpyl ( & s , sizeof ( serial ) , vendor_str , " _ " , model_str , NULL ) ;
if ( serial_str [ 0 ] ! = ' \0 ' )
l = util_strpcpyl ( & s , l , " _ " , serial_str , NULL ) ;
if ( instance_str [ 0 ] ! = ' \0 ' )
util_strpcpyl ( & s , l , " - " , instance_str , NULL ) ;
2007-03-21 15:55:48 +03:00
2005-07-08 05:29:19 +04:00
if ( export ) {
printf ( " ID_VENDOR=%s \n " , vendor_str ) ;
2009-02-17 22:15:17 +03:00
printf ( " ID_VENDOR_ENC=%s \n " , vendor_str_enc ) ;
2009-03-25 23:24:21 +03:00
printf ( " ID_VENDOR_ID=%s \n " , vendor_id ) ;
2005-07-08 05:29:19 +04:00
printf ( " ID_MODEL=%s \n " , model_str ) ;
2009-02-17 22:15:17 +03:00
printf ( " ID_MODEL_ENC=%s \n " , model_str_enc ) ;
2009-03-25 23:24:21 +03:00
printf ( " ID_MODEL_ID=%s \n " , product_id ) ;
2005-07-08 05:29:19 +04:00
printf ( " ID_REVISION=%s \n " , revision_str ) ;
2007-03-21 15:55:48 +03:00
printf ( " ID_SERIAL=%s \n " , serial ) ;
if ( serial_str [ 0 ] ! = ' \0 ' )
printf ( " ID_SERIAL_SHORT=%s \n " , serial_str ) ;
2009-02-26 19:58:22 +03:00
if ( type_str [ 0 ] ! = ' \0 ' )
printf ( " ID_TYPE=%s \n " , type_str ) ;
2007-03-21 15:55:48 +03:00
if ( instance_str [ 0 ] ! = ' \0 ' )
printf ( " ID_INSTANCE=%s \n " , instance_str ) ;
2005-07-19 19:18:19 +04:00
printf ( " ID_BUS=usb \n " ) ;
2009-02-26 19:05:58 +03:00
if ( packed_if_str [ 0 ] ! = ' \0 ' )
printf ( " ID_USB_INTERFACES=:%s \n " , packed_if_str ) ;
2009-03-25 23:24:21 +03:00
if ( ifnum ! = NULL )
printf ( " ID_USB_INTERFACE_NUM=%s \n " , ifnum ) ;
if ( driver ! = NULL )
printf ( " ID_USB_DRIVER=%s \n " , driver ) ;
2007-03-21 15:55:48 +03:00
} else
printf ( " %s \n " , serial ) ;
2005-07-04 19:02:25 +04:00
}
2006-01-09 23:18:00 +03:00
exit :
2008-10-02 23:20:18 +04:00
udev_device_unref ( dev ) ;
2008-09-06 17:45:31 +04:00
udev_unref ( udev ) ;
2009-06-10 00:47:48 +04:00
udev_log_close ( ) ;
2006-01-09 23:18:00 +03:00
return retval ;
2005-07-04 19:02:25 +04:00
}