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