2005-06-26 01:54:28 +04:00
/*
* ata_id - reads product / serial number from ATA drives
*
2008-09-06 17:45:31 +04:00
* Copyright ( C ) 2005 - 2008 Kay Sievers < kay . sievers @ vrfy . org >
2005-06-26 01:54:28 +04:00
*
2008-09-10 04:40:42 +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-06-26 01:54:28 +04:00
*/
# ifndef _GNU_SOURCE
# define _GNU_SOURCE 1
# endif
# include <stdio.h>
# include <stdlib.h>
# include <unistd.h>
# include <fcntl.h>
# include <ctype.h>
2006-01-09 23:18:00 +03:00
# include <string.h>
2005-06-26 01:54:28 +04:00
# include <errno.h>
2007-05-01 16:19:31 +04:00
# include <getopt.h>
2005-06-26 01:54:28 +04:00
# include <sys/ioctl.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <linux/types.h>
# include <linux/hdreg.h>
2008-07-30 03:45:23 +04:00
# include "../../udev/udev.h"
2005-06-26 01:54:28 +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-06-26 01:54:28 +04:00
{
vsyslog ( priority , format , args ) ;
}
2005-08-01 03:33:36 +04:00
static void set_str ( char * to , const char * from , size_t count )
2005-06-26 01:54:28 +04:00
{
2005-08-01 03:33:36 +04:00
size_t i , j , len ;
2005-06-26 01:54:28 +04:00
2005-06-27 19:04:56 +04:00
/* strip trailing whitespace */
2005-06-26 01:54:28 +04:00
len = strnlen ( from , count ) ;
2005-08-22 13:37:12 +04:00
while ( len & & isspace ( from [ len - 1 ] ) )
2005-06-26 01:54:28 +04:00
len - - ;
2005-06-27 19:04:56 +04:00
/* strip leading whitespace */
2005-06-26 01:54:28 +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-26 01:54:28 +04:00
to [ j + + ] = ' _ ' ;
}
2005-06-27 19:04:56 +04:00
/* skip chars */
if ( from [ i ] = = ' / ' ) {
i + + ;
continue ;
}
to [ j + + ] = from [ i + + ] ;
2005-06-26 01:54:28 +04:00
}
to [ j ] = ' \0 ' ;
}
int main ( int argc , char * argv [ ] )
{
2008-09-06 17:45:31 +04:00
struct udev * udev ;
2005-06-26 01:54:28 +04:00
struct hd_driveid id ;
char model [ 41 ] ;
char serial [ 21 ] ;
char revision [ 9 ] ;
const char * node = NULL ;
int export = 0 ;
int fd ;
int rc = 0 ;
2007-05-01 16:19:31 +04:00
static const struct option options [ ] = {
2008-10-02 18:49:05 +04:00
{ " export " , no_argument , NULL , ' x ' } ,
{ " help " , no_argument , NULL , ' h ' } ,
2007-05-01 16:19:31 +04:00
{ }
} ;
2005-06-26 01:54:28 +04:00
2008-09-06 17:45:31 +04:00
udev = udev_new ( ) ;
if ( udev = = NULL )
goto exit ;
2005-07-13 13:23:21 +04:00
logging_init ( " ata_id " ) ;
2008-09-06 17:45:31 +04:00
udev_set_log_fn ( udev , log_fn ) ;
2005-07-13 13:23:21 +04:00
2007-05-01 16:19:31 +04:00
while ( 1 ) {
int option ;
2005-06-26 01:54:28 +04:00
2007-05-01 16:19:31 +04:00
option = getopt_long ( argc , argv , " xh " , options , NULL ) ;
if ( option = = - 1 )
break ;
switch ( option ) {
case ' x ' :
2005-06-26 01:54:28 +04:00
export = 1 ;
2007-05-01 16:19:31 +04:00
break ;
case ' h ' :
printf ( " Usage: ata_id [--export] [--help] <device> \n "
" --export print values as environemt keys \n "
" --help print this help text \n \n " ) ;
default :
rc = 1 ;
goto exit ;
}
2005-06-26 01:54:28 +04:00
}
2007-05-01 16:19:31 +04:00
node = argv [ optind ] ;
if ( node = = NULL ) {
2008-09-06 17:45:31 +04:00
err ( udev , " no node specified \n " ) ;
2005-06-26 01:54:28 +04:00
rc = 1 ;
goto exit ;
}
2005-09-16 23:23:36 +04:00
fd = open ( node , O_RDONLY | O_NONBLOCK ) ;
2005-06-26 01:54:28 +04:00
if ( fd < 0 ) {
2008-09-06 17:45:31 +04:00
err ( udev , " unable to open '%s' \n " , node ) ;
2005-06-26 01:54:28 +04:00
rc = 1 ;
goto exit ;
}
if ( ioctl ( fd , HDIO_GET_IDENTITY , & id ) ) {
2007-04-29 02:08:30 +04:00
if ( errno = = ENOTTY ) {
2008-09-06 17:45:31 +04:00
info ( udev , " HDIO_GET_IDENTITY unsupported for '%s' \n " , node ) ;
2007-04-29 02:08:30 +04:00
rc = 2 ;
} else {
2008-09-06 17:45:31 +04:00
err ( udev , " HDIO_GET_IDENTITY failed for '%s' \n " , node ) ;
2007-04-29 02:08:30 +04:00
rc = 3 ;
}
2005-06-26 01:54:28 +04:00
goto close ;
}
2005-08-01 03:33:36 +04:00
set_str ( model , ( char * ) id . model , 40 ) ;
set_str ( serial , ( char * ) id . serial_no , 20 ) ;
set_str ( revision , ( char * ) id . fw_rev , 8 ) ;
2005-06-26 01:54:28 +04:00
if ( export ) {
2005-06-27 19:04:56 +04:00
if ( ( id . config > > 8 ) & 0x80 ) {
/* This is an ATAPI device */
switch ( ( id . config > > 8 ) & 0x1f ) {
case 0 :
printf ( " ID_TYPE=cd \n " ) ;
break ;
case 1 :
printf ( " ID_TYPE=tape \n " ) ;
break ;
case 5 :
printf ( " ID_TYPE=cd \n " ) ;
break ;
case 7 :
printf ( " ID_TYPE=optical \n " ) ;
break ;
default :
printf ( " ID_TYPE=generic \n " ) ;
break ;
}
} else {
printf ( " ID_TYPE=disk \n " ) ;
}
2005-06-26 01:54:28 +04:00
printf ( " ID_MODEL=%s \n " , model ) ;
printf ( " ID_SERIAL=%s \n " , serial ) ;
printf ( " ID_REVISION=%s \n " , revision ) ;
2005-07-19 19:18:19 +04:00
printf ( " ID_BUS=ata \n " ) ;
2005-07-12 13:41:09 +04:00
} else {
if ( serial [ 0 ] ! = ' \0 ' )
printf ( " %s_%s \n " , model , serial ) ;
else
printf ( " %s \n " , model ) ;
}
2005-06-26 01:54:28 +04:00
close :
close ( fd ) ;
exit :
2008-09-06 17:45:31 +04:00
udev_unref ( udev ) ;
2005-06-26 01:54:28 +04:00
logging_close ( ) ;
return rc ;
}