2005-08-12 00:59:21 +04:00
/*
2008-04-10 01:17:39 +04:00
* cdrom_id - optical drive and media information prober
2005-08-12 00:59:21 +04:00
*
2008-04-10 01:17:39 +04:00
* Copyright ( C ) 2008 Kay Sievers < kay . sievers @ vrfy . org >
2005-08-12 00:59:21 +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 .
2005-08-12 00:59:21 +04:00
*
2008-09-10 04:40:42 +04:00
* 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 .
2008-04-10 01:17:39 +04:00
*
2008-09-10 04:40:42 +04:00
* 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-08-12 00:59:21 +04:00
*/
# ifndef _GNU_SOURCE
# define _GNU_SOURCE 1
# endif
# include <stdio.h>
2008-04-10 01:17:39 +04:00
# include <stddef.h>
2005-08-12 00:59:21 +04:00
# include <stdlib.h>
# include <unistd.h>
2006-01-09 23:18:00 +03:00
# include <string.h>
2008-04-10 01:17:39 +04:00
# include <limits.h>
# include <fcntl.h>
2005-08-12 00:59:21 +04:00
# include <errno.h>
2008-04-10 01:17:39 +04:00
# include <getopt.h>
2010-04-07 11:24:25 +04:00
# include <time.h>
2008-04-10 01:17:39 +04:00
# include <scsi/sg.h>
2005-08-12 00:59:21 +04:00
# include <sys/types.h>
# include <sys/stat.h>
2008-04-10 01:17:39 +04:00
# include <sys/time.h>
# include <sys/ioctl.h>
# include <linux/cdrom.h>
2008-07-30 03:45:23 +04:00
2009-06-10 00:47:48 +04:00
# include "libudev.h"
# include "libudev-private.h"
2005-08-12 00:59:21 +04:00
2008-04-10 01:17:39 +04:00
static int debug ;
2005-08-12 22:37:56 +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-08-12 00:59:21 +04:00
{
2008-04-10 01:17:39 +04:00
if ( debug ) {
2008-09-06 17:45:31 +04:00
fprintf ( stderr , " %s: " , fn ) ;
2008-04-10 01:17:39 +04:00
vfprintf ( stderr , format , args ) ;
2008-09-06 17:45:31 +04:00
} else {
2008-04-10 01:17:39 +04:00
vsyslog ( priority , format , args ) ;
2008-09-06 17:45:31 +04:00
}
2005-08-12 00:59:21 +04:00
}
2008-04-10 01:17:39 +04:00
/* device info */
static unsigned int cd_cd_rom ;
static unsigned int cd_cd_r ;
static unsigned int cd_cd_rw ;
static unsigned int cd_dvd_rom ;
static unsigned int cd_dvd_r ;
static unsigned int cd_dvd_rw ;
static unsigned int cd_dvd_ram ;
static unsigned int cd_dvd_plus_r ;
static unsigned int cd_dvd_plus_rw ;
static unsigned int cd_dvd_plus_r_dl ;
static unsigned int cd_dvd_plus_rw_dl ;
static unsigned int cd_bd ;
static unsigned int cd_bd_r ;
static unsigned int cd_bd_re ;
static unsigned int cd_hddvd ;
static unsigned int cd_hddvd_r ;
static unsigned int cd_hddvd_rw ;
static unsigned int cd_mo ;
static unsigned int cd_mrw ;
static unsigned int cd_mrw_w ;
/* media info */
2009-04-21 05:27:14 +04:00
static unsigned int cd_media ;
2008-04-10 01:17:39 +04:00
static unsigned int cd_media_cd_rom ;
static unsigned int cd_media_cd_r ;
static unsigned int cd_media_cd_rw ;
static unsigned int cd_media_dvd_rom ;
static unsigned int cd_media_dvd_r ;
static unsigned int cd_media_dvd_rw ;
static unsigned int cd_media_dvd_ram ;
static unsigned int cd_media_dvd_plus_r ;
static unsigned int cd_media_dvd_plus_rw ;
static unsigned int cd_media_dvd_plus_r_dl ;
static unsigned int cd_media_dvd_plus_rw_dl ;
static unsigned int cd_media_bd ;
static unsigned int cd_media_bd_r ;
static unsigned int cd_media_bd_re ;
static unsigned int cd_media_hddvd ;
static unsigned int cd_media_hddvd_r ;
static unsigned int cd_media_hddvd_rw ;
static unsigned int cd_media_mo ;
static unsigned int cd_media_mrw ;
static unsigned int cd_media_mrw_w ;
static const char * cd_media_state ;
static unsigned int cd_media_session_next ;
static unsigned int cd_media_session_count ;
static unsigned int cd_media_track_count ;
2008-06-12 01:24:13 +04:00
static unsigned int cd_media_track_count_data ;
static unsigned int cd_media_track_count_audio ;
2008-04-10 01:17:39 +04:00
static unsigned long long int cd_media_session_last_offset ;
# define ERRCODE(s) ((((s)[2] & 0x0F) << 16) | ((s)[12] << 8) | ((s)[13]))
# define SK(errcode) (((errcode) >> 16) & 0xF)
# define ASC(errcode) (((errcode) >> 8) & 0xFF)
# define ASCQ(errcode) ((errcode) & 0xFF)
2010-03-18 13:14:32 +03:00
static int is_mounted ( const char * device )
{
struct stat statbuf ;
FILE * fp ;
int maj , min ;
int mounted = 0 ;
if ( stat ( device , & statbuf ) < 0 )
return - ENODEV ;
fp = fopen ( " /proc/self/mountinfo " , " r " ) ;
if ( fp = = NULL )
return - ENOSYS ;
while ( fscanf ( fp , " %*s %*s %i:%i %*[^ \n ] " , & maj , & min ) = = 2 ) {
if ( makedev ( maj , min ) = = statbuf . st_rdev ) {
mounted = 1 ;
break ;
}
}
fclose ( fp ) ;
return mounted ;
}
2008-09-06 17:45:31 +04:00
static void info_scsi_cmd_err ( struct udev * udev , char * cmd , int err )
2008-04-10 01:17:39 +04:00
{
if ( err = = - 1 ) {
2008-09-06 17:45:31 +04:00
info ( udev , " %s failed \n " , cmd ) ;
2008-04-10 01:17:39 +04:00
return ;
}
2008-09-06 17:45:31 +04:00
info ( udev , " %s failed with SK=%Xh/ASC=%02Xh/ACQ=%02Xh \n " , cmd , SK ( err ) , ASC ( err ) , ASCQ ( err ) ) ;
2008-04-10 01:17:39 +04:00
}
struct scsi_cmd {
struct cdrom_generic_command cgc ;
union {
struct request_sense s ;
unsigned char u [ 18 ] ;
} _sense ;
struct sg_io_hdr sg_io ;
} ;
2008-09-06 17:45:31 +04:00
static void scsi_cmd_set ( struct udev * udev , struct scsi_cmd * cmd , size_t i , int arg )
2008-04-10 01:17:39 +04:00
{
if ( i = = 0 ) {
memset ( cmd , 0x00 , sizeof ( struct scsi_cmd ) ) ;
cmd - > cgc . quiet = 1 ;
cmd - > cgc . sense = & cmd - > _sense . s ;
memset ( & cmd - > sg_io , 0 , sizeof ( cmd - > sg_io ) ) ;
cmd - > sg_io . interface_id = ' S ' ;
cmd - > sg_io . mx_sb_len = sizeof ( cmd - > _sense ) ;
cmd - > sg_io . cmdp = cmd - > cgc . cmd ;
cmd - > sg_io . sbp = cmd - > _sense . u ;
cmd - > sg_io . flags = SG_FLAG_LUN_INHIBIT | SG_FLAG_DIRECT_IO ;
}
cmd - > sg_io . cmd_len = i + 1 ;
cmd - > cgc . cmd [ i ] = arg ;
}
# define CHECK_CONDITION 0x01
2008-09-06 17:45:31 +04:00
static int scsi_cmd_run ( struct udev * udev , struct scsi_cmd * cmd , int fd , unsigned char * buf , size_t bufsize )
2008-04-10 01:17:39 +04:00
{
int ret = 0 ;
cmd - > sg_io . dxferp = buf ;
cmd - > sg_io . dxfer_len = bufsize ;
cmd - > sg_io . dxfer_direction = SG_DXFER_FROM_DEV ;
if ( ioctl ( fd , SG_IO , & cmd - > sg_io ) )
return - 1 ;
if ( ( cmd - > sg_io . info & SG_INFO_OK_MASK ) ! = SG_INFO_OK ) {
errno = EIO ;
ret = - 1 ;
if ( cmd - > sg_io . masked_status & CHECK_CONDITION ) {
ret = ERRCODE ( cmd - > _sense . u ) ;
if ( ret = = 0 )
ret = - 1 ;
}
}
return ret ;
}
2008-09-06 17:45:31 +04:00
static int cd_capability_compat ( struct udev * udev , int fd )
2008-04-10 01:17:39 +04:00
{
2009-08-08 17:29:38 +04:00
int capability ;
2008-04-10 01:17:39 +04:00
2009-08-08 17:29:38 +04:00
capability = ioctl ( fd , CDROM_GET_CAPABILITY , NULL ) ;
if ( capability < 0 ) {
2008-09-06 17:45:31 +04:00
info ( udev , " CDROM_GET_CAPABILITY failed \n " ) ;
2008-04-10 01:17:39 +04:00
return - 1 ;
}
2009-08-08 17:29:38 +04:00
if ( capability & CDC_CD_R )
2008-04-10 01:17:39 +04:00
cd_cd_r = 1 ;
2009-08-08 17:29:38 +04:00
if ( capability & CDC_CD_RW )
2008-04-10 01:17:39 +04:00
cd_cd_rw = 1 ;
2009-08-08 17:29:38 +04:00
if ( capability & CDC_DVD )
2008-04-10 01:17:39 +04:00
cd_dvd_rom = 1 ;
2009-08-08 17:29:38 +04:00
if ( capability & CDC_DVD_R )
2008-04-10 01:17:39 +04:00
cd_dvd_r = 1 ;
2009-08-08 17:29:38 +04:00
if ( capability & CDC_DVD_RAM )
2008-04-10 01:17:39 +04:00
cd_dvd_ram = 1 ;
2009-08-08 17:29:38 +04:00
if ( capability & CDC_MRW )
2008-04-10 01:17:39 +04:00
cd_mrw = 1 ;
2009-08-08 17:29:38 +04:00
if ( capability & CDC_MRW_W )
2008-04-10 01:17:39 +04:00
cd_mrw_w = 1 ;
return 0 ;
}
2009-04-23 17:04:16 +04:00
static int cd_media_compat ( struct udev * udev , int fd )
{
if ( ioctl ( fd , CDROM_DRIVE_STATUS , CDSL_CURRENT ) ! = CDS_DISC_OK ) {
info ( udev , " CDROM_DRIVE_STATUS != CDS_DISC_OK \n " ) ;
return - 1 ;
}
cd_media = 1 ;
return 0 ;
}
2008-09-06 17:45:31 +04:00
static int cd_inquiry ( struct udev * udev , int fd ) {
2008-04-10 01:17:39 +04:00
struct scsi_cmd sc ;
unsigned char inq [ 128 ] ;
int err ;
2008-09-06 17:45:31 +04:00
scsi_cmd_set ( udev , & sc , 0 , 0x12 ) ;
scsi_cmd_set ( udev , & sc , 4 , 36 ) ;
scsi_cmd_set ( udev , & sc , 5 , 0 ) ;
err = scsi_cmd_run ( udev , & sc , fd , inq , 36 ) ;
2008-04-10 01:17:39 +04:00
if ( ( err < 0 ) ) {
2008-09-06 17:45:31 +04:00
info_scsi_cmd_err ( udev , " INQUIRY " , err ) ;
2008-04-10 01:17:39 +04:00
return - 1 ;
}
if ( ( inq [ 0 ] & 0x1F ) ! = 5 ) {
2008-09-06 17:45:31 +04:00
info ( udev , " not an MMC unit \n " ) ;
2008-04-10 01:17:39 +04:00
return - 1 ;
}
2008-09-06 17:45:31 +04:00
info ( udev , " INQUIRY: [%.8s][%.16s][%.4s] \n " , inq + 8 , inq + 16 , inq + 32 ) ;
2008-04-10 01:17:39 +04:00
return 0 ;
}
2008-09-06 17:45:31 +04:00
static int cd_profiles ( struct udev * udev , int fd )
2008-04-10 01:17:39 +04:00
{
struct scsi_cmd sc ;
unsigned char header [ 8 ] ;
unsigned char profiles [ 512 ] ;
unsigned int cur_profile ;
unsigned int len ;
unsigned int i ;
int err ;
2008-09-06 17:45:31 +04:00
scsi_cmd_set ( udev , & sc , 0 , 0x46 ) ;
scsi_cmd_set ( udev , & sc , 1 , 0 ) ;
scsi_cmd_set ( udev , & sc , 8 , sizeof ( header ) ) ;
scsi_cmd_set ( udev , & sc , 9 , 0 ) ;
err = scsi_cmd_run ( udev , & sc , fd , header , sizeof ( header ) ) ;
2008-04-10 01:17:39 +04:00
if ( ( err < 0 ) ) {
2008-09-06 17:45:31 +04:00
info_scsi_cmd_err ( udev , " GET CONFIGURATION " , err ) ;
2008-04-10 01:17:39 +04:00
return - 1 ;
}
len = 4 + ( header [ 0 ] < < 24 | header [ 1 ] < < 16 | header [ 2 ] < < 8 | header [ 3 ] ) ;
2008-09-06 17:45:31 +04:00
info ( udev , " GET CONFIGURATION: number of profiles %i \n " , len ) ;
2008-04-10 01:17:39 +04:00
if ( len > sizeof ( profiles ) ) {
2008-09-06 17:45:31 +04:00
info ( udev , " invalid number of profiles \n " ) ;
2008-04-10 01:17:39 +04:00
return - 1 ;
}
2008-09-06 17:45:31 +04:00
scsi_cmd_set ( udev , & sc , 0 , 0x46 ) ;
scsi_cmd_set ( udev , & sc , 1 , 1 ) ;
scsi_cmd_set ( udev , & sc , 6 , len > > 16 ) ;
scsi_cmd_set ( udev , & sc , 7 , len > > 8 ) ;
scsi_cmd_set ( udev , & sc , 8 , len ) ;
scsi_cmd_set ( udev , & sc , 9 , 0 ) ;
err = scsi_cmd_run ( udev , & sc , fd , profiles , len ) ;
2008-04-10 01:17:39 +04:00
if ( ( err < 0 ) ) {
2008-09-06 17:45:31 +04:00
info_scsi_cmd_err ( udev , " GET CONFIGURATION " , err ) ;
2008-04-10 01:17:39 +04:00
return - 1 ;
}
/* device profiles */
for ( i = 12 ; i < profiles [ 11 ] ; i + = 4 ) {
unsigned int profile = ( profiles [ i ] < < 8 | profiles [ i + 1 ] ) ;
if ( profile = = 0 )
continue ;
2008-09-06 17:45:31 +04:00
info ( udev , " profile 0x%02x \n " , profile ) ;
2008-04-10 01:17:39 +04:00
switch ( profile ) {
case 0x03 :
case 0x04 :
case 0x05 :
cd_mo = 1 ;
break ;
case 0x10 :
cd_dvd_rom = 1 ;
break ;
case 0x12 :
cd_dvd_ram = 1 ;
break ;
case 0x13 :
case 0x14 :
cd_dvd_rw = 1 ;
break ;
case 0x1B :
cd_dvd_plus_r = 1 ;
break ;
case 0x1A :
cd_dvd_plus_rw = 1 ;
break ;
case 0x2A :
cd_dvd_plus_rw_dl = 1 ;
break ;
case 0x2B :
cd_dvd_plus_r_dl = 1 ;
break ;
case 0x40 :
cd_bd = 1 ;
break ;
case 0x41 :
case 0x42 :
cd_bd_r = 1 ;
break ;
case 0x43 :
cd_bd_re = 1 ;
break ;
case 0x50 :
cd_hddvd = 1 ;
break ;
case 0x51 :
cd_hddvd_r = 1 ;
break ;
case 0x52 :
cd_hddvd_rw = 1 ;
break ;
default :
break ;
}
}
/* current media profile */
cur_profile = header [ 6 ] < < 8 | header [ 7 ] ;
2008-09-06 17:45:31 +04:00
info ( udev , " current profile 0x%02x \n " , cur_profile ) ;
2008-04-10 01:17:39 +04:00
if ( cur_profile = = 0 ) {
2008-09-06 17:45:31 +04:00
info ( udev , " no current profile, assuming no media \n " ) ;
2008-04-10 01:17:39 +04:00
return - 1 ;
}
2009-04-21 05:27:14 +04:00
cd_media = 1 ;
2008-04-10 01:17:39 +04:00
switch ( cur_profile ) {
case 0x03 :
case 0x04 :
case 0x05 :
cd_media_mo = 1 ;
break ;
case 0x08 :
cd_media_cd_rom = 1 ;
break ;
case 0x09 :
cd_media_cd_r = 1 ;
break ;
case 0x0a :
cd_media_cd_rw = 1 ;
break ;
case 0x10 :
cd_media_dvd_rom = 1 ;
break ;
case 0x11 :
cd_media_dvd_r = 1 ;
break ;
case 0x12 :
cd_media_dvd_ram = 1 ;
break ;
case 0x13 :
case 0x14 :
cd_media_dvd_rw = 1 ;
break ;
case 0x1B :
cd_media_dvd_plus_r = 1 ;
break ;
case 0x1A :
cd_media_dvd_plus_rw = 1 ;
break ;
case 0x2A :
cd_media_dvd_plus_rw_dl = 1 ;
break ;
case 0x2B :
cd_media_dvd_plus_r_dl = 1 ;
break ;
case 0x40 :
cd_media_bd = 1 ;
break ;
case 0x41 :
case 0x42 :
cd_media_bd_r = 1 ;
break ;
case 0x43 :
cd_media_bd_re = 1 ;
break ;
case 0x50 :
cd_media_hddvd = 1 ;
break ;
case 0x51 :
cd_media_hddvd_r = 1 ;
break ;
case 0x52 :
cd_media_hddvd_rw = 1 ;
break ;
default :
break ;
}
return 0 ;
}
2008-09-06 17:45:31 +04:00
static int cd_media_info ( struct udev * udev , int fd )
2008-04-10 01:17:39 +04:00
{
struct scsi_cmd sc ;
unsigned char header [ 32 ] ;
static const char * media_status [ ] = {
" blank " ,
" appendable " ,
" complete " ,
" other "
} ;
int err ;
2008-09-06 17:45:31 +04:00
scsi_cmd_set ( udev , & sc , 0 , 0x51 ) ;
scsi_cmd_set ( udev , & sc , 8 , sizeof ( header ) ) ;
scsi_cmd_set ( udev , & sc , 9 , 0 ) ;
err = scsi_cmd_run ( udev , & sc , fd , header , sizeof ( header ) ) ;
2008-04-10 01:17:39 +04:00
if ( ( err < 0 ) ) {
2008-09-06 17:45:31 +04:00
info_scsi_cmd_err ( udev , " READ DISC INFORMATION " , err ) ;
2008-04-10 01:17:39 +04:00
return - 1 ;
} ;
2008-09-06 17:45:31 +04:00
info ( udev , " disk type %02x \n " , header [ 8 ] ) ;
2008-04-10 01:17:39 +04:00
2009-05-26 02:50:45 +04:00
/* exclude plain CDROM, some fake cdroms return 0 for "blank" media here */
if ( ! cd_media_cd_rom & & ( header [ 2 ] & 3 ) < 4 )
2008-04-10 01:17:39 +04:00
cd_media_state = media_status [ header [ 2 ] & 3 ] ;
2009-05-26 02:50:45 +04:00
2008-04-10 01:17:39 +04:00
if ( ( header [ 2 ] & 3 ) ! = 2 )
cd_media_session_next = header [ 10 ] < < 8 | header [ 5 ] ;
cd_media_session_count = header [ 9 ] < < 8 | header [ 4 ] ;
cd_media_track_count = header [ 11 ] < < 8 | header [ 6 ] ;
return 0 ;
}
2008-09-06 17:45:31 +04:00
static int cd_media_toc ( struct udev * udev , int fd )
2008-04-10 01:17:39 +04:00
{
struct scsi_cmd sc ;
unsigned char header [ 12 ] ;
unsigned char toc [ 2048 ] ;
unsigned int len , i ;
unsigned char * p ;
int err ;
2008-09-06 17:45:31 +04:00
scsi_cmd_set ( udev , & sc , 0 , 0x43 ) ;
scsi_cmd_set ( udev , & sc , 6 , 1 ) ;
scsi_cmd_set ( udev , & sc , 8 , sizeof ( header ) ) ;
scsi_cmd_set ( udev , & sc , 9 , 0 ) ;
err = scsi_cmd_run ( udev , & sc , fd , header , sizeof ( header ) ) ;
2008-04-10 01:17:39 +04:00
if ( ( err < 0 ) ) {
2008-09-06 17:45:31 +04:00
info_scsi_cmd_err ( udev , " READ TOC " , err ) ;
2008-04-10 01:17:39 +04:00
return - 1 ;
}
len = ( header [ 0 ] < < 8 | header [ 1 ] ) + 2 ;
2008-09-06 17:45:31 +04:00
info ( udev , " READ TOC: len: %d \n " , len ) ;
2008-04-10 01:17:39 +04:00
if ( len > sizeof ( toc ) )
return - 1 ;
2008-06-12 09:20:14 +04:00
if ( len < 2 )
2008-05-14 18:03:49 +04:00
return - 1 ;
2008-04-10 01:17:39 +04:00
2008-06-12 09:20:14 +04:00
/* empty media has no tracks */
if ( len < 8 )
return 0 ;
2008-09-06 17:45:31 +04:00
scsi_cmd_set ( udev , & sc , 0 , 0x43 ) ;
scsi_cmd_set ( udev , & sc , 6 , header [ 2 ] ) ; /* First Track/Session Number */
scsi_cmd_set ( udev , & sc , 7 , len > > 8 ) ;
scsi_cmd_set ( udev , & sc , 8 , len ) ;
scsi_cmd_set ( udev , & sc , 9 , 0 ) ;
err = scsi_cmd_run ( udev , & sc , fd , toc , len ) ;
2008-04-10 01:17:39 +04:00
if ( ( err < 0 ) ) {
2008-09-06 17:45:31 +04:00
info_scsi_cmd_err ( udev , " READ TOC (tracks) " , err ) ;
2008-04-10 01:17:39 +04:00
return - 1 ;
}
for ( p = toc + 4 , i = 4 ; i < len - 8 ; i + = 8 , p + = 8 ) {
unsigned int block ;
2008-06-12 01:24:13 +04:00
unsigned int is_data_track ;
is_data_track = ( p [ 1 ] & 0x04 ) ! = 0 ;
2008-04-10 01:17:39 +04:00
block = p [ 4 ] < < 24 | p [ 5 ] < < 16 | p [ 6 ] < < 8 | p [ 7 ] ;
2008-09-06 17:45:31 +04:00
info ( udev , " track=%u info=0x%x(%s) start_block=%u \n " ,
2008-06-12 01:24:13 +04:00
p [ 2 ] , p [ 1 ] & 0x0f , is_data_track ? " data " : " audio " , block ) ;
if ( is_data_track )
cd_media_track_count_data + + ;
else
cd_media_track_count_audio + + ;
2008-04-10 01:17:39 +04:00
}
2008-09-06 17:45:31 +04:00
scsi_cmd_set ( udev , & sc , 0 , 0x43 ) ;
scsi_cmd_set ( udev , & sc , 2 , 1 ) ; /* Session Info */
scsi_cmd_set ( udev , & sc , 8 , 12 ) ;
scsi_cmd_set ( udev , & sc , 9 , 0 ) ;
err = scsi_cmd_run ( udev , & sc , fd , header , sizeof ( header ) ) ;
2008-04-10 01:17:39 +04:00
if ( ( err < 0 ) ) {
2008-09-06 17:45:31 +04:00
info_scsi_cmd_err ( udev , " READ TOC (multi session) " , err ) ;
2008-04-10 01:17:39 +04:00
return - 1 ;
}
len = header [ 4 + 4 ] < < 24 | header [ 4 + 5 ] < < 16 | header [ 4 + 6 ] < < 8 | header [ 4 + 7 ] ;
2008-09-06 17:45:31 +04:00
info ( udev , " last track %u starts at block %u \n " , header [ 4 + 2 ] , len ) ;
2008-04-10 01:17:39 +04:00
cd_media_session_last_offset = ( unsigned long long int ) len * 2048 ;
return 0 ;
}
2005-08-12 00:59:21 +04:00
int main ( int argc , char * argv [ ] )
{
2008-09-06 17:45:31 +04:00
struct udev * udev ;
2008-04-10 01:17:39 +04:00
static const struct option options [ ] = {
2008-10-02 18:49:05 +04:00
{ " export " , no_argument , NULL , ' x ' } ,
{ " debug " , no_argument , NULL , ' d ' } ,
{ " help " , no_argument , NULL , ' h ' } ,
2008-04-10 01:17:39 +04:00
{ }
} ;
2005-08-12 00:59:21 +04:00
const char * node = NULL ;
int export = 0 ;
2008-04-10 01:17:39 +04:00
int fd = - 1 ;
2005-08-12 00:59:21 +04:00
int rc = 0 ;
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 ( " cdrom_id " ) ;
2008-09-06 17:45:31 +04:00
udev_set_log_fn ( udev , log_fn ) ;
2005-08-12 00:59:21 +04:00
2008-04-10 01:17:39 +04:00
while ( 1 ) {
int option ;
2005-08-12 00:59:21 +04:00
2008-04-10 01:17:39 +04:00
option = getopt_long ( argc , argv , " dxh " , options , NULL ) ;
if ( option = = - 1 )
break ;
switch ( option ) {
case ' d ' :
debug = 1 ;
2008-09-06 17:45:31 +04:00
if ( udev_get_log_priority ( udev ) < LOG_INFO )
udev_set_log_priority ( udev , LOG_INFO ) ;
2008-04-10 01:17:39 +04:00
break ;
case ' x ' :
2005-08-12 00:59:21 +04:00
export = 1 ;
2008-04-10 01:17:39 +04:00
break ;
case ' h ' :
printf ( " Usage: cdrom_id [options] <device> \n "
2008-04-21 19:41:39 +04:00
" --export export key/value pairs \n "
" --debug debug to stderr \n "
" --help print this help text \n \n " ) ;
2008-04-10 01:17:39 +04:00
goto exit ;
default :
rc = 1 ;
goto exit ;
}
2005-08-12 00:59:21 +04:00
}
2008-04-10 01:17:39 +04:00
node = argv [ optind ] ;
2005-08-12 00:59:21 +04:00
if ( ! node ) {
2008-09-06 17:45:31 +04:00
err ( udev , " no device \n " ) ;
2008-04-10 01:17:39 +04:00
fprintf ( stderr , " no device \n " ) ;
2005-08-12 00:59:21 +04:00
rc = 1 ;
goto exit ;
}
2010-04-07 11:24:25 +04:00
if ( is_mounted ( node ) ) {
fd = open ( node , O_RDONLY | O_NONBLOCK ) ;
} else {
int cnt ;
struct timespec duration ;
srand ( ( unsigned int ) getpid ( ) ) ;
for ( cnt = 40 ; cnt > 0 ; cnt - - ) {
fd = open ( node , O_RDONLY | O_NONBLOCK | O_EXCL ) ;
if ( fd > = 0 | | errno ! = EBUSY )
break ;
duration . tv_sec = 0 ;
duration . tv_nsec = ( 100 * 1000 * 1000 ) + ( rand ( ) % 100 * 1000 * 1000 ) ;
nanosleep ( & duration , NULL ) ;
}
}
2005-08-12 00:59:21 +04:00
if ( fd < 0 ) {
2008-09-06 17:45:31 +04:00
info ( udev , " unable to open '%s' \n " , node ) ;
2009-05-29 15:21:38 +04:00
fprintf ( stderr , " unable to open '%s' \n " , node ) ;
2005-08-12 00:59:21 +04:00
rc = 1 ;
goto exit ;
}
2008-09-06 17:45:31 +04:00
info ( udev , " probing: '%s' \n " , node ) ;
2008-04-10 01:17:39 +04:00
/* same data as original cdrom_id */
2008-09-06 17:45:31 +04:00
if ( cd_capability_compat ( udev , fd ) < 0 ) {
2008-04-10 01:17:39 +04:00
rc = 1 ;
goto exit ;
}
2005-08-12 00:59:21 +04:00
2009-11-10 20:32:38 +03:00
/* check for media - don't bail if there's no media as we still need to
* to read profiles */
cd_media_compat ( udev , fd ) ;
2009-04-23 17:04:16 +04:00
/* check if drive talks MMC */
2009-04-17 02:29:56 +04:00
if ( cd_inquiry ( udev , fd ) < 0 )
goto print ;
2005-08-12 00:59:21 +04:00
2008-04-10 01:17:39 +04:00
/* read drive and possibly current profile */
2008-09-06 17:45:31 +04:00
if ( cd_profiles ( udev , fd ) < 0 )
2008-04-10 01:17:39 +04:00
goto print ;
/* get session/track info */
2008-09-06 17:45:31 +04:00
if ( cd_media_toc ( udev , fd ) < 0 )
2008-04-10 01:17:39 +04:00
goto print ;
2005-08-12 00:59:21 +04:00
2008-04-10 01:17:39 +04:00
/* get writable media state */
2008-09-06 17:45:31 +04:00
if ( cd_media_info ( udev , fd ) < 0 )
2008-04-10 01:17:39 +04:00
goto print ;
print :
printf ( " ID_CDROM=1 \n " ) ;
if ( cd_cd_rom )
printf ( " ID_CDROM_CD=1 \n " ) ;
if ( cd_cd_r )
2005-08-12 01:04:24 +04:00
printf ( " ID_CDROM_CD_R=1 \n " ) ;
2008-04-10 01:17:39 +04:00
if ( cd_cd_rw )
2005-08-12 01:04:24 +04:00
printf ( " ID_CDROM_CD_RW=1 \n " ) ;
2008-04-10 01:17:39 +04:00
if ( cd_dvd_rom )
2005-08-12 01:04:24 +04:00
printf ( " ID_CDROM_DVD=1 \n " ) ;
2008-04-10 01:17:39 +04:00
if ( cd_dvd_r )
2005-08-12 01:04:24 +04:00
printf ( " ID_CDROM_DVD_R=1 \n " ) ;
2008-04-10 01:17:39 +04:00
if ( cd_dvd_rw )
printf ( " ID_CDROM_DVD_RW=1 \n " ) ;
if ( cd_dvd_ram )
2005-08-12 01:04:24 +04:00
printf ( " ID_CDROM_DVD_RAM=1 \n " ) ;
2008-04-10 01:17:39 +04:00
if ( cd_dvd_plus_r )
printf ( " ID_CDROM_DVD_PLUS_R=1 \n " ) ;
if ( cd_dvd_plus_rw )
printf ( " ID_CDROM_DVD_PLUS_RW=1 \n " ) ;
if ( cd_dvd_plus_r_dl )
printf ( " ID_CDROM_DVD_PLUS_R_DL=1 \n " ) ;
if ( cd_dvd_plus_rw_dl )
printf ( " ID_CDROM_DVD_PLUS_RW_DL=1 \n " ) ;
if ( cd_bd )
printf ( " ID_CDROM_BD=1 \n " ) ;
if ( cd_bd_r )
printf ( " ID_CDROM_BD_R=1 \n " ) ;
if ( cd_bd_re )
printf ( " ID_CDROM_BD_RE=1 \n " ) ;
if ( cd_hddvd )
printf ( " ID_CDROM_HDDVD=1 \n " ) ;
if ( cd_hddvd_r )
printf ( " ID_CDROM_HDDVD_R=1 \n " ) ;
if ( cd_hddvd_rw )
printf ( " ID_CDROM_HDDVD_RW=1 \n " ) ;
if ( cd_mo )
printf ( " ID_CDROM_MO=1 \n " ) ;
if ( cd_mrw )
2005-08-12 01:04:24 +04:00
printf ( " ID_CDROM_MRW=1 \n " ) ;
2008-04-10 01:17:39 +04:00
if ( cd_mrw_w )
2005-08-12 01:04:24 +04:00
printf ( " ID_CDROM_MRW_W=1 \n " ) ;
2005-08-12 01:38:33 +04:00
2009-04-21 05:27:14 +04:00
if ( cd_media )
printf ( " ID_CDROM_MEDIA=1 \n " ) ;
2008-04-10 01:17:39 +04:00
if ( cd_media_mo )
printf ( " ID_CDROM_MEDIA_MO=1 \n " ) ;
if ( cd_media_mrw )
printf ( " ID_CDROM_MEDIA_MRW=1 \n " ) ;
if ( cd_media_mrw_w )
printf ( " ID_CDROM_MEDIA_MRW_W=1 \n " ) ;
if ( cd_media_cd_rom )
printf ( " ID_CDROM_MEDIA_CD=1 \n " ) ;
if ( cd_media_cd_r )
printf ( " ID_CDROM_MEDIA_CD_R=1 \n " ) ;
if ( cd_media_cd_rw )
printf ( " ID_CDROM_MEDIA_CD_RW=1 \n " ) ;
if ( cd_media_dvd_rom )
printf ( " ID_CDROM_MEDIA_DVD=1 \n " ) ;
if ( cd_media_dvd_r )
printf ( " ID_CDROM_MEDIA_DVD_R=1 \n " ) ;
if ( cd_media_dvd_ram )
printf ( " ID_CDROM_MEDIA_DVD_RAM=1 \n " ) ;
if ( cd_media_dvd_rw )
printf ( " ID_CDROM_MEDIA_DVD_RW=1 \n " ) ;
if ( cd_media_dvd_plus_r )
printf ( " ID_CDROM_MEDIA_DVD_PLUS_R=1 \n " ) ;
if ( cd_media_dvd_plus_rw )
printf ( " ID_CDROM_MEDIA_DVD_PLUS_RW=1 \n " ) ;
if ( cd_media_dvd_plus_rw_dl )
printf ( " ID_CDROM_MEDIA_DVD_PLUS_RW_DL=1 \n " ) ;
if ( cd_media_dvd_plus_r_dl )
printf ( " ID_CDROM_MEDIA_DVD_PLUS_R_DL=1 \n " ) ;
if ( cd_media_bd )
printf ( " ID_CDROM_MEDIA_BD=1 \n " ) ;
if ( cd_media_bd_r )
printf ( " ID_CDROM_MEDIA_BD_R=1 \n " ) ;
if ( cd_media_bd_re )
printf ( " ID_CDROM_MEDIA_BD_RE=1 \n " ) ;
if ( cd_media_hddvd )
printf ( " ID_CDROM_MEDIA_HDDVD=1 \n " ) ;
if ( cd_media_hddvd_r )
printf ( " ID_CDROM_MEDIA_HDDVD_R=1 \n " ) ;
if ( cd_media_hddvd_rw )
printf ( " ID_CDROM_MEDIA_HDDVD_RW=1 \n " ) ;
if ( cd_media_state ! = NULL )
printf ( " ID_CDROM_MEDIA_STATE=%s \n " , cd_media_state ) ;
if ( cd_media_session_next > 0 )
printf ( " ID_CDROM_MEDIA_SESSION_NEXT=%d \n " , cd_media_session_next ) ;
if ( cd_media_session_count > 0 )
printf ( " ID_CDROM_MEDIA_SESSION_COUNT=%d \n " , cd_media_session_count ) ;
if ( cd_media_track_count > 0 )
printf ( " ID_CDROM_MEDIA_TRACK_COUNT=%d \n " , cd_media_track_count ) ;
2008-08-22 12:04:55 +04:00
if ( cd_media_track_count_audio > 0 )
2008-06-12 01:24:13 +04:00
printf ( " ID_CDROM_MEDIA_TRACK_COUNT_AUDIO=%d \n " , cd_media_track_count_audio ) ;
2008-08-22 12:04:55 +04:00
if ( cd_media_track_count_data > 0 )
2008-06-12 01:24:13 +04:00
printf ( " ID_CDROM_MEDIA_TRACK_COUNT_DATA=%d \n " , cd_media_track_count_data ) ;
2008-08-22 12:04:55 +04:00
if ( cd_media_session_last_offset > 0 )
2008-04-10 01:17:39 +04:00
printf ( " ID_CDROM_MEDIA_SESSION_LAST_OFFSET=%llu \n " , cd_media_session_last_offset ) ;
2005-08-12 00:59:21 +04:00
exit :
2008-04-10 01:17:39 +04:00
if ( fd > = 0 )
close ( fd ) ;
2008-09-06 17:45:31 +04:00
udev_unref ( udev ) ;
2009-06-10 00:47:48 +04:00
udev_log_close ( ) ;
2005-08-12 00:59:21 +04:00
return rc ;
}
2008-04-10 01:17:39 +04:00