1 /*
2   Copyright (C) 2002-2006, 2009, 2011-2012, 2017
3   Rocky Bernstein <rocky@gnu.org>
4   Copyright (C) 2001 Herbert Valerio Riedel <hvr@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 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #endif
23 
24 #ifdef HAVE_STRING_H
25 #include <string.h>
26 #endif
27 
28 #include <cdio/logging.h>
29 #include <cdio/sector.h>
30 #include <cdio/util.h>
31 #include <cdio/mmc.h>
32 #include "cdio_assert.h"
33 #include "cdio_private.h"
34 
35 #define DEFAULT_CDIO_DEVICE "/vol/dev/aliases/cdrom0"
36 
37 #ifdef HAVE_SOLARIS_CDROM
38 
39 static char ** cdio_get_devices_solaris_cXtYdZs2(int flag);
40 
41 #ifdef HAVE_GLOB_H
42 #include <glob.h>
43 #endif
44 
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <errno.h>
48 #include <unistd.h>
49 #include <fcntl.h>
50 
51 #ifdef HAVE_SYS_CDIO_H
52 # include <sys/cdio.h> /* CDIOCALLOW etc... */
53 #else
54 #error "You need <sys/cdio.h> to have CDROM support"
55 #endif
56 
57 #include <sys/dkio.h>
58 #include <sys/scsi/generic/commands.h>
59 #include <sys/scsi/impl/uscsi.h>
60 
61 #include <sys/stat.h>
62 #include <sys/types.h>
63 #include <sys/ioctl.h>
64 #include <dirent.h>
65 #include "cdtext_private.h"
66 
67 /* not defined in dkio.h yet */
68 #define DK_DVDRW 0x13
69 
70 /* reader */
71 
72 typedef  enum {
73     _AM_NONE,
74     _AM_SUN_CTRL_ATAPI,
75     _AM_SUN_CTRL_SCSI,
76     _AM_MMC_RDWR,
77     _AM_MMC_RDWR_EXCL
78 #ifdef FINISHED
79     _AM_READ_CD,
80     _AM_READ_10
81 #endif
82 } access_mode_t;
83 
84 
85 typedef struct {
86   /* Things common to all drivers like this.
87      This must be first. */
88   generic_img_private_t gen;
89 
90   access_mode_t access_mode;
91 
92   /* Some of the more OS specific things. */
93   /* Entry info for each track, add 1 for leadout. */
94   struct cdrom_tocentry  tocent[CDIO_CD_MAX_TRACKS+1];
95 
96   /* Track information */
97   struct cdrom_tochdr    tochdr;
98 } _img_private_t;
99 
100 /*!
101   Return the international standard recording code ISRC.
102 
103   Note: string is malloc'd so caller should free() then returned
104   string when done with it.
105 
106  */
107 static char *
get_track_isrc_solaris(const void * p_user_data,track_t i_track)108 get_track_isrc_solaris (const void *p_user_data, track_t i_track) {
109 
110   const _img_private_t *p_env = p_user_data;
111   return mmc_get_track_isrc( p_env->gen.cdio, i_track );
112 }
113 
114 static track_format_t get_track_format_solaris(void *p_user_data,
115                                                track_t i_track);
116 
117 static access_mode_t
str_to_access_mode_solaris(const char * psz_access_mode)118 str_to_access_mode_solaris(const char *psz_access_mode)
119 {
120   const access_mode_t default_access_mode = _AM_SUN_CTRL_SCSI;
121 
122   if (NULL==psz_access_mode) return default_access_mode;
123 
124   if (!strcmp(psz_access_mode, "ATAPI"))
125     return _AM_SUN_CTRL_SCSI; /* force ATAPI to be SCSI */
126   else if (!strcmp(psz_access_mode, "SCSI"))
127     return _AM_SUN_CTRL_SCSI;
128   else if (!strcmp(psz_access_mode, "MMC_RDWR"))
129     return _AM_MMC_RDWR;
130   else if (!strcmp(psz_access_mode, "MMC_RDWR_EXCL"))
131     return _AM_MMC_RDWR_EXCL;
132   else {
133     cdio_warn ("unknown access type: %s. Default SCSI used.",
134                psz_access_mode);
135     return default_access_mode;
136   }
137 }
138 
139 
140 /*!
141   Pause playing CD through analog output
142 
143   @param p_cdio the CD object to be acted upon.
144 */
145 static driver_return_code_t
audio_pause_solaris(void * p_user_data)146 audio_pause_solaris (void *p_user_data)
147 {
148 
149   const _img_private_t *p_env = p_user_data;
150   return ioctl(p_env->gen.fd, CDROMPAUSE);
151 }
152 
153 /*!
154   Playing starting at given MSF through analog output
155 
156   @param p_cdio the CD object to be acted upon.
157 */
158 static driver_return_code_t
audio_play_msf_solaris(void * p_user_data,msf_t * p_start_msf,msf_t * p_end_msf)159 audio_play_msf_solaris (void *p_user_data, msf_t *p_start_msf,
160                         msf_t *p_end_msf)
161 {
162 
163   const _img_private_t *p_env = p_user_data;
164 
165   struct cdrom_msf solaris_msf;
166   solaris_msf.cdmsf_min0   = cdio_from_bcd8(p_start_msf->m);
167   solaris_msf.cdmsf_sec0   = cdio_from_bcd8(p_start_msf->s);
168   solaris_msf.cdmsf_frame0 = cdio_from_bcd8(p_start_msf->f);
169   solaris_msf.cdmsf_min1   = cdio_from_bcd8(p_end_msf->m);
170   solaris_msf.cdmsf_sec1   = cdio_from_bcd8(p_end_msf->s);
171   solaris_msf.cdmsf_frame1 = cdio_from_bcd8(p_end_msf->f);
172 
173   return ioctl(p_env->gen.fd, CDROMPLAYMSF, &solaris_msf);
174 }
175 
176 /*!
177   Playing CD through analog output at the desired track and index
178 
179   @param p_cdio the CD object to be acted upon.
180   @param p_track_index location to start/end.
181 */
182 static driver_return_code_t
audio_play_track_index_solaris(void * p_user_data,cdio_track_index_t * p_track_index)183 audio_play_track_index_solaris (void *p_user_data,
184                                 cdio_track_index_t *p_track_index)
185 {
186 
187   const _img_private_t *p_env = p_user_data;
188   return ioctl(p_env->gen.fd, CDROMPLAYTRKIND, p_track_index);
189 }
190 
191 /*!
192   Read Audio Subchannel information
193 
194   @param p_cdio the CD object to be acted upon.
195 
196 */
197 static driver_return_code_t
audio_read_subchannel_solaris(void * p_user_data,cdio_subchannel_t * p_subchannel)198 audio_read_subchannel_solaris (void *p_user_data,
199                                cdio_subchannel_t *p_subchannel)
200 {
201   const _img_private_t *p_env = p_user_data;
202   struct cdrom_subchnl subchannel;
203   int   i_rc;
204   p_subchannel->format = CDIO_CDROM_MSF;
205   i_rc = ioctl(p_env->gen.fd, CDROMSUBCHNL, &subchannel);
206   if (0 == i_rc) {
207     p_subchannel->control      = subchannel.cdsc_ctrl;
208     p_subchannel->track        = subchannel.cdsc_trk;
209     p_subchannel->index        = subchannel.cdsc_ind;
210 
211     p_subchannel->abs_addr.m   =
212       cdio_to_bcd8(subchannel.cdsc_absaddr.msf.minute);
213     p_subchannel->abs_addr.s   =
214       cdio_to_bcd8(subchannel.cdsc_absaddr.msf.second);
215     p_subchannel->abs_addr.f   =
216       cdio_to_bcd8(subchannel.cdsc_absaddr.msf.frame);
217     p_subchannel->rel_addr.m   =
218       cdio_to_bcd8(subchannel.cdsc_reladdr.msf.minute);
219     p_subchannel->rel_addr.s   =
220       cdio_to_bcd8(subchannel.cdsc_reladdr.msf.second);
221     p_subchannel->rel_addr.f   =
222       cdio_to_bcd8(subchannel.cdsc_reladdr.msf.frame);
223     p_subchannel->audio_status = subchannel.cdsc_audiostatus;
224 
225     return DRIVER_OP_SUCCESS;
226   } else {
227     cdio_info ("ioctl CDROMSUBCHNL failed: %s\n", strerror(errno));
228     return DRIVER_OP_ERROR;
229   }
230 }
231 
232 /*!
233   Resume playing an audio CD.
234 
235   @param p_cdio the CD object to be acted upon.
236 
237 */
238 static driver_return_code_t
audio_resume_solaris(void * p_user_data)239 audio_resume_solaris (void *p_user_data)
240 {
241 
242   const _img_private_t *p_env = p_user_data;
243   return ioctl(p_env->gen.fd, CDROMRESUME, 0);
244 }
245 
246 /*!
247   Resume playing an audio CD.
248 
249   @param p_cdio the CD object to be acted upon.
250 
251 */
252 static driver_return_code_t
audio_set_volume_solaris(void * p_user_data,cdio_audio_volume_t * p_volume)253 audio_set_volume_solaris (void *p_user_data,
254                           cdio_audio_volume_t *p_volume) {
255 
256   const _img_private_t *p_env = p_user_data;
257   return ioctl(p_env->gen.fd, CDROMVOLCTRL, p_volume);
258 }
259 
260 /*!
261   Stop playing an audio CD.
262 
263   @param p_user_data the CD object to be acted upon.
264 
265 */
266 static driver_return_code_t
audio_stop_solaris(void * p_user_data)267 audio_stop_solaris (void *p_user_data)
268 {
269   const _img_private_t *p_env = p_user_data;
270   return ioctl(p_env->gen.fd, CDROMSTOP);
271 }
272 
273 static int
cdio_decode_btl_number(char ** cpt,int stopper,int * no)274 cdio_decode_btl_number(char **cpt, int stopper, int *no)
275 {
276   *no = 0;
277   for ((*cpt)++; **cpt != stopper; (*cpt)++) {
278     if (**cpt < '0' || **cpt > '9')
279       return 0;
280     *no = *no * 10 + **cpt - '0';
281   }
282   return 1;
283 }
284 
285 /* Read bus, target, lun from name "cXtYdZs2".
286    Return 0 if name is not of the desired form.
287 */
288 static int
cdio_decode_btl_solaris(char * name,int * busno,int * tgtno,int * lunno,int flag)289 cdio_decode_btl_solaris(char *name, int *busno, int *tgtno, int *lunno,
290                         int flag)
291 {
292   char *cpt;
293   int ret;
294 
295   *busno = *tgtno = *lunno = -1;
296   cpt = name;
297   if (*cpt != 'c')
298     return 0;
299   ret = cdio_decode_btl_number(&cpt, 't', busno);
300   if (ret <= 0)
301     return ret;
302   ret = cdio_decode_btl_number(&cpt, 'd', tgtno);
303   if (ret <= 0)
304     return ret;
305   ret = cdio_decode_btl_number(&cpt, 's', lunno);
306   if (ret <= 0)
307     return ret;
308   cpt++;
309   if (*cpt != '2' || *(cpt + 1) != 0)
310     return 0;
311   return 1;
312 }
313 
314 static int
set_scsi_tuple_solaris(_img_private_t * p_env)315 set_scsi_tuple_solaris (_img_private_t *p_env)
316 {
317   int bus_no = -1, host_no = -1, channel_no = -1, target_no = -1, lun_no = -1;
318   int ret;
319   char tuple[160], *cpt;
320 
321   cpt = strrchr(p_env->gen.source_name, '/');
322   if (cpt == NULL)
323     cpt = p_env->gen.source_name;
324   else
325     cpt++;
326   ret = cdio_decode_btl_solaris(cpt, &bus_no, &target_no, &lun_no, 0);
327   if (ret <= 0)
328     return(ret);
329   host_no = bus_no;
330   channel_no = 0;
331   snprintf(tuple, sizeof(tuple)-1, "%d,%d,%d,%d,%d",
332           bus_no, host_no, channel_no, target_no, lun_no);
333   p_env->gen.scsi_tuple = strdup(tuple);
334   return 1;
335 }
336 
337 /*!
338   Initialize CD device.
339  */
340 static bool
init_solaris(_img_private_t * p_env)341 init_solaris (_img_private_t *p_env)
342 {
343   int open_flags = O_RDONLY | O_NDELAY;
344 
345   if (_AM_MMC_RDWR != p_env->access_mode &&
346       _AM_MMC_RDWR_EXCL != p_env->access_mode)
347     /* (was once set to _AM_SUN_CTRL_SCSI unconditionally) */
348     p_env->access_mode = _AM_SUN_CTRL_SCSI;
349 
350   if (!cdio_generic_init(p_env, open_flags))
351     return false;
352   set_scsi_tuple_solaris(p_env);
353   return true;
354 }
355 
356 /*!
357   Run a SCSI MMC command.
358 
359   p_user_data   internal CD structure.
360   i_timeout_ms   time in milliseconds we will wait for the command
361                 to complete.
362   i_cdb         Size of p_cdb
363   p_cdb         CDB bytes.
364   e_direction   direction the transfer is to go.
365   i_buf         Size of buffer
366   p_buf         Buffer for data, both sending and receiving
367  */
368 static driver_return_code_t
run_mmc_cmd_solaris(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)369 run_mmc_cmd_solaris(void *p_user_data, unsigned int i_timeout_ms,
370                     unsigned int i_cdb, const mmc_cdb_t *p_cdb,
371                     cdio_mmc_direction_t e_direction,
372                     unsigned int i_buf, /*in/out*/ void *p_buf)
373 {
374   _img_private_t *p_env = p_user_data;
375   struct uscsi_cmd cgc;
376   int i_rc;
377   cdio_mmc_request_sense_t sense;
378   unsigned char *u_sense = (unsigned char *) &sense;
379 
380   memset (&cgc, 0, sizeof (struct uscsi_cmd));
381   cgc.uscsi_cdb = (caddr_t) p_cdb;
382 
383   /* See: man uscsi
384           http://docs.sun.com/app/docs/doc/816-5177/uscsi-7i?a=view
385   */
386   p_env->gen.scsi_mmc_sense_valid = 0;
387   memset(u_sense, 0, sizeof(sense));
388   cgc.uscsi_rqbuf = (caddr_t) u_sense;
389   cgc.uscsi_rqlen = sizeof(sense);
390 
391   /* No error messages, no retries, do not execute with other commands,
392      request sense data
393   */
394   cgc.uscsi_flags = USCSI_SILENT | USCSI_DIAGNOSE | USCSI_ISOLATE
395                     | USCSI_RQENABLE;
396 
397   if (SCSI_MMC_DATA_READ == e_direction)
398     cgc.uscsi_flags |= USCSI_READ;
399   else if (SCSI_MMC_DATA_WRITE == e_direction)
400     cgc.uscsi_flags |= USCSI_WRITE;
401   cgc.uscsi_timeout = msecs2secs(i_timeout_ms);
402   cgc.uscsi_bufaddr = p_buf;
403   cgc.uscsi_buflen  = i_buf;
404   cgc.uscsi_cdblen  = i_cdb;
405 
406   i_rc = ioctl(p_env->gen.fd, USCSICMD, &cgc);
407 
408   /* Record SCSI sense reply for API call mmc_last_cmd_sense().
409   */
410   if (sense.additional_sense_len) { /* sense data available */
411     int sense_size = sense.additional_sense_len + 8;
412 
413     if (sense_size > sizeof(sense))
414       sense_size = sizeof(sense);
415     memcpy((void *) p_env->gen.scsi_mmc_sense,  &sense, sense_size);
416     p_env->gen.scsi_mmc_sense_valid = sense_size;
417   }
418 
419   if (0 == i_rc) return DRIVER_OP_SUCCESS;
420   if (-1 == i_rc) {
421     cdio_info ("ioctl USCSICMD failed: %s", strerror(errno));
422     switch (errno) {
423     case EPERM:
424       return DRIVER_OP_NOT_PERMITTED;
425       break;
426     case EINVAL:
427       return DRIVER_OP_BAD_PARAMETER;
428       break;
429     case EFAULT:
430       return DRIVER_OP_BAD_POINTER;
431       break;
432     case EIO:
433     default:
434       return DRIVER_OP_ERROR;
435       break;
436     }
437   }
438   else if (i_rc < -1)
439     return DRIVER_OP_ERROR;
440   else
441     /*Not sure if this the best thing, but we'll use anyway. */
442     return DRIVER_OP_SUCCESS;
443 }
444 
445 /*!
446    Reads audio sectors from CD device into data starting from lsn.
447    Returns 0 if no error.
448 
449    May have to check size of nblocks. There may be a limit that
450    can be read in one go, e.g. 25 blocks.
451 */
452 
453 static int
_read_audio_sectors_solaris(void * p_user_data,void * data,lsn_t i_lsn,unsigned int i_blocks)454 _read_audio_sectors_solaris (void *p_user_data, void *data, lsn_t i_lsn,
455                              unsigned int i_blocks)
456 {
457   msf_t _msf;
458   struct cdrom_cdda cdda;
459 
460   _img_private_t *p_env = p_user_data;
461 
462   cdio_lba_to_msf (cdio_lsn_to_lba(i_lsn), &_msf);
463 
464   if (p_env->gen.ioctls_debugged == 75)
465     cdio_debug ("only displaying every 75th ioctl from now on");
466 
467   if (p_env->gen.ioctls_debugged == 30 * 75)
468     cdio_debug ("only displaying every 30*75th ioctl from now on");
469 
470   if (p_env->gen.ioctls_debugged < 75
471       || (p_env->gen.ioctls_debugged < (30 * 75)
472           && p_env->gen.ioctls_debugged % 75 == 0)
473       || p_env->gen.ioctls_debugged % (30 * 75) == 0)
474     cdio_debug ("reading %d", i_lsn);
475 
476   p_env->gen.ioctls_debugged++;
477 
478   if (i_blocks > 60) {
479     cdio_warn("%s:\n",
480               "we can't handle reading more than 60 blocks. Reset to 60");
481   }
482 
483   cdda.cdda_addr    = i_lsn;
484   cdda.cdda_length  = i_blocks;
485   cdda.cdda_data    = (caddr_t) data;
486   cdda.cdda_subcode = CDROM_DA_NO_SUBCODE;
487 
488   if (ioctl (p_env->gen.fd, CDROMCDDA, &cdda) == -1) {
489     perror ("ioctl(..,CDROMCDDA,..)");
490     return DRIVER_OP_ERROR;
491     /* exit (EXIT_FAILURE); */
492   }
493 
494   return DRIVER_OP_SUCCESS;
495 }
496 
497 /*!
498    Reads a single mode1 sector from cd device into data starting
499    from i_lsn.
500  */
501 static driver_return_code_t
_read_mode1_sector_solaris(void * p_env,void * data,lsn_t i_lsn,bool b_form2)502 _read_mode1_sector_solaris (void *p_env, void *data, lsn_t i_lsn,
503                             bool b_form2)
504 {
505 
506 #ifdef FIXED
507   do something here.
508 #else
509   return cdio_generic_read_form1_sector(p_env, data, i_lsn);
510 #endif
511 }
512 
513 /*!
514    Reads i_blocks of mode2 sectors from cd device into data starting
515    from i_lsn.
516  */
517 static driver_return_code_t
_read_mode1_sectors_solaris(void * p_user_data,void * p_data,lsn_t i_lsn,bool b_form2,unsigned int i_blocks)518 _read_mode1_sectors_solaris (void *p_user_data, void *p_data, lsn_t i_lsn,
519                              bool b_form2, unsigned int i_blocks)
520 {
521   _img_private_t *p_env = p_user_data;
522   unsigned int i;
523   int retval;
524   unsigned int blocksize = b_form2 ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE;
525 
526   for (i = 0; i < i_blocks; i++) {
527     if ( (retval = _read_mode1_sector_solaris (p_env,
528                                             ((char *)p_data) + (blocksize * i),
529                                                i_lsn + i, b_form2)) )
530       return retval;
531   }
532   return DRIVER_OP_SUCCESS;
533 }
534 
535 /*!
536    Reads a single mode2 sector from cd device into data starting from lsn.
537  */
538 static driver_return_code_t
_read_mode2_sector_solaris(void * p_user_data,void * p_data,lsn_t i_lsn,bool b_form2)539 _read_mode2_sector_solaris (void *p_user_data, void *p_data, lsn_t i_lsn,
540                             bool b_form2)
541 {
542   char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, };
543   struct cdrom_msf solaris_msf;
544   msf_t _msf;
545   int offset = 0;
546   struct cdrom_cdxa cd_read;
547 
548   _img_private_t *p_env = p_user_data;
549 
550   cdio_lba_to_msf (cdio_lsn_to_lba(i_lsn), &_msf);
551   solaris_msf.cdmsf_min0   = cdio_from_bcd8(_msf.m);
552   solaris_msf.cdmsf_sec0   = cdio_from_bcd8(_msf.s);
553   solaris_msf.cdmsf_frame0 = cdio_from_bcd8(_msf.f);
554 
555   if (p_env->gen.ioctls_debugged == 75)
556     cdio_debug ("only displaying every 75th ioctl from now on");
557 
558   if (p_env->gen.ioctls_debugged == 30 * 75)
559     cdio_debug ("only displaying every 30*75th ioctl from now on");
560 
561   if (p_env->gen.ioctls_debugged < 75
562       || (p_env->gen.ioctls_debugged < (30 * 75)
563           && p_env->gen.ioctls_debugged % 75 == 0)
564       || p_env->gen.ioctls_debugged % (30 * 75) == 0)
565     cdio_debug ("reading %2.2d:%2.2d:%2.2d",
566                 solaris_msf.cdmsf_min0, solaris_msf.cdmsf_sec0,
567                 solaris_msf.cdmsf_frame0);
568 
569   p_env->gen.ioctls_debugged++;
570 
571   /* Using CDROMXA ioctl will actually use the same uscsi command
572    * as ATAPI, except we don't need to be root
573    */
574   offset = CDIO_CD_XA_SYNC_HEADER;
575   cd_read.cdxa_addr = i_lsn;
576   cd_read.cdxa_data = buf;
577   cd_read.cdxa_length = 1;
578   cd_read.cdxa_format = CDROM_XA_SECTOR_DATA;
579   if (ioctl (p_env->gen.fd, CDROMCDXA, &cd_read) == -1) {
580     perror ("ioctl(..,CDROMCDXA,..)");
581     return 1;
582     /* exit (EXIT_FAILURE); */
583   }
584 
585   if (b_form2)
586     memcpy (p_data, buf + (offset-CDIO_CD_SUBHEADER_SIZE), M2RAW_SECTOR_SIZE);
587   else
588     memcpy (((char *)p_data), buf + offset, CDIO_CD_FRAMESIZE);
589 
590   return DRIVER_OP_SUCCESS;
591 }
592 
593 /*!
594    Reads i_blocks of mode2 sectors from cd device into data starting
595    from i_lsn.
596  */
597 static driver_return_code_t
_read_mode2_sectors_solaris(void * p_user_data,void * data,lsn_t i_lsn,bool b_form2,unsigned int i_blocks)598 _read_mode2_sectors_solaris (void *p_user_data, void *data, lsn_t i_lsn,
599                              bool b_form2, unsigned int i_blocks)
600 {
601   _img_private_t *p_env = p_user_data;
602   unsigned int i;
603   int retval;
604   unsigned int blocksize = b_form2 ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE;
605 
606   for (i = 0; i < i_blocks; i++) {
607     if ( (retval = _read_mode2_sector_solaris (p_env,
608                                             ((char *)data) + (blocksize * i),
609                                                i_lsn + i, b_form2)) )
610       return retval;
611   }
612   return 0;
613 }
614 
615 
616 /*!
617    Return the size of the CD in logical block address (LBA) units.
618    @return the size. On error return CDIO_INVALID_LSN.
619  */
620 static lsn_t
get_disc_last_lsn_solaris(void * p_user_data)621 get_disc_last_lsn_solaris (void *p_user_data)
622 {
623   _img_private_t *p_env = p_user_data;
624 
625   struct cdrom_tocentry tocent;
626   uint32_t size;
627 
628   tocent.cdte_track  = CDIO_CDROM_LEADOUT_TRACK;
629   tocent.cdte_format = CDIO_CDROM_LBA;
630   if (ioctl (p_env->gen.fd, CDROMREADTOCENTRY, &tocent) == -1)
631     {
632       perror ("ioctl(CDROMREADTOCENTRY)");
633       exit (EXIT_FAILURE);
634     }
635 
636   size = tocent.cdte_addr.lba;
637 
638   return size;
639 }
640 
641 /*!
642   Set the arg "key" with "value" in the source device.
643   Currently "source" and "access-mode" are valid keys.
644   "source" sets the source device in I/O operations
645   "access-mode" sets the the method of CD access
646 
647   DRIVER_OP_SUCCESS is returned if no error was found,
648   and nonzero if there as an error.
649 */
650 static driver_return_code_t
_set_arg_solaris(void * p_user_data,const char key[],const char value[])651 _set_arg_solaris (void *p_user_data, const char key[], const char value[])
652 {
653   _img_private_t *p_env = p_user_data;
654 
655   if (!strcmp (key, "source"))
656     {
657       if (!value) return DRIVER_OP_ERROR;
658       free (p_env->gen.source_name);
659       p_env->gen.source_name = strdup (value);
660     }
661   else if (!strcmp (key, "access-mode"))
662     {
663       p_env->access_mode = str_to_access_mode_solaris(key);
664     }
665   else return DRIVER_OP_ERROR;
666 
667   return DRIVER_OP_SUCCESS;
668 }
669 
670 /*!
671   Read and cache the CD's Track Table of Contents and track info.
672   Return true if successful or false if an error.
673 */
674 static bool
read_toc_solaris(void * p_user_data)675 read_toc_solaris (void *p_user_data)
676 {
677   _img_private_t *p_env = p_user_data;
678   int i;
679 
680   /* read TOC header */
681   if ( ioctl(p_env->gen.fd, CDROMREADTOCHDR, &p_env->tochdr) == -1 ) {
682     cdio_warn("%s: %s\n",
683             "error in ioctl CDROMREADTOCHDR", strerror(errno));
684     return false;
685   }
686 
687   p_env->gen.i_first_track = p_env->tochdr.cdth_trk0;
688   p_env->gen.i_tracks      = p_env->tochdr.cdth_trk1;
689 
690   /* read individual tracks */
691   for (i=p_env->gen.i_first_track; i<=p_env->gen.i_tracks; i++) {
692     struct cdrom_tocentry *p_toc =
693       &(p_env->tocent[i-p_env->gen.i_first_track]);
694 
695     p_toc->cdte_track = i;
696     p_toc->cdte_format = CDIO_CDROM_MSF;
697     if ( ioctl(p_env->gen.fd, CDROMREADTOCENTRY, p_toc) == -1 ) {
698       cdio_warn("%s %d: %s\n",
699               "error in ioctl CDROMREADTOCENTRY for track",
700               i, strerror(errno));
701       return false;
702     }
703 
704     set_track_flags(&(p_env->gen.track_flags[i]), p_toc->cdte_ctrl);
705   }
706 
707   /* read the lead-out track */
708   p_env->tocent[p_env->tochdr.cdth_trk1].cdte_track = CDIO_CDROM_LEADOUT_TRACK;
709   p_env->tocent[p_env->tochdr.cdth_trk1].cdte_format = CDIO_CDROM_MSF;
710 
711   if (ioctl(p_env->gen.fd, CDROMREADTOCENTRY,
712             &p_env->tocent[p_env->tochdr.cdth_trk1]) == -1 ) {
713     cdio_warn("%s: %s\n",
714              "error in ioctl CDROMREADTOCENTRY for lead-out",
715             strerror(errno));
716     return false;
717   }
718 
719   p_env->gen.toc_init = true;
720   return true;
721 }
722 
723 /*!
724   Eject media in CD drive. If successful, as a side effect we
725   also free obj.
726  */
727 static driver_return_code_t
eject_media_solaris(void * p_user_data)728 eject_media_solaris (void *p_user_data) {
729 
730   _img_private_t *p_env = p_user_data;
731   int ret;
732 
733   close(p_env->gen.fd);
734   p_env->gen.fd = -1;
735   if (p_env->gen.fd > -1) {
736     if ((ret = ioctl(p_env->gen.fd, CDROMEJECT)) != 0) {
737       cdio_generic_free((void *) p_env);
738       cdio_warn ("CDROMEJECT failed: %s\n", strerror(errno));
739       return DRIVER_OP_ERROR;
740     } else {
741       return DRIVER_OP_SUCCESS;
742     }
743   }
744   return DRIVER_OP_ERROR;
745 }
746 
747 static bool
is_mmc_supported(void * user_data)748 is_mmc_supported(void *user_data)
749 {
750     _img_private_t *env = user_data;
751     return (_AM_NONE == env->access_mode) ? false : true;
752 }
753 
754 /*!
755   Return the value associated with the key "arg".
756 */
757 static const char *
get_arg_solaris(void * p_user_data,const char key[])758 get_arg_solaris (void *p_user_data, const char key[])
759 {
760   _img_private_t *p_env = p_user_data;
761 
762   if (!strcmp (key, "source")) {
763     return p_env->gen.source_name;
764   } else if (!strcmp (key, "access-mode")) {
765     switch (p_env->access_mode) {
766     case _AM_SUN_CTRL_ATAPI:
767       return "ATAPI";
768     case _AM_SUN_CTRL_SCSI:
769       return "SCSI";
770     case _AM_MMC_RDWR:
771       return "MMC_RDWR";
772     case _AM_MMC_RDWR_EXCL:
773       return "MMC_RDWR_EXCL";
774     case _AM_NONE:
775       return "no access method";
776     }
777   } else if (!strcmp (key, "scsi-tuple")) {
778     return p_env->gen.scsi_tuple;
779   } else if (!strcmp (key, "mmc-supported?")) {
780     return is_mmc_supported(p_user_data) ? "true" : "false";
781   }
782   return NULL;
783 }
784 
785 /*!
786   Get the block size used in read requests, via ioctl.
787   @return the blocksize if > 0; error if <= 0
788  */
789 static int
get_blocksize_solaris(void * p_user_data)790 get_blocksize_solaris (void *p_user_data) {
791 
792   _img_private_t *p_env = p_user_data;
793   int ret;
794   int i_blocksize;
795 
796   if ( !p_env || p_env->gen.fd <=0 ) return DRIVER_OP_UNINIT;
797   if ((ret = ioctl(p_env->gen.fd, CDROMGBLKMODE, &i_blocksize)) != 0) {
798     cdio_warn ("CDROMGBLKMODE failed: %s\n", strerror(errno));
799     return DRIVER_OP_ERROR;
800   } else {
801     return i_blocksize;
802   }
803 }
804 
805 #ifdef HAVE_SOLARIS_CDROM
806 /*!
807   Return a string containing the default CD device if none is specified.
808   This call does not assume a fixed default drive address but rather uses
809   the first drive that gets enumerated by cdio_get_devices_solaris_cXtYdZs2().
810  */
811 static char *
cdio_get_default_cXtYdZs2(void)812 cdio_get_default_cXtYdZs2(void)
813 {
814   char **devlist, *result = NULL;
815 
816   devlist = cdio_get_devices_solaris_cXtYdZs2(1);
817   if(devlist != NULL) {
818     if(devlist[0] != NULL)
819       result = strdup(devlist[0]);
820     free(devlist);
821   }
822   if(result != NULL)
823     return result;
824   return strdup(DEFAULT_CDIO_DEVICE);
825 }
826 #endif
827 
828 /*!
829   Return a string containing the default CD device if none is specified.
830  */
831 char *
cdio_get_default_device_solaris(void)832 cdio_get_default_device_solaris(void)
833 {
834   char *volume_device;
835   char *volume_name;
836   char *volume_action;
837   char *device;
838   struct stat stb;
839 
840   /* vold and its directory /vol have been replaced by "Tamarack" which
841      is based on hald. This happened in 2006.
842   */
843   if(stat("/vol", &stb) == -1)
844     return cdio_get_default_cXtYdZs2();
845   if((stb.st_mode & S_IFMT) != S_IFDIR)
846     return cdio_get_default_cXtYdZs2();
847 
848   if ((volume_device = getenv("VOLUME_DEVICE")) != NULL &&
849       (volume_name   = getenv("VOLUME_NAME"))   != NULL &&
850       (volume_action = getenv("VOLUME_ACTION")) != NULL &&
851       strcmp(volume_action, "insert") == 0) {
852     uint len = strlen(volume_device) + strlen(volume_name) + 2;
853     device = calloc(1, len);
854     if (device == NULL)
855       return strdup(DEFAULT_CDIO_DEVICE);
856     snprintf(device, len, "%s/%s", volume_device, volume_name);
857     if (stat(device, &stb) != 0 || !S_ISCHR(stb.st_mode)) {
858       free(device);
859       return strdup(DEFAULT_CDIO_DEVICE);
860     }
861     return device;
862   }
863   /* Check if it could be a Solaris media*/
864   if((stat(DEFAULT_CDIO_DEVICE, &stb) == 0) && S_ISDIR(stb.st_mode)) {
865     uint len = strlen(DEFAULT_CDIO_DEVICE + 4);
866     device = calloc(1, len);
867     snprintf(device, len, "%s/s0", DEFAULT_CDIO_DEVICE);
868     return device;
869   }
870   return strdup(DEFAULT_CDIO_DEVICE);
871 }
872 
873 /*!
874   Get disc type associated with cd object.
875 */
876 
877 static discmode_t
get_discmode_solaris(void * p_user_data)878 get_discmode_solaris (void *p_user_data)
879 {
880   _img_private_t *p_env = p_user_data;
881   track_t i_track;
882   discmode_t discmode=CDIO_DISC_MODE_NO_INFO;
883   struct dk_minfo media;
884   int ret;
885 
886   memset(&media, 0, sizeof(media));
887 
888   /* Get the media info */
889   if((ret = ioctl(p_env->gen.fd, DKIOCGMEDIAINFO, &media)) != 0) {
890      cdio_warn ("DKIOCGMEDIAINFO failed: %s\n", strerror(errno));
891          return CDIO_DISC_MODE_NO_INFO;
892   }
893   switch(media.dki_media_type) {
894   case DK_CDROM:
895   case DK_CDR:
896   case DK_CDRW:
897   /* Do cdrom detection */
898   break;
899   case DK_DVDROM:       return CDIO_DISC_MODE_DVD_ROM;
900   case DK_DVDR:         discmode = CDIO_DISC_MODE_DVD_R;
901   break;
902   case DK_DVDRAM:       discmode = CDIO_DISC_MODE_DVD_RAM;
903   break;
904   case DK_DVDRW:
905   case DK_DVDRW+1:      discmode = CDIO_DISC_MODE_DVD_RW;
906   break;
907   default: /* no valid match */
908   return CDIO_DISC_MODE_NO_INFO;
909   }
910 
911   /*
912      GNU/Linux ioctl(.., CDROM_DISC_STATUS) does not return "CD DATA
913      Form 2" for SVCD's even though they are are form 2.
914      Issue a SCSI MMC-2 FULL TOC command first to try get more
915      accurate information.
916   */
917   discmode = mmc_get_discmode(p_env->gen.cdio);
918   if (CDIO_DISC_MODE_NO_INFO != discmode)
919     return discmode;
920 
921   if((discmode == CDIO_DISC_MODE_DVD_RAM ||
922       discmode == CDIO_DISC_MODE_DVD_RW ||
923       discmode == CDIO_DISC_MODE_DVD_R)) {
924     /* Fallback to uscsi if we can */
925     if(geteuid() == 0)
926       return get_discmode_solaris(p_user_data);
927     return discmode;
928   }
929 
930   if (!p_env->gen.toc_init)
931     read_toc_solaris (p_env);
932 
933   if (!p_env->gen.toc_init)
934     return CDIO_DISC_MODE_NO_INFO;
935 
936   for (i_track = p_env->gen.i_first_track;
937        i_track < p_env->gen.i_first_track + p_env->tochdr.cdth_trk1 ;
938        i_track ++) {
939     track_format_t track_fmt=get_track_format_solaris(p_env, i_track);
940 
941     switch(track_fmt) {
942     case TRACK_FORMAT_AUDIO:
943       switch(discmode) {
944         case CDIO_DISC_MODE_NO_INFO:
945           discmode = CDIO_DISC_MODE_CD_DA;
946           break;
947         case CDIO_DISC_MODE_CD_DA:
948         case CDIO_DISC_MODE_CD_MIXED:
949         case CDIO_DISC_MODE_ERROR:
950           /* No change*/
951           break;
952       default:
953           discmode = CDIO_DISC_MODE_CD_MIXED;
954       }
955       break;
956     case TRACK_FORMAT_XA:
957       switch(discmode) {
958         case CDIO_DISC_MODE_NO_INFO:
959           discmode = CDIO_DISC_MODE_CD_XA;
960           break;
961         case CDIO_DISC_MODE_CD_XA:
962         case CDIO_DISC_MODE_CD_MIXED:
963         case CDIO_DISC_MODE_ERROR:
964           /* No change*/
965           break;
966       default:
967         discmode = CDIO_DISC_MODE_CD_MIXED;
968       }
969       break;
970     case TRACK_FORMAT_DATA:
971       switch(discmode) {
972         case CDIO_DISC_MODE_NO_INFO:
973           discmode = CDIO_DISC_MODE_CD_DATA;
974           break;
975         case CDIO_DISC_MODE_CD_DATA:
976         case CDIO_DISC_MODE_CD_MIXED:
977         case CDIO_DISC_MODE_ERROR:
978           /* No change*/
979           break;
980       default:
981         discmode = CDIO_DISC_MODE_CD_MIXED;
982       }
983       break;
984     case TRACK_FORMAT_ERROR:
985     default:
986       discmode = CDIO_DISC_MODE_ERROR;
987     }
988   }
989   return discmode;
990 }
991 
992 /*!
993   Return the session number of the last on the CD.
994 
995   @param p_cdio the CD object to be acted upon.
996   @param i_last_session pointer to the session number to be returned.
997 */
998 static driver_return_code_t
get_last_session_solaris(void * p_user_data,lsn_t * i_last_session_lsn)999 get_last_session_solaris (void *p_user_data,
1000                           /*out*/ lsn_t *i_last_session_lsn)
1001 {
1002   const _img_private_t *p_env = p_user_data;
1003   int i_rc;
1004 
1005   i_rc = ioctl(p_env->gen.fd, CDROMREADOFFSET, &i_last_session_lsn);
1006   if (0 == i_rc) {
1007     return DRIVER_OP_SUCCESS;
1008   } else {
1009     cdio_warn ("ioctl CDROMREADOFFSET failed: %s\n", strerror(errno));
1010     return DRIVER_OP_ERROR;
1011   }
1012 }
1013 
1014 /*!
1015   Get format of track.
1016 */
1017 static track_format_t
get_track_format_solaris(void * p_user_data,track_t i_track)1018 get_track_format_solaris(void *p_user_data, track_t i_track)
1019 {
1020   _img_private_t *p_env = p_user_data;
1021 
1022   if ( !p_env ) return TRACK_FORMAT_ERROR;
1023   if (!p_env->gen.init) init_solaris(p_env);
1024   if (!p_env->gen.toc_init) read_toc_solaris (p_user_data) ;
1025 
1026   if ( (i_track > p_env->gen.i_tracks+p_env->gen.i_first_track)
1027        || i_track < p_env->gen.i_first_track)
1028     return TRACK_FORMAT_ERROR;
1029 
1030   i_track -= p_env->gen.i_first_track;
1031 
1032   /* This is pretty much copied from the "badly broken" cdrom_count_tracks
1033      in linux/cdrom.c.
1034    */
1035   if (p_env->tocent[i_track].cdte_ctrl & CDROM_DATA_TRACK) {
1036     if (p_env->tocent[i_track].cdte_format == CDIO_CDROM_CDI_TRACK)
1037       return TRACK_FORMAT_CDI;
1038     else if (p_env->tocent[i_track].cdte_format == CDIO_CDROM_XA_TRACK)
1039       return TRACK_FORMAT_XA;
1040     else
1041       return TRACK_FORMAT_DATA;
1042   } else
1043     return TRACK_FORMAT_AUDIO;
1044 
1045 }
1046 
1047 /*!
1048   Return true if we have XA data (green, mode2 form1) or
1049   XA data (green, mode2 form2). That is track begins:
1050   sync - header - subheader
1051   12     4      -  8
1052 
1053   FIXME: there's gotta be a better design for this and get_track_format?
1054 */
1055 static bool
get_track_green_solaris(void * p_user_data,track_t i_track)1056 get_track_green_solaris(void *p_user_data, track_t i_track)
1057 {
1058   _img_private_t *p_env = p_user_data;
1059 
1060   if ( !p_env ) return false;
1061   if (!p_env->gen.init) init_solaris(p_env);
1062   if (!p_env->gen.toc_init) read_toc_solaris (p_env) ;
1063 
1064   if (i_track >= p_env->gen.i_tracks+p_env->gen.i_first_track
1065       || i_track < p_env->gen.i_first_track)
1066     return false;
1067 
1068   i_track -= p_env->gen.i_first_track;
1069 
1070   /* FIXME: Dunno if this is the right way, but it's what
1071      I was using in cd-info for a while.
1072    */
1073   return ((p_env->tocent[i_track].cdte_ctrl & 2) != 0);
1074 }
1075 
1076 /*!
1077   Return the starting MSF (minutes/secs/frames) for track number
1078   track_num in obj.  Track numbers usually start at something
1079   greater than 0, usually 1.
1080 
1081   The "leadout" track is specified either by
1082   using track_num LEADOUT_TRACK or the total tracks+1.
1083   False is returned if there is no entry.
1084 */
1085 static bool
get_track_msf_solaris(void * p_user_data,track_t i_track,msf_t * msf)1086 get_track_msf_solaris(void *p_user_data, track_t i_track, msf_t *msf)
1087 {
1088   _img_private_t *p_env = p_user_data;
1089 
1090   if (NULL == msf) return false;
1091 
1092   if (!p_env->gen.init) init_solaris(p_env);
1093   if (!p_env->gen.toc_init) read_toc_solaris (p_env) ;
1094 
1095   if (i_track == CDIO_CDROM_LEADOUT_TRACK)
1096     i_track = p_env->gen.i_tracks + p_env->gen.i_first_track;
1097 
1098   if (i_track > (p_env->gen.i_tracks+p_env->gen.i_first_track)
1099       || i_track < p_env->gen.i_first_track) {
1100     return false;
1101   } else {
1102     struct cdrom_tocentry *msf0 = &p_env->tocent[i_track-1];
1103     msf->m = cdio_to_bcd8(msf0->cdte_addr.msf.minute);
1104     msf->s = cdio_to_bcd8(msf0->cdte_addr.msf.second);
1105     msf->f = cdio_to_bcd8(msf0->cdte_addr.msf.frame);
1106     return true;
1107   }
1108 }
1109 
1110 /*!
1111   Get the block size used in read requests, via ioctl.
1112   @return the blocksize if > 0; error if <= 0
1113  */
1114 static driver_return_code_t
set_blocksize_solaris(void * p_user_data,uint16_t i_blocksize)1115 set_blocksize_solaris (void *p_user_data, uint16_t i_blocksize) {
1116 
1117   _img_private_t *p_env = p_user_data;
1118   int ret;
1119 
1120   if ( !p_env || p_env->gen.fd <=0 ) return DRIVER_OP_UNINIT;
1121   if ((ret = ioctl(p_env->gen.fd,  CDROMSBLKMODE, i_blocksize)) != 0) {
1122     cdio_warn ("CDROMSBLKMODE failed: %s\n", strerror(errno));
1123     return DRIVER_OP_ERROR;
1124   } else {
1125     return DRIVER_OP_SUCCESS;
1126   }
1127 }
1128 
1129 /* Set CD-ROM drive speed */
1130 static driver_return_code_t
set_speed_solaris(void * p_user_data,int i_speed)1131 set_speed_solaris (void *p_user_data, int i_speed)
1132 {
1133   const _img_private_t *p_env = p_user_data;
1134 
1135   if (!p_env) return DRIVER_OP_UNINIT;
1136   return ioctl(p_env->gen.fd, CDROMSDRVSPEED, i_speed);
1137 }
1138 
1139 #else
1140 /*!
1141   Return a string containing the default VCD device if none is specified.
1142  */
1143 char *
cdio_get_default_device_solaris(void)1144 cdio_get_default_device_solaris(void)
1145 {
1146   return strdup(DEFAULT_CDIO_DEVICE);
1147 }
1148 
1149 #endif /* HAVE_SOLARIS_CDROM */
1150 
1151 /*!
1152   Close tray on CD-ROM.
1153 
1154   @param psz_device the CD-ROM drive to be closed.
1155 
1156 */
1157 driver_return_code_t
close_tray_solaris(const char * psz_device)1158 close_tray_solaris (const char *psz_device)
1159 {
1160 #ifdef HAVE_SOLARIS_CDROM
1161   int i_rc;
1162   int fd = open (psz_device, O_RDONLY|O_NONBLOCK);
1163 
1164   if ( fd > -1 ) {
1165     i_rc = DRIVER_OP_SUCCESS;
1166     if((i_rc = ioctl(fd, CDROMSTART)) != 0) {
1167       cdio_warn ("ioctl CDROMSTART failed: %s\n", strerror(errno));
1168       i_rc = DRIVER_OP_ERROR;
1169     }
1170     close(fd);
1171   } else
1172     i_rc = DRIVER_OP_ERROR;
1173   return i_rc;
1174 #else
1175   return DRIVER_OP_NO_DRIVER;
1176 #endif /*HAVE_SOLARIS_CDROM*/
1177 }
1178 
1179 #ifdef HAVE_SOLARIS_CDROM
1180 /*!
1181   Return an array of strings giving possible CD devices.
1182   New method after demise of vold in 2006.
1183  */
1184 /* flag bit0= need only the first drive
1185 */
1186 static char **
cdio_get_devices_solaris_cXtYdZs2(int flag)1187 cdio_get_devices_solaris_cXtYdZs2(int flag)
1188 {
1189   int busno, tgtno, lunno, ret;
1190   char volpath[160];
1191   char **drives = NULL;
1192   unsigned int i_files=0;
1193   DIR *dir = NULL;
1194   struct dirent *entry;
1195 
1196 #ifdef LIBCDIO_SOLARIS_WITH_CD_INQUIRY
1197   CdIo_t *cdio = NULL;
1198   mmc_cdb_t cdb = {{0, }};
1199   int timeout_ms;
1200   driver_return_code_t i_status;
1201   char reply[36];
1202   static unsigned char spc_inquiry[] = { 0x12, 0, 0, 0, 36, 0 };
1203 #else
1204   struct dk_cinfo cinfo;
1205   int fd = -1;
1206 #endif
1207 
1208   static int recursion = 0;
1209 
1210   if (recursion) {
1211     fprintf(stderr, "Program error ! Recursion of cdio_get_devices_solaris_cXtYdZs2()\n");
1212     return NULL;
1213   }
1214   recursion = 1;
1215 
1216   dir = opendir("/dev/rdsk");
1217   if (dir == NULL) {
1218     cdio_warn ("opendir(\"/dev/rdsk\") failed: %s\n", strerror(errno));
1219     goto ex;
1220   }
1221   while (1) {
1222     entry = readdir(dir);
1223     if (entry == NULL) {
1224       if (errno) {
1225         cdio_warn ("readdir(/dev/rdsk) failed: %s\n", strerror(errno));
1226         goto ex;
1227       }
1228   break;
1229     }
1230     ret = cdio_decode_btl_solaris(entry->d_name, &busno, &tgtno, &lunno, 0);
1231     if (ret < 0)
1232       goto ex;
1233     if (ret == 0)
1234   continue; /* not cXtYdZs2 */
1235 
1236     if (strlen(entry->d_name) > sizeof(volpath) - 11)
1237   continue;
1238     snprintf(volpath, sizeof(volpath), "/dev/rdsk/%s", entry->d_name);
1239 
1240 #ifdef LIBCDIO_SOLARIS_WITH_CD_INQUIRY
1241 
1242     cdio = cdio_open_am_solaris(volpath, "MMC_RDWR");
1243     if(cdio == NULL)
1244   continue;
1245     memcpy(cdb.field, spc_inquiry, 6);
1246     timeout_ms = 10000;
1247     i_status = run_mmc_cmd_solaris(cdio->env, timeout_ms,
1248                                    6, &cdb, SCSI_MMC_DATA_READ,
1249                                    (unsigned int) spc_inquiry[4], reply);
1250     cdio_destroy(cdio);
1251     cdio = NULL;
1252     if (i_status != 0)
1253   continue;
1254 
1255     /* SBC-3 , table 83 , PERIPHERAL DEVICE TYPE : 5 = CD/DVD device */
1256     if((reply[0] & 0x1F) != 5)
1257   continue;
1258 
1259 #else /* LIBCDIO_SOLARIS_WITH_CD_INQUIRY */
1260 
1261     fd = open(volpath, O_RDONLY | O_NDELAY);
1262     if (fd < 0)
1263   continue;
1264     /* See man dkio */
1265     ret = ioctl(fd, DKIOCINFO, &cinfo);
1266     close(fd);
1267     fd = -1;
1268     if (ret < 0)
1269   continue;
1270     if (cinfo.dki_ctype != DKC_CDROM)
1271   continue;
1272 
1273 #endif /* ! LIBCDIO_SOLARIS_WITH_CD_INQUIRY */
1274 
1275     cdio_add_device_list(&drives, volpath, &i_files);
1276     if(flag & 1)
1277       goto ex; /* Only the first drive is desired */
1278   }
1279 ex:;
1280   recursion = 0;
1281   if(dir != NULL)
1282     closedir(dir);
1283   cdio_add_device_list(&drives, NULL, &i_files);
1284   return drives;
1285 }
1286 #endif /*HAVE_SOLARIS_CDROM*/
1287 
1288 /*!
1289   Return an array of strings giving possible CD devices.
1290  */
1291 char **
cdio_get_devices_solaris(void)1292 cdio_get_devices_solaris (void)
1293 {
1294 #ifndef HAVE_SOLARIS_CDROM
1295   return NULL;
1296 #else
1297   char volpath[256];
1298   struct stat st;
1299   char **drives = NULL;
1300   unsigned int i_files=0;
1301 #ifdef HAVE_GLOB_H
1302   unsigned int i;
1303   glob_t globbuf;
1304 #endif
1305 
1306   /* vold and its directory /vol have been replaced by "Tamarack" which
1307      is based on hald. This happened in 2006.
1308   */
1309   if(stat("/vol", &st) == -1)
1310     return cdio_get_devices_solaris_cXtYdZs2(0);
1311   if((st.st_mode & S_IFMT) != S_IFDIR)
1312     return cdio_get_devices_solaris_cXtYdZs2(0);
1313 
1314 #ifdef HAVE_GLOB_H
1315 
1316   globbuf.gl_offs = 0;
1317   glob("/vol/dev/aliases/cdrom*", GLOB_DOOFFS, NULL, &globbuf);
1318   for (i=0; i<globbuf.gl_pathc; i++) {
1319     if(stat(globbuf.gl_pathv[i], &st) < 0)
1320       continue;
1321 
1322     /* Check if this is a directory, if so it's probably Solaris media */
1323     if(S_ISDIR(st.st_mode)) {
1324       snprintf(volpath, sizeof(volpath), "%s/s0", globbuf.gl_pathv[i]);
1325       if(stat(volpath, &st) == 0)
1326         cdio_add_device_list(&drives, volpath, &i_files);
1327         }else
1328       cdio_add_device_list(&drives, globbuf.gl_pathv[i], &i_files);
1329   }
1330   globfree(&globbuf);
1331 #else
1332   if(stat(DEFAULT_CDIO_DEVICE, &st) == 0) {
1333     /* Check if this is a directory, if so it's probably Solaris media */
1334     if(S_ISDIR(st.st_mode)) {
1335       snprintf(volpath, sizeof(volpath), "%s/s0", DEFAULT_CDIO_DEVICE);
1336       if(stat(volpath, &st) == 0)
1337         cdio_add_device_list(&drives, volpath, &i_files);
1338     }else
1339       cdio_add_device_list(&drives, DEFAULT_CDIO_DEVICE, &i_files);
1340   }
1341 #endif /*HAVE_GLOB_H*/
1342   cdio_add_device_list(&drives, NULL, &i_files);
1343   return drives;
1344 #endif /*HAVE_SOLARIS_CDROM*/
1345 }
1346 
1347 /*!
1348   Initialization routine. This is the only thing that doesn't
1349   get called via a function pointer. In fact *we* are the
1350   ones to set that up.
1351  */
1352 CdIo *
cdio_open_solaris(const char * psz_source_name)1353 cdio_open_solaris (const char *psz_source_name)
1354 {
1355   return cdio_open_am_solaris(psz_source_name, NULL);
1356 }
1357 
1358 /*!
1359   Initialization routine. This is the only thing that doesn't
1360   get called via a function pointer. In fact *we* are the
1361   ones to set that up.
1362  */
1363 CdIo *
cdio_open_am_solaris(const char * psz_orig_source,const char * access_mode)1364 cdio_open_am_solaris (const char *psz_orig_source, const char *access_mode)
1365 {
1366 
1367 #ifdef HAVE_SOLARIS_CDROM
1368   CdIo *ret;
1369   _img_private_t *_data;
1370   char *psz_source;
1371 
1372   cdio_funcs_t _funcs;
1373 
1374   memset(&_funcs, 0, sizeof(_funcs));
1375 
1376   _funcs.audio_pause            = audio_pause_solaris;
1377   _funcs.audio_play_msf         = audio_play_msf_solaris;
1378   _funcs.audio_play_track_index = audio_play_track_index_solaris;
1379   _funcs.audio_read_subchannel  = audio_read_subchannel_solaris;
1380   _funcs.audio_resume           = audio_resume_solaris;
1381   _funcs.audio_set_volume       = audio_set_volume_solaris;
1382   _funcs.audio_stop             = audio_stop_solaris,
1383   _funcs.eject_media            = eject_media_solaris;
1384   _funcs.free                   = cdio_generic_free;
1385   _funcs.get_arg                = get_arg_solaris;
1386 #ifdef USE_MMC
1387   _funcs.get_blocksize          = get_blocksize_mmc;
1388 #else
1389   _funcs.get_blocksize          = get_blocksize_solaris;
1390 #endif
1391   _funcs.get_cdtext             = get_cdtext_generic;
1392   _funcs.get_cdtext_raw         = read_cdtext_generic;
1393   _funcs.get_default_device     = cdio_get_default_device_solaris;
1394   _funcs.get_devices            = cdio_get_devices_solaris;
1395   _funcs.get_disc_last_lsn      = get_disc_last_lsn_solaris;
1396   _funcs.get_discmode           = get_discmode_solaris;
1397   _funcs.get_drive_cap          = get_drive_cap_mmc;
1398   _funcs.get_first_track_num    = get_first_track_num_generic;
1399   _funcs.get_hwinfo             = NULL;
1400   _funcs.get_last_session       = get_last_session_solaris;
1401   _funcs.get_media_changed      = get_media_changed_mmc,
1402   _funcs.get_mcn                = get_mcn_mmc,
1403   _funcs.get_num_tracks         = get_num_tracks_generic;
1404   _funcs.get_track_channels     = get_track_channels_generic,
1405   _funcs.get_track_copy_permit  = get_track_copy_permit_generic,
1406   _funcs.get_track_format       = get_track_format_solaris;
1407   _funcs.get_track_green        = get_track_green_solaris;
1408   _funcs.get_track_lba          = NULL; /* This could be done if need be. */
1409   _funcs.get_track_preemphasis  = get_track_preemphasis_generic,
1410   _funcs.get_track_msf          = get_track_msf_solaris;
1411   _funcs.get_track_isrc         = get_track_isrc_solaris;
1412   _funcs.lseek                  = cdio_generic_lseek;
1413   _funcs.read                   = cdio_generic_read;
1414   _funcs.read_audio_sectors     = _read_audio_sectors_solaris;
1415   _funcs.read_data_sectors      = read_data_sectors_generic;
1416   _funcs.read_mode1_sector      = _read_mode1_sector_solaris;
1417   _funcs.read_mode1_sectors     = _read_mode1_sectors_solaris;
1418   _funcs.read_mode2_sector      = _read_mode2_sector_solaris;
1419   _funcs.read_mode2_sectors     = _read_mode2_sectors_solaris;
1420   _funcs.read_toc               = read_toc_solaris;
1421   _funcs.run_mmc_cmd            = run_mmc_cmd_solaris;
1422   _funcs.set_arg                = _set_arg_solaris;
1423 #ifdef USE_MMC
1424   _funcs.set_blocksize          = set_blocksize_mmc;
1425 #else
1426   _funcs.set_blocksize          = set_blocksize_solaris;
1427 #endif
1428   _funcs.set_speed              = set_speed_solaris;
1429 
1430   _data                         = calloc(1, sizeof (_img_private_t));
1431 
1432   _data->access_mode    = str_to_access_mode_solaris(access_mode);
1433   _data->gen.init       = false;
1434   _data->gen.fd         = -1;
1435   _data->gen.toc_init   = false;
1436   _data->gen.b_cdtext_error = false;
1437 
1438   if (NULL == psz_orig_source) {
1439     psz_source = cdio_get_default_device_solaris();
1440     if (NULL == psz_source) {
1441       free(_data);
1442       return NULL;
1443     }
1444 
1445     _set_arg_solaris(_data, "source", psz_source);
1446     free(psz_source);
1447   } else {
1448     if (cdio_is_device_generic(psz_orig_source))
1449       _set_arg_solaris(_data, "source", psz_orig_source);
1450     else {
1451       /* The below would be okay if all device drivers worked this way. */
1452 #if 0
1453       cdio_info ("source %s is not a device", psz_orig_source);
1454 #endif
1455       free(_data);
1456       return NULL;
1457     }
1458   }
1459 
1460   ret = cdio_new ( (void *) _data, &_funcs );
1461   if (ret == NULL) return NULL;
1462 
1463   ret->driver_id = DRIVER_SOLARIS;
1464 
1465   if (init_solaris(_data))
1466     return ret;
1467   else {
1468     cdio_generic_free (_data);
1469     free(ret);
1470     return NULL;
1471   }
1472 
1473 #else
1474   return NULL;
1475 #endif /* HAVE_SOLARIS_CDROM */
1476 
1477 }
1478 
1479 bool
cdio_have_solaris(void)1480 cdio_have_solaris (void)
1481 {
1482 #ifdef HAVE_SOLARIS_CDROM
1483   return true;
1484 #else
1485   return false;
1486 #endif /* HAVE_SOLARIS_CDROM */
1487 }
1488