1 /*
2   Copyright (C) 2001 Herbert Valerio Riedel <hvr@gnu.org>
3   Copyright (C) 2002-2006, 2008-2013, 2017 Rocky Bernstein
4   <rocky@gnu.org>
5 
6   This program is free software: you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation, either version 3 of the License, or
9   (at your option) any later version.
10 
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15 
16   You should have received a copy of the GNU General Public License
17   along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 /* This file contains Linux-specific code and implements low-level
21    control of the CD drive.
22 */
23 
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 # define __CDIO_CONFIG_H__ 1
27 #endif
28 
29 #ifdef HAVE_STRING_H
30 #include <string.h>
31 #endif
32 
33 #include <cdio/sector.h>
34 #include <cdio/util.h>
35 #include <cdio/types.h>
36 #include <cdio/mmc_cmds.h>
37 #include <cdio/audio.h>
38 #include <cdio/cdtext.h>
39 #include "cdio_assert.h"
40 #include "cdio_private.h"
41 
42 #ifdef HAVE_LINUX_CDROM
43 
44 #include <sys/types.h>
45 #include <sys/wait.h>
46 #include <limits.h>
47 
48 #if defined(HAVE_LINUX_VERSION_H)
49 # include <linux/version.h>
50 # if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,16)
51 #   define __CDIO_LINUXCD_BUILD
52 # else
53 #  error "You need a kernel greater than 2.2.16 to have CDROM support"
54 # endif
55 #else
56 #  error "You need <linux/version.h> to have CDROM support"
57 #endif
58 
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <errno.h>
62 #include <unistd.h>
63 #include <fcntl.h>
64 #include <mntent.h>
65 
66 #include <linux/cdrom.h>
67 #include <scsi/scsi.h>
68 #include <scsi/sg.h>
69 #include <scsi/scsi_ioctl.h>
70 #include <sys/mount.h>
71 
72 #include <sys/stat.h>
73 #include <sys/types.h>
74 #include <sys/ioctl.h>
75 
76 #ifndef PATH_MAX
77 #define PATH_MAX 4096
78 #endif
79 
80 typedef enum {
81   _AM_NONE,
82   _AM_IOCTL,
83   _AM_READ_CD,
84   _AM_READ_10,
85   _AM_MMC_RDWR,
86   _AM_MMC_RDWR_EXCL,
87 } access_mode_t;
88 
89 typedef struct {
90   /* Things common to all drivers like this.
91      This must be first. */
92   generic_img_private_t gen;
93 
94   access_mode_t access_mode;
95 
96   /* Some of the more OS specific things. */
97   /* Entry info for each track, add 1 for leadout. */
98   struct cdrom_tocentry  tocent[CDIO_CD_MAX_TRACKS+1];
99 
100   struct cdrom_tochdr    tochdr;
101 
102 } _img_private_t;
103 
104 /* Some ioctl() errno values which occur when the tray is empty */
105 #define ERRNO_TRAYEMPTY(errno)  \
106         ((errno == EIO) || (errno == ENOENT) || (errno == EINVAL))
107 
108 /**** prototypes for static functions ****/
109 static bool is_cdrom_linux(const char *drive, char *mnttype);
110 static bool read_toc_linux (void *p_user_data);
111 static driver_return_code_t
112 run_mmc_cmd_linux( void *p_user_data,
113                    unsigned int i_timeout,
114                    unsigned int i_cdb,
115                    const mmc_cdb_t *p_cdb,
116                    cdio_mmc_direction_t e_direction,
117                    unsigned int i_buf,
118                    /*in/out*/ void *p_buf );
119 
120 static access_mode_t
str_to_access_mode_linux(const char * psz_access_mode)121 str_to_access_mode_linux(const char *psz_access_mode)
122 {
123   const access_mode_t default_access_mode = _AM_IOCTL;
124 
125   if (NULL==psz_access_mode) return default_access_mode;
126 
127   if (!strcmp(psz_access_mode, "IOCTL"))
128     return _AM_IOCTL;
129   else if (!strcmp(psz_access_mode, "READ_CD"))
130     return _AM_READ_CD;
131   else if (!strcmp(psz_access_mode, "READ_10"))
132     return _AM_READ_10;
133   else if (!strcmp(psz_access_mode, "MMC_RDWR"))
134     return _AM_MMC_RDWR;
135   else if (!strcmp(psz_access_mode, "MMC_RDWR_EXCL"))
136     return _AM_MMC_RDWR_EXCL;
137   else {
138     cdio_warn ("unknown access type: %s. Default IOCTL used.",
139                psz_access_mode);
140     return default_access_mode;
141   }
142 }
143 
144 static char *
check_mounts_linux(const char * mtab)145 check_mounts_linux(const char *mtab)
146 {
147   FILE *mntfp;
148   struct mntent *mntent;
149 
150   mntfp = setmntent(mtab, "r");
151   if ( mntfp != NULL ) {
152     char *tmp;
153     char *mnt_type;
154     char *mnt_dev;
155     unsigned int i_mnt_type;
156     unsigned int i_mnt_dev;
157 
158     while ( (mntent=getmntent(mntfp)) != NULL ) {
159       i_mnt_type = strlen(mntent->mnt_type) + 1;
160       mnt_type = calloc(1, i_mnt_type);
161       if (mnt_type == NULL)
162         continue;  /* maybe you'll get lucky next time. */
163 
164       i_mnt_dev = strlen(mntent->mnt_fsname) + 1;
165       mnt_dev = calloc(1, i_mnt_dev);
166       if (mnt_dev == NULL) {
167         free(mnt_type);
168         continue;
169       }
170 
171       strncpy(mnt_type, mntent->mnt_type, i_mnt_type);
172       strncpy(mnt_dev, mntent->mnt_fsname, i_mnt_dev);
173 
174       /* Handle "supermount" filesystem mounts */
175       if ( strcmp(mnt_type, "supermount") == 0 ) {
176         tmp = strstr(mntent->mnt_opts, "fs=");
177         if ( tmp ) {
178           free(mnt_type);
179           mnt_type = strdup(tmp + strlen("fs="));
180           if ( mnt_type ) {
181             tmp = strchr(mnt_type, ',');
182             if ( tmp ) {
183               *tmp = '\0';
184             }
185           }
186         }
187         tmp = strstr(mntent->mnt_opts, "dev=");
188         if ( tmp ) {
189           free(mnt_dev);
190           mnt_dev = strdup(tmp + strlen("dev="));
191           if ( mnt_dev ) {
192             tmp = strchr(mnt_dev, ',');
193             if ( tmp ) {
194               *tmp = '\0';
195             }
196           }
197         }
198       }
199       if ( mnt_type && mnt_dev ) {
200 	if ( strcmp(mnt_type, "iso9660") == 0 ) {
201 	  if (is_cdrom_linux(mnt_dev, mnt_type) > 0) {
202 	    free(mnt_type);
203 	    endmntent(mntfp);
204 	    return mnt_dev;
205 	  }
206         }
207       }
208       free(mnt_dev);
209       free(mnt_type);
210     }
211     endmntent(mntfp);
212   }
213   return NULL;
214 }
215 
216 /*!
217   Get the volume of an audio CD.
218 
219   @param p_cdio the CD object to be acted upon.
220 */
221 static driver_return_code_t
audio_get_volume_linux(void * p_user_data,cdio_audio_volume_t * p_volume)222 audio_get_volume_linux (void *p_user_data,
223                         /*out*/ cdio_audio_volume_t *p_volume)
224 {
225 
226   const _img_private_t *p_env = p_user_data;
227   return ioctl(p_env->gen.fd, CDROMVOLREAD, p_volume);
228 }
229 
230 /*!
231   Pause playing CD through analog output
232 
233   @param p_cdio the CD object to be acted upon.
234 */
235 static driver_return_code_t
audio_pause_linux(void * p_user_data)236 audio_pause_linux (void *p_user_data)
237 {
238 
239   const _img_private_t *p_env = p_user_data;
240   return ioctl(p_env->gen.fd, CDROMPAUSE);
241 }
242 
243 /*!
244   Playing starting at given MSF through analog output
245 
246   @param p_cdio the CD object to be acted upon.
247 */
248 static driver_return_code_t
audio_play_msf_linux(void * p_user_data,msf_t * p_start_msf,msf_t * p_end_msf)249 audio_play_msf_linux (void *p_user_data, msf_t *p_start_msf, msf_t *p_end_msf)
250 {
251 
252   const _img_private_t *p_env = p_user_data;
253   struct cdrom_msf cdrom_msf;
254 
255   cdrom_msf.cdmsf_min0   = cdio_from_bcd8(p_start_msf->m);
256   cdrom_msf.cdmsf_sec0   = cdio_from_bcd8(p_start_msf->s);
257   cdrom_msf.cdmsf_frame0 = cdio_from_bcd8(p_start_msf->f);
258 
259   cdrom_msf.cdmsf_min1   = cdio_from_bcd8(p_end_msf->m);
260   cdrom_msf.cdmsf_sec1   = cdio_from_bcd8(p_end_msf->s);
261   cdrom_msf.cdmsf_frame1 = cdio_from_bcd8(p_end_msf->f);
262 
263   return ioctl(p_env->gen.fd, CDROMPLAYMSF, &cdrom_msf);
264 }
265 
266 /*!
267   Playing CD through analog output at the desired track and index
268 
269   @param p_cdio the CD object to be acted upon.
270   @param p_track_index location to start/end.
271 */
272 static driver_return_code_t
audio_play_track_index_linux(void * p_user_data,cdio_track_index_t * p_track_index)273 audio_play_track_index_linux (void *p_user_data,
274                               cdio_track_index_t *p_track_index)
275 {
276 
277   const _img_private_t *p_env = p_user_data;
278   return ioctl(p_env->gen.fd, CDROMPLAYTRKIND, p_track_index);
279 }
280 
281 /*!
282   Read Audio Subchannel information
283 
284   @param p_user_data the CD object to be acted upon.
285   @param p_subchannel returned information
286 */
287 static driver_return_code_t
audio_read_subchannel_linux(void * p_user_data,cdio_subchannel_t * p_subchannel)288 audio_read_subchannel_linux (void *p_user_data,
289                              /*out*/ cdio_subchannel_t *p_subchannel)
290 {
291 
292   const _img_private_t *p_env = p_user_data;
293   struct cdrom_subchnl subchannel;
294   int   i_rc;
295 
296   subchannel.cdsc_format = CDIO_CDROM_MSF;
297   i_rc = ioctl(p_env->gen.fd, CDROMSUBCHNL, &subchannel);
298   if (0 == i_rc) {
299     p_subchannel->control      = subchannel.cdsc_ctrl;
300     p_subchannel->track        = subchannel.cdsc_trk;
301     p_subchannel->index        = subchannel.cdsc_ind;
302 
303     p_subchannel->abs_addr.m   =
304       cdio_to_bcd8(subchannel.cdsc_absaddr.msf.minute);
305     p_subchannel->abs_addr.s   =
306       cdio_to_bcd8(subchannel.cdsc_absaddr.msf.second);
307     p_subchannel->abs_addr.f   =
308       cdio_to_bcd8(subchannel.cdsc_absaddr.msf.frame);
309     p_subchannel->rel_addr.m   =
310       cdio_to_bcd8(subchannel.cdsc_reladdr.msf.minute);
311     p_subchannel->rel_addr.s   =
312       cdio_to_bcd8(subchannel.cdsc_reladdr.msf.second);
313     p_subchannel->rel_addr.f   =
314       cdio_to_bcd8(subchannel.cdsc_reladdr.msf.frame);
315     p_subchannel->audio_status = subchannel.cdsc_audiostatus;
316 
317     return DRIVER_OP_SUCCESS;
318   } else {
319     cdio_info ("ioctl CDROMSUBCHNL failed: %s\n", strerror(errno));
320     return DRIVER_OP_ERROR;
321   }
322 }
323 
324 /*!
325   Resume playing an audio CD.
326 
327   @param p_cdio the CD object to be acted upon.
328 
329 */
330 static driver_return_code_t
audio_resume_linux(void * p_user_data)331 audio_resume_linux (void *p_user_data)
332 {
333   const _img_private_t *p_env = p_user_data;
334   return ioctl(p_env->gen.fd, CDROMRESUME, 0);
335 }
336 
337 /*!
338   Set the volume of an audio CD.
339 
340   @param p_user_data the CD object to be acted upon.
341 
342 */
343 static driver_return_code_t
audio_set_volume_linux(void * p_user_data,cdio_audio_volume_t * p_volume)344 audio_set_volume_linux (void *p_user_data, cdio_audio_volume_t *p_volume)
345 {
346   const _img_private_t *p_env = p_user_data;
347   return ioctl(p_env->gen.fd, CDROMVOLCTRL, p_volume);
348 }
349 
350 /*!
351   Stop playing an audio CD.
352 
353   @param p_user_data the CD object to be acted upon.
354 
355 */
356 static driver_return_code_t
audio_stop_linux(void * p_user_data)357 audio_stop_linux (void *p_user_data)
358 {
359   const _img_private_t *p_env = p_user_data;
360   return ioctl(p_env->gen.fd, CDROMSTOP);
361 }
362 
363 static bool
is_mmc_supported(void * user_data)364 is_mmc_supported(void *user_data)
365 {
366     _img_private_t *env = user_data;
367     return (_AM_NONE == env->access_mode) ? false : true;
368 }
369 
370 /*!
371   Return the value associated with the key "arg".
372 */
373 static const char *
get_arg_linux(void * env,const char key[])374 get_arg_linux (void *env, const char key[])
375 {
376   _img_private_t *_obj = env;
377 
378   if (!strcmp (key, "source")) {
379     return _obj->gen.source_name;
380   } else if (!strcmp (key, "access-mode")) {
381     switch (_obj->access_mode) {
382     case _AM_IOCTL:
383       return "IOCTL";
384     case _AM_READ_CD:
385       return "READ_CD";
386     case _AM_READ_10:
387       return "READ_10";
388     case _AM_MMC_RDWR:
389       return "MMC_RDWR";
390     case _AM_MMC_RDWR_EXCL:
391       return "MMC_RDWR_EXCL";
392     case _AM_NONE:
393       return "no access method";
394     }
395   } else if (!strcmp (key, "scsi-tuple")) {
396     return _obj->gen.scsi_tuple;
397   } else if (!strcmp (key, "mmc-supported?")) {
398       return is_mmc_supported(env) ? "true" : "false";
399   }
400   return NULL;
401 }
402 
403 #undef USE_LINUX_CAP
404 #ifdef USE_LINUX_CAP
405 /*!
406   Return the the kind of drive capabilities of device.
407 
408   Note: string is malloc'd so caller should free() then returned
409   string when done with it.
410 
411  */
412 static void
get_drive_cap_linux(const void * p_user_data,cdio_drive_read_cap_t * p_read_cap,cdio_drive_write_cap_t * p_write_cap,cdio_drive_misc_cap_t * p_misc_cap)413 get_drive_cap_linux (const void *p_user_data,
414                      /*out*/ cdio_drive_read_cap_t  *p_read_cap,
415                      /*out*/ cdio_drive_write_cap_t *p_write_cap,
416                      /*out*/ cdio_drive_misc_cap_t  *p_misc_cap)
417 {
418   const _img_private_t *p_env = p_user_data;
419   int32_t i_drivetype;
420 
421   i_drivetype = ioctl (p_env->gen.fd, CDROM_GET_CAPABILITY, CDSL_CURRENT);
422 
423   if (i_drivetype < 0) {
424     *p_read_cap  = CDIO_DRIVE_CAP_ERROR;
425     *p_write_cap = CDIO_DRIVE_CAP_ERROR;
426     *p_misc_cap  = CDIO_DRIVE_CAP_ERROR;
427     return;
428   }
429 
430   *p_read_cap  = 0;
431   *p_write_cap = 0;
432   *p_misc_cap  = 0;
433 
434   /* Reader */
435   if (i_drivetype & CDC_PLAY_AUDIO)
436     *p_read_cap  |= CDIO_DRIVE_CAP_READ_AUDIO;
437   if (i_drivetype & CDC_CD_R)
438     *p_read_cap  |= CDIO_DRIVE_CAP_READ_CD_R;
439   if (i_drivetype & CDC_CD_RW)
440     *p_read_cap  |= CDIO_DRIVE_CAP_READ_CD_RW;
441   if (i_drivetype & CDC_DVD)
442     *p_read_cap  |= CDIO_DRIVE_CAP_READ_DVD_ROM;
443 
444   /* Writer */
445   if (i_drivetype & CDC_CD_RW)
446     *p_read_cap  |= CDIO_DRIVE_CAP_WRITE_CD_RW;
447   if (i_drivetype & CDC_DVD_R)
448     *p_read_cap  |= CDIO_DRIVE_CAP_WRITE_DVD_R;
449   if (i_drivetype & CDC_DVD_RAM)
450     *p_read_cap  |= CDIO_DRIVE_CAP_WRITE_DVD_RAM;
451 
452   /* Misc */
453   if (i_drivetype & CDC_CLOSE_TRAY)
454     *p_misc_cap  |= CDIO_DRIVE_CAP_MISC_CLOSE_TRAY;
455   if (i_drivetype & CDC_OPEN_TRAY)
456     *p_misc_cap  |= CDIO_DRIVE_CAP_MISC_EJECT;
457   if (i_drivetype & CDC_LOCK)
458     *p_misc_cap  |= CDIO_DRIVE_CAP_MISC_LOCK;
459   if (i_drivetype & CDC_SELECT_SPEED)
460     *p_misc_cap  |= CDIO_DRIVE_CAP_MISC_SELECT_SPEED;
461   if (i_drivetype & CDC_SELECT_DISC)
462     *p_misc_cap  |= CDIO_DRIVE_CAP_MISC_SELECT_DISC;
463   if (i_drivetype & CDC_MULTI_SESSION)
464     *p_misc_cap  |= CDIO_DRIVE_CAP_MISC_MULTI_SESSION;
465   if (i_drivetype & CDC_MEDIA_CHANGED)
466     *p_misc_cap  |= CDIO_DRIVE_CAP_MISC_MEDIA_CHANGED;
467   if (i_drivetype & CDC_RESET)
468     *p_misc_cap  |= CDIO_DRIVE_CAP_MISC_RESET;
469 }
470 #endif
471 
472 /*! Get the LSN of the first track of the last session of
473   on the CD.
474 
475   @param p_cdio the CD object to be acted upon.
476   @param i_last_session pointer to the session number to be returned.
477 */
478 static driver_return_code_t
get_last_session_linux(void * p_user_data,lsn_t * i_last_session)479 get_last_session_linux (void *p_user_data,
480                         /*out*/ lsn_t *i_last_session)
481 {
482   const _img_private_t *p_env = p_user_data;
483   struct cdrom_multisession ms;
484   int i_rc;
485 
486   ms.addr_format = CDROM_LBA;
487   i_rc = ioctl(p_env->gen.fd, CDROMMULTISESSION, &ms);
488   if (0 == i_rc) {
489     *i_last_session = ms.addr.lba;
490     return DRIVER_OP_SUCCESS;
491   } else {
492     cdio_warn ("ioctl CDROMMULTISESSION failed: %s\n", strerror(errno));
493     return DRIVER_OP_ERROR;
494   }
495 }
496 
497 
498 
499 /*!
500   Find out if media has changed since the last call.
501   @param p_user_data the environment object to be acted upon.
502   @return 1 if media has changed since last call, 0 if not. Error
503   return codes are the same as driver_return_code_t
504 */
505 static int
get_media_changed_linux(const void * p_user_data)506 get_media_changed_linux (const void *p_user_data) {
507   const _img_private_t *p_env = p_user_data;
508   return ioctl(p_env->gen.fd, CDROM_MEDIA_CHANGED, 0);
509 }
510 
511 /*!
512   Return the media catalog number MCN.
513 
514   Note: string is malloc'd so caller should free() then returned
515   string when done with it.
516 
517  */
518 static char *
get_mcn_linux(const void * p_user_data)519 get_mcn_linux (const void *p_user_data) {
520 
521   struct cdrom_mcn mcn;
522   const _img_private_t *p_env = p_user_data;
523   memset(&mcn, 0, sizeof(mcn));
524   if (ioctl(p_env->gen.fd, CDROM_GET_MCN, &mcn) != 0)
525     return NULL;
526   return strdup((char *)mcn.medium_catalog_number);
527 }
528 
529 /*!
530   Return the international standard recording code ISRC.
531 
532   Note: string is malloc'd so caller should free() then returned
533   string when done with it.
534 
535  */
536 static char *
get_track_isrc_linux(const void * p_user_data,track_t i_track)537 get_track_isrc_linux (const void *p_user_data, track_t i_track) {
538 
539   const _img_private_t *p_env = p_user_data;
540   return mmc_get_track_isrc( p_env->gen.cdio, i_track );
541 }
542 
543 /*!
544   Get format of track.
545 */
546 static track_format_t
get_track_format_linux(void * p_user_data,track_t i_track)547 get_track_format_linux(void *p_user_data, track_t i_track)
548 {
549   _img_private_t *p_env = p_user_data;
550 
551   if ( !p_env ) return TRACK_FORMAT_ERROR;
552 
553   if (!p_env->gen.toc_init) read_toc_linux (p_user_data) ;
554 
555   if (i_track > (p_env->gen.i_tracks+p_env->gen.i_first_track)
556       || i_track < p_env->gen.i_first_track)
557     return TRACK_FORMAT_ERROR;
558 
559   i_track -= p_env->gen.i_first_track;
560 
561   /* This is pretty much copied from the "badly broken" cdrom_count_tracks
562      in linux/cdrom.c.
563    */
564   if (p_env->tocent[i_track].cdte_ctrl & CDIO_CDROM_DATA_TRACK) {
565     if (p_env->tocent[i_track].cdte_format == CDIO_CDROM_CDI_TRACK)
566       return TRACK_FORMAT_CDI;
567     else if (p_env->tocent[i_track].cdte_format == CDIO_CDROM_XA_TRACK)
568       return TRACK_FORMAT_XA;
569     else
570       return TRACK_FORMAT_DATA;
571   } else
572     return TRACK_FORMAT_AUDIO;
573 
574 }
575 
576 /*!
577   Return true if we have XA data (green, mode2 form1) or
578   XA data (green, mode2 form2). That is track begins:
579   sync - header - subheader
580   12     4      -  8
581 
582   FIXME: there's gotta be a better design for this and get_track_format?
583 */
584 static bool
get_track_green_linux(void * p_user_data,track_t i_track)585 get_track_green_linux(void *p_user_data, track_t i_track)
586 {
587   _img_private_t *p_env = p_user_data;
588 
589   if (!p_env->gen.toc_init) read_toc_linux (p_user_data) ;
590 
591   if (i_track >= (p_env->gen.i_tracks+p_env->gen.i_first_track)
592       || i_track < p_env->gen.i_first_track)
593     return false;
594 
595   i_track -= p_env->gen.i_first_track;
596 
597   /* FIXME: Dunno if this is the right way, but it's what
598      I was using in cd-info for a while.
599    */
600   return ((p_env->tocent[i_track].cdte_ctrl & 2) != 0);
601 }
602 
603 /*!
604   Return the starting MSF (minutes/secs/frames) for track number
605   track_num in obj.  Track numbers usually start at something
606   greater than 0, usually 1.
607 
608   The "leadout" track is specified either by
609   using i_track LEADOUT_TRACK or the total tracks+1.
610   False is returned if there is no track entry.
611 */
612 static bool
get_track_msf_linux(void * p_user_data,track_t i_track,msf_t * msf)613 get_track_msf_linux(void *p_user_data, track_t i_track, msf_t *msf)
614 {
615   _img_private_t *p_env = p_user_data;
616 
617   if (NULL == msf ||
618       (i_track > CDIO_CD_MAX_TRACKS && i_track != CDIO_CDROM_LEADOUT_TRACK))
619     return false;
620 
621   if (!p_env->gen.toc_init) read_toc_linux (p_user_data) ;
622 
623   if (i_track == CDIO_CDROM_LEADOUT_TRACK)
624     i_track = p_env->gen.i_tracks + p_env->gen.i_first_track;
625 
626   if (i_track > (p_env->gen.i_tracks+p_env->gen.i_first_track)
627       || i_track < p_env->gen.i_first_track) {
628     return false;
629   } else {
630     struct cdrom_msf0  *msf0=
631       &p_env->tocent[i_track-p_env->gen.i_first_track].cdte_addr.msf;
632     msf->m = cdio_to_bcd8(msf0->minute);
633     msf->s = cdio_to_bcd8(msf0->second);
634     msf->f = cdio_to_bcd8(msf0->frame);
635     return true;
636   }
637 }
638 
639 
640 /*!
641   Check, if a device is mounted and return the target (=mountpoint)
642   needed for umounting (idea taken from libunieject).
643  */
644 
is_mounted(const char * device,char * target)645 static int is_mounted (const char * device, char * target) {
646   FILE * fp;
647   char real_device_1[PATH_MAX];
648   char real_device_2[PATH_MAX];
649 
650   char file_device[PATH_MAX];
651   char file_target[PATH_MAX];
652 
653   fp = fopen ( "/proc/mounts", "r");
654   /* Older systems just have /etc/mtab */
655   if(!fp)
656     fp = fopen ( "/etc/mtab", "r");
657 
658   /* Neither /proc/mounts nor /etc/mtab could be opened, give up here */
659   if(!fp) return 0;
660 
661   /* Get real device */
662   if (NULL == cdio_realpath(device, real_device_1)) {
663     cdio_warn("Problems resolving device %s: %s\n", device, strerror(errno));
664   }
665 
666 
667   /* Read entries */
668 
669   while ( fscanf(fp, "%s %s %*s %*s %*d %*d\n", file_device, file_target) != EOF ) {
670       if (NULL == cdio_realpath(file_device, real_device_2)) {
671           cdio_debug("Problems resolving device %s: %s\n",
672                      file_device, strerror(errno));
673       }
674     if(!strcmp(real_device_1, real_device_2)) {
675       strcpy(target, file_target);
676       fclose(fp);
677       return 1;
678     }
679 
680   }
681   fclose(fp);
682   return 0;
683 }
684 
685 /*!
686   Umount a filesystem specified by it's mountpoint. We must do this
687   by forking and calling the umount command, because the raw umount
688   (or umount2) system calls will *always* trigger an EPERM even if
689   we are allowed to umount the filesystem. The umount command is
690   suid root.
691 
692   Code here is inspired by the standard linux eject command by
693   Jeff Tranter and Frank Lichtenheld.
694  */
695 
do_umount(char * target)696 static int do_umount(char * target) {
697   int status;
698 
699   switch (fork()) {
700   case 0: /* child */
701     execlp("pumount", "pumount", target, NULL);
702     execlp("umount", "umount", target, NULL);
703     return -1;
704   case -1:
705     return -1;
706   default: /* parent */
707     wait(&status);
708     if (WIFEXITED(status) == 0) {
709       return -1;
710     }
711     if (WEXITSTATUS(status) != 0) {
712       return -1;
713     }
714     break;
715   }
716   return 0;
717 }
718 
719 
720 /*!
721   Eject media in CD-ROM drive. Return DRIVER_OP_SUCCESS if successful,
722   DRIVER_OP_ERROR on error.
723  */
724 
725 static driver_return_code_t
eject_media_linux(void * p_user_data)726 eject_media_linux (void *p_user_data) {
727 
728   _img_private_t *p_env = p_user_data;
729   driver_return_code_t ret=DRIVER_OP_SUCCESS;
730   int status;
731   bool was_open = false;
732   char mount_target[PATH_MAX];
733 
734   /* Make sure the device is opened in read/write mode. */
735   if ( p_env->gen.fd >= 0 ) {
736     close(p_env->gen.fd);
737     was_open = true;
738   }
739 
740   p_env->gen.fd = open (p_env->gen.source_name, O_RDWR|O_NONBLOCK);
741 
742   if ( p_env->gen.fd <= -1 ) return DRIVER_OP_ERROR;
743 
744   if ((status = ioctl(p_env->gen.fd, CDROM_DRIVE_STATUS, CDSL_CURRENT)) > 0) {
745     switch(status) {
746     case CDS_TRAY_OPEN:
747       cdio_info ("Drive status reports that tray is open\n");
748       break;
749     default:
750       cdio_info ("Unknown state of CD-ROM (%d)\n", status);
751       /* Fall through */
752     case CDS_DISC_OK:
753       /* Some systems automount the drive, so we must umount it.
754          We check if the drive is actually mounted */
755       if(is_mounted (p_env->gen.source_name, mount_target)) {
756         /* Try to umount the drive */
757         if(do_umount(mount_target)) {
758           cdio_log(CDIO_LOG_WARN, "Could not umount %s\n",
759                    p_env->gen.source_name);
760           ret=DRIVER_OP_ERROR;
761           break;
762         }
763         /* For some reason, we must close and reopen the device after
764            it got umounted (at least the commandline eject program
765            opens the device just after umounting it) */
766         close(p_env->gen.fd);
767         p_env->gen.fd = open (p_env->gen.source_name, O_RDWR|O_NONBLOCK);
768       }
769 
770       if((ret = ioctl(p_env->gen.fd, CDROMEJECT)) != 0) {
771         int eject_error = errno;
772         /* Try ejecting the MMC way... */
773         ret = mmc_eject_media(p_env->gen.cdio);
774         if (0 != ret) {
775           cdio_info("ioctl CDROMEJECT and MMC eject failed: %s",
776                     strerror(eject_error));
777           ret = DRIVER_OP_ERROR;
778         }
779       }
780       /* force kernel to reread partition table when new disc inserted */
781       if (0 != ioctl(p_env->gen.fd, BLKRRPART)) {
782         cdio_info ("BLKRRPART request failed: %s\n", strerror(errno));
783       }
784       break;
785     }
786   } else {
787     cdio_warn ("CDROM_DRIVE_STATUS failed: %s\n", strerror(errno));
788     ret=DRIVER_OP_ERROR;
789   }
790   if(!was_open) {
791     close(p_env->gen.fd);
792     p_env->gen.fd = -1;
793   }
794   return ret;
795 }
796 
797 /*!
798   Get disc type associated with cd object.
799 */
800 static discmode_t
dvd_discmode_linux(_img_private_t * p_env)801 dvd_discmode_linux (_img_private_t *p_env)
802 {
803   discmode_t discmode=CDIO_DISC_MODE_NO_INFO;
804 
805   /* See if this is a DVD. */
806   cdio_dvd_struct_t dvd;  /* DVD READ STRUCT for layer 0. */
807 
808   memset(&dvd, 0, sizeof(dvd));
809 
810   dvd.physical.type = CDIO_DVD_STRUCT_PHYSICAL;
811   dvd.physical.layer_num = 0;
812   if (0 == ioctl (p_env->gen.fd, DVD_READ_STRUCT, &dvd)) {
813     switch(dvd.physical.layer[0].book_type) {
814     case CDIO_DVD_BOOK_DVD_ROM:  return CDIO_DISC_MODE_DVD_ROM;
815     case CDIO_DVD_BOOK_DVD_RAM:  return CDIO_DISC_MODE_DVD_RAM;
816     case CDIO_DVD_BOOK_DVD_R:    return CDIO_DISC_MODE_DVD_R;
817     case CDIO_DVD_BOOK_DVD_RW:   return CDIO_DISC_MODE_DVD_RW;
818     case CDIO_DVD_BOOK_DVD_PR:   return CDIO_DISC_MODE_DVD_PR;
819     case CDIO_DVD_BOOK_DVD_PRW:  return CDIO_DISC_MODE_DVD_PRW;
820     default:                     return CDIO_DISC_MODE_DVD_OTHER;
821     }
822   }
823   return discmode;
824 }
825 
826 /*!
827   Get disc type associated with the cd object.
828 */
829 static discmode_t
get_discmode_linux(void * p_user_data)830 get_discmode_linux (void *p_user_data)
831 {
832   _img_private_t *p_env = p_user_data;
833 
834   discmode_t discmode;
835 
836   if (!p_env) return CDIO_DISC_MODE_ERROR;
837 
838   /* Try DVD types first. See note below. */
839   discmode = dvd_discmode_linux(p_env);
840 
841   if (CDIO_DISC_MODE_NO_INFO != discmode) return discmode;
842   /*
843      Justin B Ruggles <jruggle@earthlink.net> reports that the
844      GNU/Linux ioctl(.., CDROM_DISC_STATUS) does not return "CD DATA
845      Form 2" for SVCD's even though they are are form 2.  In
846      mmc_get_discmode we issue a SCSI MMC-2 TOC command first to
847      try get more accurate information. But we took care above *not*
848      to issue a FULL TOC on DVD media.
849   */
850   discmode = mmc_get_discmode(p_env->gen.cdio);
851   if (CDIO_DISC_MODE_NO_INFO != discmode)
852     return discmode;
853   else {
854     int32_t i_discmode = ioctl (p_env->gen.fd, CDROM_DISC_STATUS);
855 
856     if (i_discmode < 0) return CDIO_DISC_MODE_ERROR;
857 
858     switch(i_discmode) {
859     case CDS_AUDIO:
860       return CDIO_DISC_MODE_CD_DA;
861     case CDS_DATA_1:
862     case CDS_DATA_2: /* Actually, recent GNU/Linux kernels don't return
863                         CDS_DATA_2, but just in case. */
864       return CDIO_DISC_MODE_CD_DATA;
865     case CDS_MIXED:
866       return CDIO_DISC_MODE_CD_MIXED;
867     case CDS_XA_2_1:
868     case CDS_XA_2_2:
869       return CDIO_DISC_MODE_CD_XA;
870     case CDS_NO_INFO:
871       return CDIO_DISC_MODE_NO_INFO;
872     default:
873       return CDIO_DISC_MODE_ERROR;
874     }
875   }
876 }
877 
878 /* Check a drive to see if it is a CD-ROM
879    Return 1 if a CD-ROM. 0 if it exists but isn't a CD-ROM drive
880    and -1 if no device exists .
881 */
882 static bool
is_cdrom_linux(const char * drive,char * mnttype)883 is_cdrom_linux(const char *drive, char *mnttype)
884 {
885   bool is_cd=false;
886   int cdfd;
887 
888   /* If it doesn't exist, return -1 */
889   if ( !cdio_is_device_quiet_generic(drive) ) {
890     return(false);
891   }
892 
893   /* If it does exist, verify that it's an available CD-ROM */
894   cdfd = open(drive, (O_RDONLY|O_NONBLOCK), 0);
895   if ( cdfd >= 0 ) {
896     if ( ioctl(cdfd, CDROM_GET_CAPABILITY, 0) != -1 ) {
897       is_cd = true;
898     }
899     close(cdfd);
900     }
901   /* Even if we can't read it, it might be mounted */
902   else if ( mnttype && (strcmp(mnttype, "iso9660") == 0) ) {
903     is_cd = true;
904   }
905   return(is_cd);
906 }
907 
908 /* MMC driver to read audio sectors.
909    Can read only up to 25 blocks.
910 */
911 static driver_return_code_t
read_audio_sectors_linux(void * p_user_data,void * p_buf,lsn_t i_lsn,uint32_t i_blocks)912 read_audio_sectors_linux (void *p_user_data, void *p_buf, lsn_t i_lsn,
913                            uint32_t i_blocks)
914 {
915   _img_private_t *p_env = p_user_data;
916   return mmc_read_sectors( p_env->gen.cdio, p_buf, i_lsn,
917                            CDIO_MMC_READ_TYPE_CDDA, i_blocks);
918 }
919 
920 /* Packet driver to read mode2 sectors.
921    Can read only up to 25 blocks.
922 */
923 static driver_return_code_t
_read_mode2_sectors_mmc(_img_private_t * p_env,void * p_buf,lba_t lba,uint32_t i_blocks,bool b_read_10)924 _read_mode2_sectors_mmc (_img_private_t *p_env, void *p_buf, lba_t lba,
925                          uint32_t i_blocks, bool b_read_10)
926 {
927   mmc_cdb_t cdb = {{0, }};
928 
929   CDIO_MMC_SET_READ_LBA(cdb.field, lba);
930 
931   if (b_read_10) {
932     int retval;
933 
934     CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_READ_10);
935     CDIO_MMC_SET_READ_LENGTH16(cdb.field, i_blocks);
936 
937     if ((retval = mmc_set_blocksize (p_env->gen.cdio, M2RAW_SECTOR_SIZE)))
938       return retval;
939 
940     if ((retval = run_mmc_cmd_linux (p_env, 0,
941                                      mmc_get_cmd_len(cdb.field[0]),
942                                      &cdb,
943                                      SCSI_MMC_DATA_READ,
944                                      M2RAW_SECTOR_SIZE * i_blocks,
945                                      p_buf)))
946       {
947         mmc_set_blocksize (p_env->gen.cdio, CDIO_CD_FRAMESIZE);
948         return retval;
949       }
950 
951     /* Restore blocksize. */
952     retval = mmc_set_blocksize (p_env->gen.cdio, CDIO_CD_FRAMESIZE);
953     return retval;
954   } else {
955 
956     cdb.field[1] = 0; /* sector size mode2 */
957     cdb.field[9] = 0x58; /* 2336 mode2 */
958 
959     CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_READ_CD);
960     CDIO_MMC_SET_READ_LENGTH24(cdb.field, i_blocks);
961 
962     return run_mmc_cmd_linux (p_env, 0,
963                               mmc_get_cmd_len(cdb.field[0]), &cdb,
964                               SCSI_MMC_DATA_READ,
965                               M2RAW_SECTOR_SIZE * i_blocks, p_buf);
966   }
967 }
968 
969 static driver_return_code_t
_read_mode2_sectors(_img_private_t * p_env,void * p_buf,lba_t lba,uint32_t i_blocks,bool b_read_10)970 _read_mode2_sectors (_img_private_t *p_env, void *p_buf, lba_t lba,
971                      uint32_t i_blocks, bool b_read_10)
972 {
973   unsigned int l = 0;
974   int retval = 0;
975 
976   while (i_blocks > 0)
977     {
978       const unsigned i_blocks2 = (i_blocks > 25) ? 25 : i_blocks;
979       void *p_buf2 = ((char *)p_buf ) + (l * M2RAW_SECTOR_SIZE);
980 
981       retval |= _read_mode2_sectors_mmc (p_env, p_buf2, lba + l,
982                                          i_blocks2, b_read_10);
983 
984       if (retval)
985         break;
986 
987       i_blocks -= i_blocks2;
988       l += i_blocks2;
989     }
990 
991   return retval;
992 }
993 
994 /*!
995    Reads a single mode1 sector from cd device into data starting
996    from lsn. Returns 0 if no error.
997  */
998 static driver_return_code_t
_read_mode1_sector_linux(void * p_user_data,void * p_data,lsn_t lsn,bool b_form2)999 _read_mode1_sector_linux (void *p_user_data, void *p_data, lsn_t lsn,
1000                           bool b_form2)
1001 {
1002   return cdio_generic_read_form1_sector(p_user_data, p_data, lsn);
1003 }
1004 
1005 /*!
1006    Reads i_blocks of mode2 sectors from cd device into data starting
1007    from lsn.
1008    Returns 0 if no error.
1009  */
1010 static driver_return_code_t
_read_mode1_sectors_linux(void * p_user_data,void * p_data,lsn_t lsn,bool b_form2,uint32_t i_blocks)1011 _read_mode1_sectors_linux (void *p_user_data, void *p_data, lsn_t lsn,
1012                            bool b_form2, uint32_t i_blocks)
1013 {
1014   _img_private_t *p_env = p_user_data;
1015   unsigned int i;
1016   int retval;
1017   unsigned int blocksize = b_form2 ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE;
1018 
1019   for (i = 0; i < i_blocks; i++) {
1020     if ( (retval = _read_mode1_sector_linux (p_env,
1021                                             ((char *)p_data) + (blocksize*i),
1022                                             lsn + i, b_form2)) )
1023       return retval;
1024   }
1025   return DRIVER_OP_SUCCESS;
1026 }
1027 
1028 /*!
1029    Reads a single mode2 sector from cd device into data starting
1030    from lsn. Returns 0 if no error.
1031  */
1032 static driver_return_code_t
_read_mode2_sector_linux(void * p_user_data,void * p_data,lsn_t lsn,bool b_form2)1033 _read_mode2_sector_linux (void *p_user_data, void *p_data, lsn_t lsn,
1034                           bool b_form2)
1035 {
1036   char buf[M2RAW_SECTOR_SIZE] = { 0, };
1037   struct cdrom_msf *msf = (struct cdrom_msf *) &buf;
1038   msf_t _msf;
1039 
1040   _img_private_t *p_env = p_user_data;
1041 
1042   cdio_lba_to_msf (cdio_lsn_to_lba(lsn), &_msf);
1043   msf->cdmsf_min0 = cdio_from_bcd8(_msf.m);
1044   msf->cdmsf_sec0 = cdio_from_bcd8(_msf.s);
1045   msf->cdmsf_frame0 = cdio_from_bcd8(_msf.f);
1046 
1047  retry:
1048   switch (p_env->access_mode)
1049     {
1050     case _AM_NONE:
1051       cdio_warn ("no way to read mode2");
1052       return 1;
1053       break;
1054 
1055     case _AM_IOCTL:
1056     case _AM_MMC_RDWR:
1057     case _AM_MMC_RDWR_EXCL:
1058       if (ioctl (p_env->gen.fd, CDROMREADMODE2, &buf) == -1)
1059         {
1060           perror ("ioctl()");
1061           return 1;
1062           /* exit (EXIT_FAILURE); */
1063         }
1064       break;
1065 
1066     case _AM_READ_CD:
1067     case _AM_READ_10:
1068       if (_read_mode2_sectors (p_env, buf, lsn, 1,
1069                                (p_env->access_mode == _AM_READ_10)))
1070         {
1071           perror ("ioctl()");
1072           if (p_env->access_mode == _AM_READ_CD)
1073             {
1074               cdio_info ("READ_CD failed; switching to READ_10 mode...");
1075               p_env->access_mode = _AM_READ_10;
1076               goto retry;
1077             }
1078           else
1079             {
1080               cdio_info ("READ_10 failed; switching to ioctl(CDROMREADMODE2) mode...");
1081               p_env->access_mode = _AM_IOCTL;
1082               goto retry;
1083             }
1084           return 1;
1085         }
1086       break;
1087     }
1088 
1089   if (b_form2)
1090     memcpy (p_data, buf, M2RAW_SECTOR_SIZE);
1091   else
1092     memcpy (((char *)p_data), buf + CDIO_CD_SUBHEADER_SIZE, CDIO_CD_FRAMESIZE);
1093 
1094   return DRIVER_OP_SUCCESS;
1095 }
1096 
1097 /*!
1098    Reads i_blocks of mode2 sectors from cd device into data starting
1099    from lsn.
1100    Returns 0 if no error.
1101  */
1102 static driver_return_code_t
_read_mode2_sectors_linux(void * p_user_data,void * data,lsn_t lsn,bool b_form2,uint32_t i_blocks)1103 _read_mode2_sectors_linux (void *p_user_data, void *data, lsn_t lsn,
1104                            bool b_form2, uint32_t i_blocks)
1105 {
1106   _img_private_t *p_env = p_user_data;
1107   unsigned int i;
1108   uint16_t i_blocksize = b_form2 ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE;
1109 
1110   /* For each frame, pick out the data part we need */
1111   for (i = 0; i < i_blocks; i++) {
1112     int retval;
1113     if ( (retval = _read_mode2_sector_linux (p_env,
1114                                             ((char *)data) + (i_blocksize*i),
1115                                             lsn + i, b_form2)) )
1116       return retval;
1117   }
1118   return DRIVER_OP_SUCCESS;
1119 }
1120 
1121 /*!
1122   Read and cache the CD's Track Table of Contents and track info.
1123   Return false if successful or true if an error.
1124 */
1125 static bool
read_toc_linux(void * p_user_data)1126 read_toc_linux (void *p_user_data)
1127 {
1128   _img_private_t *p_env = p_user_data;
1129   int i, i_last_track;
1130   unsigned int u_tracks;
1131 
1132   /* read TOC header */
1133   if ( ioctl(p_env->gen.fd, CDROMREADTOCHDR, &p_env->tochdr) == -1 ) {
1134     cdio_warn("%s: %s\n",
1135             "error in ioctl CDROMREADTOCHDR", strerror(errno));
1136     return false;
1137   }
1138 
1139   p_env->gen.i_first_track = p_env->tochdr.cdth_trk0;
1140   i_last_track             = p_env->tochdr.cdth_trk1;
1141   p_env->gen.i_tracks      = i_last_track - p_env->gen.i_first_track + 1;
1142 
1143   u_tracks = p_env->gen.i_tracks;
1144 
1145   if (u_tracks > CDIO_CD_MAX_TRACKS) {
1146      cdio_log(CDIO_LOG_WARN, "Number of tracks exceeds maximum (%d vs. %d)\n",
1147               u_tracks, CDIO_CD_MAX_TRACKS);
1148      p_env->gen.i_tracks = CDIO_CD_MAX_TRACKS;
1149   }
1150 
1151 
1152   /* read individual tracks */
1153   for (i= p_env->gen.i_first_track; i <= i_last_track; i++) {
1154     struct cdrom_tocentry *p_toc =
1155       &(p_env->tocent[i-p_env->gen.i_first_track]);
1156 
1157     p_toc->cdte_track = i;
1158     p_toc->cdte_format = CDROM_MSF;
1159     if ( ioctl(p_env->gen.fd, CDROMREADTOCENTRY, p_toc) == -1 ) {
1160       cdio_warn("%s %d: %s\n",
1161               "error in ioctl CDROMREADTOCENTRY for track",
1162               i, strerror(errno));
1163       return false;
1164     }
1165 
1166     set_track_flags(&(p_env->gen.track_flags[i]), p_toc->cdte_ctrl);
1167 
1168     /****
1169     struct cdrom_msf0 *msf= &env->tocent[i-1].cdte_addr.msf;
1170 
1171     fprintf (stdout, "--- track# %d (msf %2.2x:%2.2x:%2.2x)\n",
1172              i, msf->minute, msf->second, msf->frame);
1173     ****/
1174 
1175   }
1176 
1177   /* read the lead-out track */
1178   p_env->tocent[p_env->gen.i_tracks].cdte_track = CDIO_CDROM_LEADOUT_TRACK;
1179   p_env->tocent[p_env->gen.i_tracks].cdte_format = CDROM_MSF;
1180 
1181   if (ioctl(p_env->gen.fd, CDROMREADTOCENTRY,
1182             &p_env->tocent[p_env->gen.i_tracks]) == -1 ) {
1183     cdio_warn("%s: %s\n",
1184              "error in ioctl CDROMREADTOCENTRY for lead-out",
1185             strerror(errno));
1186     return false;
1187   }
1188 
1189   /*
1190   struct cdrom_msf0 *msf= &env->tocent[p_env->gen.i_tracks].cdte_addr.msf;
1191 
1192   fprintf (stdout, "--- track# %d (msf %2.2x:%2.2x:%2.2x)\n",
1193            i, msf->minute, msf->second, msf->frame);
1194   */
1195 
1196   p_env->gen.toc_init = true;
1197   return true;
1198 }
1199 
1200 /*!
1201   Run a SCSI MMC command.
1202 
1203   cdio          CD structure set by cdio_open().
1204   i_timeout     time in milliseconds we will wait for the command
1205                 to complete. If this value is -1, use the default
1206                 time-out value.
1207   p_buf         Buffer for data, both sending and receiving
1208   i_buf         Size of buffer
1209   e_direction   direction the transfer is to go.
1210   cdb           CDB bytes. All values that are needed should be set on
1211                 input. We'll figure out what the right CDB length should be.
1212 
1213   We return true if command completed successfully and false if not.
1214  */
1215 static driver_return_code_t
run_mmc_cmd_linux(void * p_user_data,unsigned int i_timeout_ms,unsigned int i_cdb,const mmc_cdb_t * p_cdb,cdio_mmc_direction_t e_direction,unsigned int i_buf,void * p_buf)1216 run_mmc_cmd_linux(void *p_user_data,
1217                   unsigned int i_timeout_ms,
1218                   unsigned int i_cdb, const mmc_cdb_t *p_cdb,
1219                   cdio_mmc_direction_t e_direction,
1220                   unsigned int i_buf, /*in/out*/ void *p_buf)
1221 {
1222   _img_private_t *p_env = p_user_data;
1223   struct cdrom_generic_command cgc;
1224   cdio_mmc_request_sense_t sense;
1225 
1226   p_env->gen.scsi_mmc_sense_valid = 0;
1227 
1228   memset(&cgc, 0, sizeof (struct cdrom_generic_command));
1229   memset(&sense, 0, sizeof (struct cdio_mmc_request_sense));
1230   memcpy(&cgc.cmd, p_cdb, i_cdb);
1231 
1232   cgc.buflen = i_buf;
1233   cgc.buffer = p_buf;
1234   cgc.sense  = (struct request_sense *) &sense;
1235 
1236   cgc.data_direction = (SCSI_MMC_DATA_READ  == e_direction) ? CGC_DATA_READ  :
1237                        (SCSI_MMC_DATA_WRITE == e_direction) ? CGC_DATA_WRITE :
1238                        CGC_DATA_NONE;
1239 
1240 #ifdef HAVE_LINUX_CDROM_TIMEOUT
1241   cgc.timeout = i_timeout_ms;
1242 #endif
1243 
1244   {
1245     int i_rc = ioctl (p_env->gen.fd, CDROM_SEND_PACKET, &cgc);
1246 
1247     /* Record SCSI sense reply for API call mmc_last_cmd_sense().
1248     */
1249     if (sense.additional_sense_len) {
1250         /* SCSI Primary Command standard
1251            SPC 4.5.3, Table 26: 252 bytes legal, 263 bytes possible */
1252         int sense_size = sense.additional_sense_len + 8;
1253 
1254         if (sense_size > sizeof(sense))
1255             sense_size = sizeof(sense);
1256         memcpy((void *) p_env->gen.scsi_mmc_sense, &sense, sense_size);
1257         p_env->gen.scsi_mmc_sense_valid = sense_size;
1258     }
1259 
1260     if (0 == i_rc) return DRIVER_OP_SUCCESS;
1261     if (-1 == i_rc) {
1262       cdio_info("ioctl CDROM_SEND_PACKET for command %s (0x%0x) failed:\n\t%s",
1263                 mmc_cmd2str((uint8_t) p_cdb->field[0]),
1264                 p_cdb->field[0],
1265                 strerror(errno));
1266       switch (errno) {
1267       case EPERM:
1268         return DRIVER_OP_NOT_PERMITTED;
1269         break;
1270       case EINVAL:
1271         return DRIVER_OP_BAD_PARAMETER;
1272         break;
1273       case EFAULT:
1274         return DRIVER_OP_BAD_POINTER;
1275         break;
1276       case EIO:
1277       default:
1278         return DRIVER_OP_ERROR;
1279         break;
1280       }
1281     } else if (i_rc < -1)
1282       return DRIVER_OP_ERROR;
1283     else
1284       /*Not sure if this the best thing, but we'll use anyway. */
1285       return DRIVER_OP_SUCCESS;
1286   }
1287 }
1288 
1289 /*!
1290    Return the size of the CD in logical block address (LBA) units.
1291    @return the lsn. On error return CDIO_INVALID_LSN.
1292 
1293    As of GNU/Linux 2.6, CDROMTOCENTRY gives
1294    ioctl CDROMREADTOCENTRY failed: Invalid argument
1295 
1296 
1297    In some cases CDROMREADTOCHDR seems to fix this, but I haven't been
1298    able to find anything that documents this requirement or behavior. It's
1299    not the way CDROMREADTOCHDR works on other 'nixs.
1300 
1301    Also note that in one at least one test the corresponding MMC gives
1302    a different answer, so there may be some disagreement about what is in
1303    fact the last lsn.
1304  */
1305 static lsn_t
get_disc_last_lsn_linux(void * p_user_data)1306 get_disc_last_lsn_linux (void *p_user_data)
1307 {
1308   _img_private_t *p_env = p_user_data;
1309 
1310   struct cdrom_tocentry tocent;
1311   uint32_t i_size;
1312 
1313   if (!p_env->gen.toc_init) read_toc_linux (p_user_data) ;
1314 
1315   tocent.cdte_track = CDIO_CDROM_LEADOUT_TRACK;
1316   tocent.cdte_format = CDROM_LBA;
1317   if (ioctl (p_env->gen.fd, CDROMREADTOCENTRY, &tocent) == -1)
1318     {
1319       cdio_warn ("ioctl CDROMREADTOCENTRY failed: %s\n", strerror(errno));
1320       return CDIO_INVALID_LSN;
1321     }
1322 
1323   i_size = tocent.cdte_addr.lba;
1324 
1325   return i_size;
1326 }
1327 
1328 /*!
1329   Set the arg "key" with "value" in the source device.
1330   Currently "source" and "access-mode" are valid keys.
1331   "source" sets the source device in I/O operations
1332   "access-mode" sets the the method of CD access
1333 
1334   DRIVER_OP_SUCCESS is returned if no error was found,
1335   and nonzero if there as an error.
1336 */
1337 static driver_return_code_t
set_arg_linux(void * p_user_data,const char key[],const char value[])1338 set_arg_linux (void *p_user_data, const char key[], const char value[])
1339 {
1340   _img_private_t *p_env = p_user_data;
1341 
1342   if (!strcmp (key, "source"))
1343     {
1344       if (!value) return DRIVER_OP_ERROR;
1345       free (p_env->gen.source_name);
1346       p_env->gen.source_name = strdup (value);
1347     }
1348   else if (!strcmp (key, "access-mode"))
1349     {
1350       p_env->access_mode = str_to_access_mode_linux(key);
1351     }
1352   else return DRIVER_OP_ERROR;
1353 
1354   return DRIVER_OP_SUCCESS;
1355 }
1356 
1357 /* checklist: /dev/cdrom, /dev/dvd /dev/hd?, /dev/scd? /dev/sr? */
1358 static const char checklist1[][40] = {
1359   {"cdrom"}, {"dvd"}
1360 };
1361 static const int checklist1_size = sizeof(checklist1) / sizeof(checklist1[0]);
1362 
1363 static const struct
1364   {
1365     char format[22];
1366     int num_min;
1367     int num_max;
1368   }
1369 checklist2[] =
1370   {
1371     { "/dev/hd%c",  'a', 'z' },
1372     { "/dev/scd%d", 0,   27 },
1373     { "/dev/sr%d",  0,   27 },
1374   };
1375 static const int checklist2_size = sizeof(checklist2) / sizeof(checklist2[0]);
1376 
1377 
1378 /* Set CD-ROM drive speed */
1379 static driver_return_code_t
set_speed_linux(void * p_user_data,int i_drive_speed)1380 set_speed_linux (void *p_user_data, int i_drive_speed)
1381 {
1382   const _img_private_t *p_env = p_user_data;
1383 
1384   if (!p_env) return DRIVER_OP_UNINIT;
1385   return ioctl(p_env->gen.fd, CDROM_SELECT_SPEED, i_drive_speed);
1386 }
1387 
1388 #endif /* HAVE_LINUX_CDROM */
1389 
1390 /*!
1391   Return an array of strings giving possible CD devices.
1392  */
1393 char **
cdio_get_devices_linux(void)1394 cdio_get_devices_linux (void)
1395 {
1396 #ifndef HAVE_LINUX_CDROM
1397   return NULL;
1398 #else
1399   unsigned int i;
1400   char drive[40];
1401   char *ret_drive;
1402   char **drives = NULL;
1403   unsigned int num_drives=0;
1404 
1405   /* Scan the system for CD-ROM drives.
1406   */
1407   for ( i=0; i < checklist1_size; ++i ) {
1408     if (snprintf(drive, sizeof(drive), "/dev/%s", checklist1[i]) < 0)
1409       continue;
1410     if ( is_cdrom_linux(drive, NULL) > 0 ) {
1411       cdio_add_device_list(&drives, drive, &num_drives);
1412     }
1413   }
1414 
1415   /* Now check the currently mounted CD drives */
1416   if (NULL != (ret_drive = check_mounts_linux("/etc/mtab"))) {
1417     cdio_add_device_list(&drives, ret_drive, &num_drives);
1418     free(ret_drive);
1419   }
1420 
1421   /* Finally check possible mountable drives in /etc/fstab */
1422   if (NULL != (ret_drive = check_mounts_linux("/etc/fstab"))) {
1423     cdio_add_device_list(&drives, ret_drive, &num_drives);
1424     free(ret_drive);
1425   }
1426 
1427   /* Scan the system for CD-ROM drives.
1428      Not always 100% reliable, so use the USE_MNTENT code above first.
1429   */
1430   for ( i=0; i < checklist2_size; ++i ) {
1431     unsigned int j;
1432     for ( j=checklist2[i].num_min; j<=checklist2[i].num_max; ++j ) {
1433       if (snprintf(drive, sizeof(drive), checklist2[i].format, j) < 0)
1434         continue;
1435       if ( (is_cdrom_linux(drive, NULL)) > 0 ) {
1436         cdio_add_device_list(&drives, drive, &num_drives);
1437       }
1438     }
1439   }
1440   cdio_add_device_list(&drives, NULL, &num_drives);
1441   return drives;
1442 #endif /*HAVE_LINUX_CDROM*/
1443 }
1444 
1445 /*!
1446   Return a string containing the default CD device.
1447  */
1448 char *
cdio_get_default_device_linux(void)1449 cdio_get_default_device_linux(void)
1450 {
1451 #ifndef HAVE_LINUX_CDROM
1452   return NULL;
1453 
1454 #else
1455   unsigned int i;
1456   char drive[40];
1457   char *ret_drive;
1458 
1459   /* Scan the system for CD-ROM drives.
1460   */
1461   for ( i=0; i < checklist1_size; ++i ) {
1462     if (snprintf(drive, sizeof(drive), "/dev/%s", checklist1[i]) < 0)
1463       continue;
1464     if ( is_cdrom_linux(drive, NULL) > 0 ) {
1465       return strdup(drive);
1466     }
1467   }
1468 
1469   /* Now check the currently mounted CD drives */
1470   if (NULL != (ret_drive = check_mounts_linux("/etc/mtab")))
1471     return ret_drive;
1472 
1473   /* Finally check possible mountable drives in /etc/fstab */
1474   if (NULL != (ret_drive = check_mounts_linux("/etc/fstab")))
1475     return ret_drive;
1476 
1477   /* Scan the system for CD-ROM drives.
1478      Not always 100% reliable, so use the USE_MNTENT code above first.
1479   */
1480   for ( i=0; i < checklist2_size; ++i ) {
1481     unsigned int j;
1482     for ( j=checklist2[i].num_min; j<=checklist2[i].num_max; ++j ) {
1483       if (snprintf(drive, sizeof(drive), checklist2[i].format, j) < 0)
1484         continue;
1485       if ( is_cdrom_linux(drive, NULL) > 0 ) {
1486         return(strdup(drive));
1487       }
1488     }
1489   }
1490   return NULL;
1491 #endif /*HAVE_LINUX_CDROM*/
1492 }
1493 
1494 /*!
1495   Close tray on CD-ROM.
1496 
1497   @param psz_device the CD-ROM drive to be closed.
1498 
1499 */
1500 driver_return_code_t
close_tray_linux(const char * psz_device)1501 close_tray_linux (const char *psz_device)
1502 {
1503 #ifdef HAVE_LINUX_CDROM
1504   int i_rc;
1505   int fd = open (psz_device, O_RDONLY|O_NONBLOCK);
1506   int status;
1507 
1508   if ( fd > -1 ) {
1509     if((status = ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT)) > 0) {
1510       switch(status) {
1511       case CDS_TRAY_OPEN:
1512         goto try_anyway;
1513         break;
1514       case CDS_DISC_OK:
1515         cdio_info ("Tray already closed.");
1516         i_rc = DRIVER_OP_SUCCESS;
1517         break;
1518       default:
1519         cdio_info ("Unknown CD-ROM status (%d), trying anyway", status);
1520         goto try_anyway;
1521       }
1522     } else {
1523       cdio_info ("CDROM_DRIVE_STATUS failed: %s, trying anyway",
1524                  strerror(errno));
1525     try_anyway:
1526       if((i_rc = ioctl(fd, CDROMCLOSETRAY)) != 0) {
1527         cdio_warn ("ioctl CDROMCLOSETRAY failed: %s\n", strerror(errno));
1528         i_rc = DRIVER_OP_ERROR;
1529       }
1530     }
1531     close(fd);
1532   } else
1533     i_rc = DRIVER_OP_ERROR;
1534   return i_rc;
1535 #else
1536   return DRIVER_OP_NO_DRIVER;
1537 #endif /*HAVE_LINUX_CDROM*/
1538 }
1539 
1540 #ifdef HAVE_LINUX_CDROM
1541 /*!
1542   Produce a text composed from the system SCSI address tuple according to
1543   habits of Linux 2.4 and 2.6 :  "Bus,Host,Channel,Target,Lun" and store
1544   it in generic_img_private_t.scsi_tuple.
1545   To be accessed via cdio_get_arg("scsi-tuple-linux") or ("scsi-tuple").
1546   Drivers which implement this code have to return 5 valid decimal numbers
1547   separated by comma, or empty text if no such numbers are available.
1548   @return   1=success , 0=failure
1549 */
1550 static int
set_scsi_tuple_linux(_img_private_t * env)1551 set_scsi_tuple_linux(_img_private_t *env)
1552 {
1553   int bus_no = -1, host_no = -1, channel_no = -1, target_no = -1, lun_no = -1;
1554   int ret, i;
1555   char tuple[160], hdx[10];
1556 #ifdef SCSI_IOCTL_GET_IDLUN
1557   struct my_scsi_idlun {
1558     int x;
1559     int host_unique_id;
1560   };
1561   struct my_scsi_idlun idlun;
1562 #endif
1563   struct stat stbuf, env_stbuf;
1564 
1565   /* Check whether this is a hdX and declare tuple unavailable.
1566      /dev/hdX is traditionally for IDE drives and the ioctls here traditionally
1567      return ok and all 0s for all IDE drives. So the tuples are no unique ids.
1568   */
1569   if (fstat(env->gen.fd, &env_stbuf) == -1)
1570     goto no_tuple;
1571   strcpy(hdx, "/dev/hdX");
1572   for (i = 'a'; i <= 'z'; i++) {
1573     hdx[7] = i;
1574     if (stat(hdx, &stbuf) == -1)
1575   continue;
1576     if (env_stbuf.st_dev == stbuf.st_dev && env_stbuf.st_ino == stbuf.st_ino)
1577       goto no_tuple;
1578   }
1579 
1580 #ifdef SCSI_IOCTL_GET_BUS_NUMBER
1581   if (ioctl(env->gen.fd, SCSI_IOCTL_GET_BUS_NUMBER, &bus_no) == -1)
1582     bus_no = -1;
1583 #endif
1584 
1585 #ifdef SCSI_IOCTL_GET_IDLUN
1586   /* http://www.tldp.org/HOWTO/SCSI-Generic-HOWTO/scsi_g_idlun.html */
1587 
1588   ret = ioctl(env->gen.fd, SCSI_IOCTL_GET_IDLUN, &idlun);
1589   if (ret != -1) {
1590     host_no= (idlun.x >> 24) & 255;
1591     channel_no= (idlun.x >> 16) & 255;
1592     target_no= (idlun.x) & 255;
1593     lun_no= (idlun.x >> 8) & 255;
1594   }
1595 #endif
1596 
1597   if (env->gen.scsi_tuple != NULL)
1598     free (env->gen.scsi_tuple);
1599   env->gen.scsi_tuple = NULL;
1600   if (bus_no < 0 || host_no < 0 || channel_no < 0 || target_no < 0 ||
1601       lun_no < 0) {
1602 no_tuple:;
1603     env->gen.scsi_tuple = strdup("");
1604     return 0;
1605   }
1606   snprintf(tuple, sizeof(tuple)-1, "%d,%d,%d,%d,%d",
1607           bus_no, host_no, channel_no, target_no, lun_no);
1608   env->gen.scsi_tuple = strdup(tuple);
1609   return 1;
1610 }
1611 #endif
1612 
1613 /*!
1614   Initialization routine. This is the only thing that doesn't
1615   get called via a function pointer. In fact *we* are the
1616   ones to set that up.
1617  */
1618 CdIo_t *
cdio_open_linux(const char * psz_source_name)1619 cdio_open_linux (const char *psz_source_name)
1620 {
1621 #ifdef HAVE_LINUX_CDROM
1622   return cdio_open_am_linux(psz_source_name, NULL);
1623 #else
1624   return NULL;
1625 #endif /*HAVE_LINUX_CDROM*/
1626 }
1627 
1628 /*!
1629   Initialization routine. This is the only thing that doesn't
1630   get called via a function pointer. In fact *we* are the
1631   ones to set that up.
1632  */
1633 CdIo_t *
cdio_open_am_linux(const char * psz_orig_source,const char * access_mode)1634 cdio_open_am_linux (const char *psz_orig_source, const char *access_mode)
1635 {
1636 
1637 #ifdef HAVE_LINUX_CDROM
1638   CdIo_t *ret;
1639   _img_private_t *_data;
1640   char *psz_source;
1641   int open_access_mode;  /* Access mode passed to cdio_generic_init. */
1642 
1643   cdio_funcs_t _funcs = {
1644     .audio_get_volume      = audio_get_volume_linux,
1645     .audio_pause           = audio_pause_linux,
1646     .audio_play_msf        = audio_play_msf_linux,
1647     .audio_play_track_index= audio_play_track_index_linux,
1648 #ifdef USE_MMC_SUBCHANNEL
1649     .audio_read_subchannel = audio_read_subchannel_mmc,
1650 #else
1651     .audio_read_subchannel = audio_read_subchannel_linux,
1652 #endif
1653     .audio_resume          = audio_resume_linux,
1654     .audio_set_volume      = audio_set_volume_linux,
1655     .audio_stop            = audio_stop_linux,
1656     .eject_media           = eject_media_linux,
1657     .free                  = cdio_generic_free,
1658     .get_arg               = get_arg_linux,
1659     .get_blocksize         = get_blocksize_mmc,
1660     .get_cdtext            = get_cdtext_generic,
1661     .get_cdtext_raw        = read_cdtext_generic,
1662     .get_default_device    = cdio_get_default_device_linux,
1663     .get_devices           = cdio_get_devices_linux,
1664     .get_disc_last_lsn     = get_disc_last_lsn_linux,
1665     .get_discmode          = get_discmode_linux,
1666 #if defined(USE_LINUX_CAP)
1667     .get_drive_cap         = get_drive_cap_linux,
1668 #else
1669     .get_drive_cap         = get_drive_cap_mmc,
1670 #endif
1671     .get_first_track_num   = get_first_track_num_generic,
1672     .get_hwinfo            = NULL,
1673     .get_last_session      = get_last_session_linux,
1674     .get_media_changed     = get_media_changed_linux,
1675     .get_mcn               = get_mcn_linux,
1676     .get_num_tracks        = get_num_tracks_generic,
1677     .get_track_channels    = get_track_channels_generic,
1678     .get_track_copy_permit = get_track_copy_permit_generic,
1679     .get_track_format      = get_track_format_linux,
1680     .get_track_green       = get_track_green_linux,
1681     .get_track_lba         = NULL, /* This could be implemented if need be. */
1682     .get_track_preemphasis = get_track_preemphasis_generic,
1683     .get_track_msf         = get_track_msf_linux,
1684     .get_track_isrc        = get_track_isrc_linux,
1685     .lseek                 = cdio_generic_lseek,
1686     .read                  = cdio_generic_read,
1687     .read_audio_sectors    = read_audio_sectors_linux,
1688 #if 1
1689     .read_data_sectors     = read_data_sectors_generic,
1690 #else
1691     .read_data_sectors     = read_data_sectors_mmc,
1692 #endif
1693     .read_mode1_sector     = _read_mode1_sector_linux,
1694     .read_mode1_sectors    = _read_mode1_sectors_linux,
1695     .read_mode2_sector     = _read_mode2_sector_linux,
1696     .read_mode2_sectors    = _read_mode2_sectors_linux,
1697     .read_toc              = read_toc_linux,
1698     .run_mmc_cmd           = run_mmc_cmd_linux,
1699     .set_arg               = set_arg_linux,
1700     .set_blocksize         = set_blocksize_mmc,
1701 #if 1
1702     .set_speed             = set_speed_linux,
1703 #else
1704     .set_speed             = set_speed_mmc,
1705 #endif
1706   };
1707 
1708   _data                 = calloc (1, sizeof (_img_private_t));
1709 
1710   _data->access_mode    = str_to_access_mode_linux(access_mode);
1711   _data->gen.init       = false;
1712   _data->gen.toc_init   = false;
1713   _data->gen.fd         = -1;
1714   _data->gen.b_cdtext_error = false;
1715 
1716   if (NULL == psz_orig_source) {
1717     psz_source=cdio_get_default_device_linux();
1718     if (NULL == psz_source) {
1719       goto err_exit;
1720     }
1721 
1722     set_arg_linux(_data, "source", psz_source);
1723     free(psz_source);
1724   } else {
1725     if (cdio_is_device_generic(psz_orig_source))
1726       set_arg_linux(_data, "source", psz_orig_source);
1727     else {
1728       /* The below would be okay if all device drivers worked this way. */
1729 #if 0
1730       cdio_info ("source %s is not a device", psz_orig_source);
1731 #endif
1732       goto err_exit;
1733     }
1734   }
1735 
1736   ret = cdio_new ((void *)_data, &_funcs);
1737   if (ret == NULL) {
1738     goto err_exit;
1739   }
1740 
1741   ret->driver_id = DRIVER_LINUX;
1742 
1743   open_access_mode = O_NONBLOCK;
1744   if (_AM_MMC_RDWR == _data->access_mode)
1745     open_access_mode |= O_RDWR;
1746   else if (_AM_MMC_RDWR_EXCL == _data->access_mode)
1747     open_access_mode |= O_RDWR | O_EXCL;
1748   else
1749     open_access_mode |= O_RDONLY;
1750   if (cdio_generic_init(_data, open_access_mode)) {
1751     set_scsi_tuple_linux(_data);
1752     return ret;
1753   }
1754   free(ret);
1755 
1756  err_exit:
1757     cdio_generic_free(_data);
1758     return NULL;
1759 
1760 #else
1761   return NULL;
1762 #endif /* HAVE_LINUX_CDROM */
1763 
1764 }
1765 
1766 bool
cdio_have_linux(void)1767 cdio_have_linux (void)
1768 {
1769 #ifdef HAVE_LINUX_CDROM
1770   return true;
1771 #else
1772   return false;
1773 #endif /* HAVE_LINUX_CDROM */
1774 }
1775 
1776 
1777 /*
1778  * Local variables:
1779  *  c-file-style: "gnu"
1780  *  tab-width: 8
1781  *  indent-tabs-mode: nil
1782  * End:
1783  */
1784