Imported Upstream version 1.1.11
[platform/upstream/cdrkit.git] / icedax / interface.c
1 /*
2  * This file has been modified for the cdrkit suite.
3  *
4  * The behaviour and appearence of the program code below can differ to a major
5  * extent from the version distributed by the original author(s).
6  *
7  * For details, see Changelog file distributed with the cdrkit package. If you
8  * received this file from another source then ask the distributing person for
9  * a log of modifications.
10  *
11  */
12
13 /* @(#)interface.c      1.40 06/02/19 Copyright 1998-2002 Heiko Eissfeldt, Copyright 2006 J. Schilling */
14 /***
15  * CopyPolicy: GNU Public License 2 applies
16  * Copyright (C) 1994-1997 Heiko Eissfeldt heiko@colossus.escape.de
17  *
18  * Interface module for cdrom drive access
19  *
20  * Two interfaces are possible.
21  *
22  * 1. using 'cooked' ioctls() (Linux only)
23  *    : available for atapi, sbpcd and cdu31a drives only.
24  *
25  * 2. using the generic scsi device (for details see SCSI Prog. HOWTO).
26  *    NOTE: a bug/misfeature in the kernel requires blocking signal
27  *          SIGINT during SCSI command handling. Once this flaw has
28  *          been removed, the sigprocmask SIG_BLOCK and SIG_UNBLOCK calls
29  *          should removed, thus saving context switches.
30  *
31  * For testing purposes I have added a third simulation interface.
32  *
33  * Version 0.8: used experiences of Jochen Karrer.
34  *              SparcLinux port fixes
35  *              AlphaLinux port fixes
36  *
37  */
38 #if 0
39 #define SIM_CD
40 #endif
41
42 #include "config.h"
43 #include <stdio.h>
44 #include <standard.h>
45 #include <stdxlib.h>
46 #include <unixstd.h>
47 #include <strdefs.h>
48 #include <errno.h>
49 #include <signal.h>
50 #include <fctldefs.h>
51 #include <assert.h>
52 #include <schily.h>
53 #include <device.h>
54
55 #include <sys/ioctl.h>
56 #include <statdefs.h>
57
58
59 #include "mycdrom.h"
60 #include "lowlevel.h"
61 /* some include file locations have changed with newer kernels */
62 #if defined (__linux__)
63 # if LINUX_VERSION_CODE > 0x10300 + 97
64 #  if LINUX_VERSION_CODE < 0x200ff
65 #   include <linux/sbpcd.h>
66 #   include <linux/ucdrom.h>
67 #  endif
68 #  if !defined(CDROM_SELECT_SPEED)
69 #   include <linux/ucdrom.h>
70 #  endif
71 # endif
72 #endif
73
74 #include <usal/scsitransp.h>
75
76 #include "mytype.h"
77 #include "byteorder.h"
78 #include "interface.h"
79 #include "icedax.h"
80 #include "semshm.h"
81 #include "setuid.h"
82 #include "ringbuff.h"
83 #include "toc.h"
84 #include "global.h"
85 #include "ioctl.h"
86 #include "exitcodes.h"
87 #include "scsi_cmds.h"
88
89 #include <utypes.h>
90 #include <wodim.h>
91 #include "scsi_scan.h"
92
93 unsigned interface;
94
95 int trackindex_disp = 0;
96
97 void    priv_init(void);
98 void    priv_on(void);
99 void    priv_off(void);
100
101 void            (*EnableCdda)(SCSI *, int Switch, unsigned uSectorsize);
102 unsigned (*doReadToc)(SCSI *usalp);
103 void            (*ReadTocText)(SCSI *usalp);
104 unsigned (*ReadLastAudio)(SCSI *usalp);
105 int      (*ReadCdRom)(SCSI *usalp, UINT4 *p, unsigned lSector, 
106                                                          unsigned SectorBurstVal);
107 int      (*ReadCdRomData)(SCSI *usalp, unsigned char *p, unsigned lSector, 
108                                                                   unsigned SectorBurstVal);
109 int      (*ReadCdRomSub)(SCSI *usalp, UINT4 *p, unsigned lSector, 
110                                                                  unsigned SectorBurstVal);
111 subq_chnl *(*ReadSubChannels)(SCSI *usalp, unsigned lSector);
112 subq_chnl *(*ReadSubQ)(SCSI *usalp, unsigned char sq_format, 
113                                                           unsigned char track);
114 void     (*SelectSpeed)(SCSI *usalp, unsigned speed);
115 int             (*Play_at)(SCSI *usalp, unsigned int from_sector, unsigned int sectors);
116 int             (*StopPlay)(SCSI *usalp);
117 void            (*trash_cache)(UINT4 *p, unsigned lSector, unsigned SectorBurstVal);
118
119 #if     defined USE_PARANOIA
120 long cdda_read(void *d, void *buffer, long beginsector, long sectors);
121
122 long cdda_read(void *d, void *buffer, long beginsector, long sectors)
123 {
124         long ret = ReadCdRom(d, buffer, beginsector, sectors);
125         return ret;
126 }
127 #endif
128
129 typedef struct string_len {
130   char *str;
131   unsigned int sl;
132 } mystring;
133
134 static mystring drv_is_not_mmc[] = {
135         {"DEC     RRD47   (C) DEC ",24},
136 /*      {"SONY    CD-ROM CDU625    1.0",28}, */
137         {NULL,0}        /* must be last entry */
138 };
139
140 static mystring drv_has_mmc_cdda[] = {
141         {"HITACHI CDR-7930",16},
142 /*      {"TOSHIBA CD-ROM XM-5402TA3605",28}, */
143         {NULL,0}        /* must be last entry */
144 };
145
146 static int      Is_a_Toshiba3401;
147
148 int Toshiba3401(void);
149
150 int Toshiba3401() 
151 {
152   return Is_a_Toshiba3401;
153 }
154
155 /* hook */
156 static void Dummy(void);
157 static void Dummy()
158 {
159 }
160
161 static SCSI    *usalp;
162
163 SCSI *get_scsi_p(void);
164
165 SCSI *get_scsi_p()
166 {
167     return usalp;
168 }
169
170 #if !defined(SIM_CD)
171
172 static void trash_cache_SCSI(UINT4 *p, unsigned lSector, 
173                                                                           unsigned SectorBurstVal);
174
175 static void trash_cache_SCSI(UINT4 *p, unsigned lSector, 
176                                                                           unsigned SectorBurstVal)
177 {
178       /* trash the cache */
179       ReadCdRom(get_scsi_p(), p, find_an_off_sector(lSector, SectorBurstVal), min(global.nsectors,6));
180 }
181
182
183
184 static void Check_interface_for_device(struct stat *statstruct, 
185                                                                                                         char *pdev_name);
186 static int OpenCdRom(char *pdev_name);
187
188 static void SetupSCSI(void);
189
190 static void SetupSCSI()
191 {
192     unsigned char *p;
193
194     if (interface != GENERIC_SCSI) {
195         /* unfortunately we have the wrong interface and are
196          * not able to change on the fly */
197         fprintf(stderr, "The generic SCSI interface and devices are required\n");
198         exit(SYNTAX_ERROR);
199     }
200
201     /* do a test unit ready to 'init' the device. */
202     TestForMedium(usalp);
203
204     /* check for the correct type of unit. */
205     p = Inquiry(usalp);
206
207 #undef TYPE_ROM
208 #define TYPE_ROM 5
209 #undef TYPE_WORM
210 #define TYPE_WORM  4
211     if (p == NULL) {
212         fprintf(stderr, "Inquiry command failed. Aborting...\n");
213         exit(DEVICE_ERROR);
214     }
215
216     if ((*p != TYPE_ROM && *p != TYPE_WORM)) {
217         fprintf(stderr, "this is neither a scsi cdrom nor a worm device\n");
218         exit(SYNTAX_ERROR);
219     }
220
221     if (global.quiet == 0) {
222         fprintf(stderr,
223                  "Type: %s, Vendor '%8.8s' Model '%16.16s' Revision '%4.4s' ",
224                  *p == TYPE_ROM ? "ROM" : "WORM"
225                  ,p+8
226                  ,p+16
227                  ,p+32);
228     }
229     /* generic Sony type defaults */
230     density = 0x0;
231     accepts_fua_bit = -1;
232     EnableCdda = (void (*)(SCSI *, int, unsigned))Dummy;
233     ReadCdRom = ReadCdda12;
234     ReadCdRomSub = ReadCddaSubSony;
235     ReadCdRomData = (int (*)(SCSI *, unsigned char *, unsigned, unsigned))ReadStandardData;
236     ReadLastAudio = ReadFirstSessionTOCSony;
237     SelectSpeed = SpeedSelectSCSISony;
238     Play_at = Play_atSCSI;
239     StopPlay = StopPlaySCSI;
240     trash_cache = trash_cache_SCSI;
241     ReadTocText = ReadTocTextSCSIMMC;
242     doReadToc = ReadTocSCSI;
243     ReadSubQ = ReadSubQSCSI;
244     ReadSubChannels = NULL;
245
246     /* check for brands and adjust special peculiaritites */
247
248     /* If your drive is not treated correctly, you can adjust some things
249        here:
250
251        global.in_lendian: should be to 1, if the CDROM drive or CD-Writer
252                   delivers the samples in the native byteorder of the audio cd
253                   (LSB first).
254                   HP CD-Writers need it set to 0.
255        NOTE: If you get correct wav files when using sox with the '-x' option,
256              the endianess is wrong. You can use the -C option to specify
257              the value of global.in_lendian.
258
259      */
260
261     {
262       int mmc_code;
263
264       usalp->silent ++;
265       allow_atapi(usalp, 1);
266       if (*p == TYPE_ROM) {
267         mmc_code = heiko_mmc(usalp);
268       } else {
269         mmc_code = 0;
270       }
271       usalp->silent --;
272
273       /* Exceptions for drives that report incorrect MMC capability */
274       if (mmc_code != 0) {
275         /* these drives are NOT capable of MMC commands */
276         mystring *pp = drv_is_not_mmc;
277         while (pp->str != NULL) {
278           if (!strncmp(pp->str, (char *)p+8,pp->sl)) {
279             mmc_code = 0;
280             break;
281           }
282           pp++;
283         }
284       }
285       {
286         /* these drives flag themselves as non-MMC, but offer CDDA reading
287            only with a MMC method. */
288         mystring *pp = drv_has_mmc_cdda;
289         while (pp->str != NULL) {
290           if (!strncmp(pp->str, (char *)p+8,pp->sl)) {
291             mmc_code = 1;
292             break;
293           }
294           pp++;
295         }
296       }
297
298       switch (mmc_code) {
299        case 2:      /* SCSI-3 cdrom drive with accurate audio stream */
300         /* fall through */
301        case 1:      /* SCSI-3 cdrom drive with no accurate audio stream */
302         /* fall through */
303 lost_toshibas:
304          global.in_lendian = 1;
305          if (mmc_code == 2)
306            global.overlap = 0;
307          else
308            global.overlap = 1;
309          ReadCdRom = ReadCddaFallbackMMC;
310          ReadCdRomSub = ReadCddaSubSony;
311          ReadLastAudio = ReadFirstSessionTOCMMC;
312          SelectSpeed = SpeedSelectSCSIMMC;
313          ReadTocText = ReadTocTextSCSIMMC;
314          doReadToc = ReadTocMMC;
315          ReadSubChannels = ReadSubChannelsFallbackMMC;
316          if (!memcmp(p+8,"SONY    CD-RW  CRX100E  1.0", 27)) ReadTocText = NULL;
317          if (!global.quiet) fprintf(stderr, "MMC+CDDA\n");
318        break;
319        case -1: /* "MMC drive does not support cdda reading, sorry\n." */
320          doReadToc = ReadTocMMC;
321          if (!global.quiet) fprintf(stderr, "MMC-CDDA\n");
322          /* FALLTHROUGH */
323        case 0:      /* non SCSI-3 cdrom drive */
324          if (!global.quiet) fprintf(stderr, "no MMC\n");
325          ReadLastAudio = NULL;
326     if (!memcmp(p+8,"TOSHIBA", 7) ||
327         !memcmp(p+8,"IBM", 3) ||
328         !memcmp(p+8,"DEC", 3)) {
329             /*
330              * older Toshiba ATAPI drives don't identify themselves as MMC.
331              * The last digit of the model number is '2' for ATAPI drives.
332              * These are treated as MMC.
333              */
334             if (!memcmp(p+15, " CD-ROM XM-", 11) && p[29] == '2') {
335                 goto lost_toshibas;
336             }
337         density = 0x82;
338         EnableCdda = EnableCddaModeSelect;
339         ReadSubChannels = ReadStandardSub;
340         ReadCdRom = ReadStandard;
341         SelectSpeed = SpeedSelectSCSIToshiba;
342         if (!memcmp(p+15, " CD-ROM XM-3401",15)) {
343            Is_a_Toshiba3401 = 1;
344         }
345         global.in_lendian = 1;
346     } else if (!memcmp(p+8,"IMS",3) ||
347                !memcmp(p+8,"KODAK",5) ||
348                !memcmp(p+8,"RICOH",5) ||
349                !memcmp(p+8,"HP",2) ||
350                !memcmp(p+8,"PHILIPS",7) ||
351                !memcmp(p+8,"PLASMON",7) ||
352                !memcmp(p+8,"GRUNDIG CDR100IPW",17) ||
353                !memcmp(p+8,"MITSUMI CD-R ",13)) {
354         EnableCdda = EnableCddaModeSelect;
355         ReadCdRom = ReadStandard;
356         SelectSpeed = SpeedSelectSCSIPhilipsCDD2600;
357
358         /* treat all of these as bigendian */
359         global.in_lendian = 0;
360
361         /* no overlap reading for cd-writers */
362         global.overlap = 0;
363     } else if (!memcmp(p+8,"NRC",3)) {
364         SelectSpeed = NULL;
365     } else if (!memcmp(p+8,"YAMAHA",6)) {
366         EnableCdda = EnableCddaModeSelect;
367         SelectSpeed = SpeedSelectSCSIYamaha;
368
369         /* no overlap reading for cd-writers */
370         global.overlap = 0;
371         global.in_lendian = 1;
372     } else if (!memcmp(p+8,"PLEXTOR",7)) {
373         global.in_lendian = 1;
374         global.overlap = 0;
375         ReadLastAudio = ReadFirstSessionTOCSony;
376         ReadTocText = ReadTocTextSCSIMMC;
377         doReadToc = ReadTocSony;
378         ReadSubChannels = ReadSubChannelsSony;
379     } else if (!memcmp(p+8,"SONY",4)) {
380         global.in_lendian = 1;
381         if (!memcmp(p+16, "CD-ROM CDU55E",13)) {
382            ReadCdRom = ReadCddaMMC12;
383         }
384         ReadLastAudio = ReadFirstSessionTOCSony;
385         ReadTocText = ReadTocTextSCSIMMC;
386         doReadToc = ReadTocSony;
387         ReadSubChannels = ReadSubChannelsSony;
388     } else if (!memcmp(p+8,"NEC",3)) {
389         ReadCdRom = ReadCdda10;
390         ReadTocText = NULL;
391         SelectSpeed = SpeedSelectSCSINEC;
392         global.in_lendian = 1;
393         if (!memcmp(p+29,"5022.0r",3)) /* I assume all versions of the 502 require this? */
394                global.overlap = 0;           /* no overlap reading for NEC CD-ROM 502 */
395     } else if (!memcmp(p+8,"MATSHITA",8)) {
396         ReadCdRom = ReadCdda12Matsushita;
397         global.in_lendian = 1;
398     }
399     } /* switch (get_mmc) */
400     }
401
402
403     /* look if caddy is loaded */
404     if (interface == GENERIC_SCSI) {
405         usalp->silent++;
406         while (!wait_unit_ready(usalp, 60)) {
407                 fprintf(stderr,"load cdrom please and press enter");
408                 getchar();
409         }
410         usalp->silent--;
411     }
412 }
413
414 /* Check to see if the device will support SCSI generic commands. A
415  * better check than simply looking at the device name. Open the
416  * device, issue an inquiry. If they both succeed, there's a good
417  * chance that the device works... */
418 #if defined(__linux__)
419 static int check_linux_scsi_interface(char *pdev_name)
420 {
421     SCSI *dev = NULL;
422     unsigned char *p = NULL;
423         char    errstr[80];
424     
425         dev = usal_open(pdev_name, errstr, sizeof(errstr), 0, 0);
426     if (NULL == dev)
427         return EINVAL;
428     p = Inquiry(dev);
429     if (p)
430     {
431         usal_close(dev);
432         return 0;
433     }
434     usal_close(dev);
435     return EINVAL;
436 }
437 #endif
438
439 /********************** General setup *******************************/
440
441 /* As the name implies, interfaces and devices are checked.  We also
442    adjust nsectors, overlap, and interface for the first time here.
443    Any unnecessary privileges (setuid, setgid) are also dropped here.
444 */
445 static void Check_interface_for_device(struct stat *statstruct, char *pdev_name)
446 {
447 #if defined(__linux__)
448     int is_scsi = 1;
449 #endif
450 #ifndef STAT_MACROS_BROKEN
451     if (!S_ISCHR(statstruct->st_mode) &&
452         !S_ISBLK(statstruct->st_mode)) {
453       fprintf(stderr, "%s is not a device\n",pdev_name);
454       exit(SYNTAX_ERROR);
455     }
456 #endif
457
458 /* Check what type of device we have */
459 #if defined (__linux__)
460     if (check_linux_scsi_interface(pdev_name))
461         is_scsi = 0;
462     if (interface == GENERIC_SCSI && !is_scsi)
463     {
464         fprintf(stderr, "device %s does not support generic_scsi; falling back to cooked_ioctl instead\n", pdev_name);
465         interface = COOKED_IOCTL;
466     }
467     if ((interface == COOKED_IOCTL) &&
468         is_scsi &&
469         (SCSI_GENERIC_MAJOR == major(statstruct->st_rdev)))
470     {
471         fprintf(stderr, "device %s is generic_scsi NOT cooked_ioctl\n", pdev_name);
472         interface = GENERIC_SCSI;
473     }
474 #else
475     
476 #if defined (HAVE_ST_RDEV)
477     switch (major(statstruct->st_rdev)) {
478 #if defined (__linux__)
479     case SCSI_GENERIC_MAJOR:    /* generic */
480 #else
481     default:                    /* ??? what is the proper value here */
482 #endif
483 #ifndef STAT_MACROS_BROKEN
484 #if defined (__linux__)
485        if (!S_ISCHR(statstruct->st_mode)) {
486          fprintf(stderr, "%s is not a char device\n",pdev_name);
487          exit(SYNTAX_ERROR);
488        }
489
490        if (interface != GENERIC_SCSI) {
491          fprintf(stderr, "wrong interface (cooked_ioctl) for this device (%s)\nset to generic_scsi\n", pdev_name);
492          interface = GENERIC_SCSI;
493        }
494 #endif
495 #else
496     default:                    /* ??? what is the proper value here */
497 #endif
498        break;
499
500 #if defined (__linux__) || defined (__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
501 #if defined (__linux__)
502     case SCSI_CDROM_MAJOR:     /* scsi cd */
503     default:                    /* for example ATAPI cds */
504 #else
505 #if defined (__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
506 #if __FreeBSD_version >= 600021
507     case 0:     /* majors abandoned */
508         /* FALLTHROUGH */
509 #endif
510 #if __FreeBSD_version >= 501113
511     case 4:     /* GEOM */
512         /* FALLTHROUGH */
513 #endif
514     case 117:   /* pre-GEOM atapi cd */
515         if (!S_ISCHR(statstruct->st_mode)) {
516             fprintf(stderr, "%s is not a char device\n",pdev_name);
517             exit(SYNTAX_ERROR);
518         }
519         if (interface != COOKED_IOCTL) {
520             fprintf(stderr,
521 "cdrom device (%s) is not of type generic SCSI. \
522 Setting interface to cooked_ioctl.\n", pdev_name);
523             interface = COOKED_IOCTL;
524         }
525         break;
526     case 19:     /* first atapi cd */
527 #endif
528 #endif
529         if (!S_ISBLK(statstruct->st_mode)) {
530             fprintf(stderr, "%s is not a block device\n",pdev_name);
531             exit(SYNTAX_ERROR);
532         }
533 #if defined (__linux__)
534 #if LINUX_VERSION_CODE >= 0x20600
535         /* In Linux kernel 2.6 it is better to use the SCSI interface
536          * with the device.
537          */
538         break;
539 #endif
540 #endif
541         if (interface != COOKED_IOCTL) {
542             fprintf(stderr, 
543 "cdrom device (%s) is not of type generic SCSI. \
544 Setting interface to cooked_ioctl.\n", pdev_name);
545             interface = COOKED_IOCTL;
546         }
547
548         if (interface == COOKED_IOCTL) {
549                 fprintf(stderr, "\nW: The cooked_ioctl interface is functionally very limited!!\n");
550 #if     defined (__linux__)
551                 fprintf(stderr, "\nW: For good sampling quality simply use the generic SCSI interface!\n"
552                                 "For example dev=ATA:1,0,0\n");
553 #endif
554         }
555
556         break;
557 #endif
558     }
559 #endif
560 #endif 
561     if (global.overlap >= global.nsectors)
562       global.overlap = global.nsectors-1;
563 }
564
565 /* open the cdrom device */
566 static int OpenCdRom(char *pdev_name)
567 {
568   int retval = 0;
569   struct stat fstatstruct;
570
571   /*  The device (given by pdevname) can be:
572       a. an SCSI device specified with a /dev/xxx name,
573       b. an SCSI device specified with bus,target,lun numbers,
574       c. a non-SCSI device such as ATAPI or proprietary CDROM devices.
575    */
576 #ifdef HAVE_IOCTL_INTERFACE
577   struct stat statstruct;
578   int have_named_device = 0;
579
580         have_named_device = FALSE;
581         if (pdev_name) {
582                 have_named_device = strchr(pdev_name, ':') == NULL
583                                         && memcmp(pdev_name, "/dev/", 5) == 0;
584         }
585
586   if (have_named_device) {
587     if (stat(pdev_name, &statstruct)) {
588       fprintf(stderr, "cannot stat device %s\n", pdev_name);
589       exit(STAT_ERROR);
590     } else {
591       Check_interface_for_device( &statstruct, pdev_name );
592     }
593   }
594 #endif
595
596   if (interface == GENERIC_SCSI) {
597         char    errstr[80];
598
599         priv_on();
600         needroot(0);
601         needgroup(0);
602         /*
603          * Call usal_remote() to force loading the remote SCSI transport library
604          * code that is located in librusal instead of the dummy remote routines
605          * that are located inside libusal.
606          */
607         usal_remote();
608         if (pdev_name != NULL &&
609             ((strncmp(pdev_name, "HELP", 4) == 0) ||
610              (strncmp(pdev_name, "help", 4) == 0))) {
611                 usal_help(stderr);
612                 exit(NO_ERROR);
613         }
614         /* device name, debug, verboseopen */
615         usalp = usal_open(pdev_name, errstr, sizeof(errstr), 0, 0);
616
617         if (usalp == NULL) {
618                 int     err = geterrno();
619
620                 errmsgno(err, "%s%sCannot open SCSI driver.\n", errstr, errstr[0]?". ":"");
621                 errmsgno(EX_BAD, "For possible targets try 'wodim -scanbus'.%s\n",
622                                         geteuid() ? " Make sure you are root.":"");
623                 priv_off();
624                 dontneedgroup();
625                 dontneedroot();
626 #if defined(sun) || defined(__sun)
627                 fprintf(stderr, "On SunOS/Solaris make sure you have Joerg Schillings usal SCSI driver installed.\n");
628 #endif
629 #if defined (__linux__)
630                 fprintf(stderr, "Use the script scan_scsi.linux to find out more.\n");
631 #endif
632                 fprintf(stderr, "Probably you did not define your SCSI device.\n");
633                 fprintf(stderr, "Set the CDDA_DEVICE environment variable or use the -D option.\n");
634                 fprintf(stderr, "You can also define the default device in the Makefile.\n");
635                 fprintf(stderr, "For possible transport specifiers try 'wodim dev=help'.\n");
636                 exit(SYNTAX_ERROR);
637         }
638         usal_settimeout(usalp, 300);
639         usal_settimeout(usalp, 60);
640         usalp->silent = global.scsi_silent;
641         usalp->verbose = global.scsi_verbose;
642
643         if (global.nsectors > (unsigned) usal_bufsize(usalp, 3*1024*1024)/CD_FRAMESIZE_RAW)
644                 global.nsectors = usal_bufsize(usalp, 3*1024*1024)/CD_FRAMESIZE_RAW;
645         if (global.overlap >= global.nsectors)
646                 global.overlap = global.nsectors-1;
647
648         /*
649          * Newer versions of Linux seem to introduce an incompatible change
650          * and require root privileges or limit RLIMIT_MEMLOCK infinity
651          * in order to get a SCSI buffer in case we did call mlockall(MCL_FUTURE).
652          */
653         init_scsibuf(usalp, global.nsectors*CD_FRAMESIZE_RAW);
654         priv_off();
655         dontneedgroup();
656         dontneedroot();
657
658         if (global.scandevs) {
659                 list_devices(usalp, stdout, 0);
660                 exit(0);
661         }
662
663         if (global.scanbus) {
664                 select_target(usalp, stdout);
665                 exit(0);
666         }
667   } else {
668       needgroup(0);
669       retval = open(pdev_name,O_RDONLY
670 #ifdef  linux
671                                 | O_NONBLOCK
672 #endif
673         );
674       dontneedgroup();
675
676       if (retval < 0) {
677         fprintf(stderr, "while opening %s :", pdev_name);
678         perror("");
679         exit(DEVICEOPEN_ERROR);
680       }
681
682       /* Do final security checks here */
683       if (fstat(retval, &fstatstruct)) {
684         fprintf(stderr, "Could not fstat %s (fd %d): ", pdev_name, retval);
685         perror("");
686         exit(STAT_ERROR);
687       }
688       Check_interface_for_device( &fstatstruct, pdev_name );
689
690 #if defined HAVE_IOCTL_INTERFACE
691       /* Watch for race conditions */
692       if (have_named_device 
693           && (fstatstruct.st_dev != statstruct.st_dev ||
694               fstatstruct.st_ino != statstruct.st_ino)) {
695          fprintf(stderr,"Race condition attempted in OpenCdRom.  Exiting now.\n");
696          exit(RACE_ERROR);
697       }
698 #endif
699         /*
700          * The structure looks like a desaster :-(
701          * We do this more than once as it is impossible to understand where
702          * the right place would be to do this....
703          */
704         if (usalp != NULL) {
705                 usalp->verbose = global.scsi_verbose;
706         }
707   }
708   return retval;
709 }
710 #endif /* SIM_CD */
711
712 /******************* Simulation interface *****************/
713 #if     defined SIM_CD
714 #include "toc.h"
715 static unsigned long sim_pos=0;
716
717 /* read 'SectorBurst' adjacent sectors of audio sectors 
718  * to Buffer '*p' beginning at sector 'lSector'
719  */
720 static int ReadCdRom_sim(SCSI *x, UINT4 *p, unsigned lSector, 
721                                                                  unsigned SectorBurstVal);
722 static int ReadCdRom_sim(SCSI *x, UINT4 *p, unsigned lSector, 
723                                                                  unsigned SectorBurstVal)
724 {
725   unsigned int loop=0;
726   Int16_t *q = (Int16_t *) p;
727   int joffset = 0;
728
729   if (lSector > g_toc[cdtracks].dwStartSector || lSector + SectorBurstVal > g_toc[cdtracks].dwStartSector + 1) {
730     fprintf(stderr, "Read request out of bounds: %u - %u (%d - %d allowed)\n",
731         lSector, lSector + SectorBurstVal, 0, g_toc[cdtracks].dwStartSector);
732   }
733 #if 0
734   /* jitter with a probability of jprob */
735   if (random() <= jprob) {
736     /* jitter up to jmax samples */
737     joffset = random();
738   }
739 #endif
740
741 #ifdef DEBUG_SHM
742   fprintf(stderr, ", last_b = %p\n", *last_buffer);
743 #endif
744   for (loop = lSector*CD_FRAMESAMPLES + joffset; 
745        loop < (lSector+SectorBurstVal)*CD_FRAMESAMPLES + joffset; 
746        loop++) {
747     *q++ = loop;
748     *q++ = ~loop;
749   }
750 #ifdef DEBUG_SHM
751   fprintf(stderr, "sim wrote from %p upto %p - 4 (%d), last_b = %p\n",
752           p, q, SectorBurstVal*CD_FRAMESAMPLES, *last_buffer);
753 #endif
754   sim_pos = (lSector+SectorBurstVal)*CD_FRAMESAMPLES + joffset; 
755   return SectorBurstVal;
756 }
757
758 static int Play_at_sim(SCSI *x, unsigned int from_sector, unsigned int sectors);
759 static int Play_at_sim(SCSI *x, unsigned int from_sector, unsigned int sectors)
760 {
761   sim_pos = from_sector*CD_FRAMESAMPLES; 
762   return 0;
763 }
764
765 static unsigned sim_indices;
766
767
768 /* read the table of contents (toc) via the ioctl interface */
769 static unsigned ReadToc_sim(SCSI *x, TOC *toc);
770 static unsigned ReadToc_sim(SCSI *x, TOC *toc)
771 {
772     unsigned int scenario;
773     int scen[12][3] = { 
774       {1,1,500}, 
775       {1,2,500}, 
776       {1,99,150*99}, 
777       {2,1,500}, 
778       {2,2,500}, 
779       {2,99,150*99},
780       {2,1,500}, 
781       {5,2,500}, 
782       {5,99,150*99}, 
783       {99,1,1000}, 
784       {99,2,1000}, 
785       {99,99,150*99}, 
786     };
787     unsigned int i;
788     unsigned trcks;
789 #if 0
790     fprintf(stderr, "select one of the following TOCs\n"
791             "0 :  1 track  with  1 index\n"
792             "1 :  1 track  with  2 indices\n"
793             "2 :  1 track  with 99 indices\n"
794             "3 :  2 tracks with  1 index each\n"
795             "4 :  2 tracks with  2 indices each\n"
796             "5 :  2 tracks with 99 indices each\n"
797             "6 :  2 tracks (data and audio) with  1 index each\n"
798             "7 :  5 tracks with  2 indices each\n"
799             "8 :  5 tracks with 99 indices each\n"
800             "9 : 99 tracks with  1 index each\n"
801             "10: 99 tracks with  2 indices each\n"
802             "11: 99 tracks with 99 indices each\n"
803             );
804
805     do {
806       scanf("%u", &scenario);
807     } while (scenario > sizeof(scen)/2/sizeof(int));
808 #else
809     scenario = 6;
810 #endif
811     /* build table of contents */
812
813 #if 0
814     trcks = scen[scenario][0] + 1;
815     sim_indices = scen[scenario][1];
816
817     for (i = 0; i < trcks; i++) {
818         toc[i].bFlags = (scenario == 6 && i == 0) ? 0x40 : 0xb1;
819         toc[i].bTrack = i + 1;
820         toc[i].dwStartSector = i * scen[scenario][2];
821         toc[i].mins = (toc[i].dwStartSector+150) / (60*75);
822         toc[i].secs = (toc[i].dwStartSector+150 / 75) % (60);
823         toc[i].frms = (toc[i].dwStartSector+150) % (75);
824     }
825     toc[i].bTrack = 0xaa;
826     toc[i].dwStartSector = i * scen[scenario][2];
827     toc[i].mins = (toc[i].dwStartSector+150) / (60*75);
828     toc[i].secs = (toc[i].dwStartSector+150 / 75) % (60);
829     toc[i].frms = (toc[i].dwStartSector+150) % (75);
830 #else
831     {
832       int starts[15] = { 23625, 30115, 39050, 51777, 67507, 
833                 88612, 112962, 116840, 143387, 162662,
834                 173990, 186427, 188077, 209757, 257120};
835       trcks = 14 + 1;
836       sim_indices = 1;
837
838       for (i = 0; i < trcks; i++) {
839         toc[i].bFlags = 0x0;
840         toc[i].bTrack = i + 1;
841         toc[i].dwStartSector = starts[i];
842         toc[i].mins = (starts[i]+150) / (60*75);
843         toc[i].secs = (starts[i]+150 / 75) % (60);
844         toc[i].frms = (starts[i]+150) % (75);
845       }
846       toc[i].bTrack = 0xaa;
847       toc[i].dwStartSector = starts[i];
848       toc[i].mins = (starts[i]) / (60*75);
849       toc[i].secs = (starts[i] / 75) % (60);
850       toc[i].frms = (starts[i]) % (75);
851     }
852 #endif
853     return --trcks;           /* without lead-out */
854 }
855
856
857 static subq_chnl *ReadSubQ_sim(SCSI *usalp, unsigned char sq_format, 
858                                                                                  unsigned char track);
859 /* request sub-q-channel information. This function may cause confusion
860  * for a drive, when called in the sampling process.
861  */
862 static subq_chnl *ReadSubQ_sim(SCSI *usalp, unsigned char sq_format, 
863                                                                                  unsigned char track)
864 {
865     subq_chnl *SQp = (subq_chnl *) (SubQbuffer);
866     subq_position *SQPp = (subq_position *) &SQp->data;
867     unsigned long sim_pos1;
868     unsigned long sim_pos2;
869
870     if ( sq_format != GET_POSITIONDATA ) return NULL;  /* not supported by sim */
871
872     /* simulate CDROMSUBCHNL ioctl */
873
874     /* copy to SubQbuffer */
875     SQp->audio_status   = 0;
876     SQp->format         = 0xff;
877     SQp->control_adr    = 0xff;
878     sim_pos1 = sim_pos/CD_FRAMESAMPLES;
879     sim_pos2 = sim_pos1 % 150;
880     SQp->track          = (sim_pos1 / 5000) + 1;
881     SQp->index          = ((sim_pos1 / 150) % sim_indices) + 1;
882     sim_pos1 += 150;
883     SQPp->abs_min       = sim_pos1 / (75*60);
884     SQPp->abs_sec       = (sim_pos1 / 75) % 60;
885     SQPp->abs_frame     = sim_pos1 % 75;
886     SQPp->trel_min      = sim_pos2 / (75*60);
887     SQPp->trel_sec      = (sim_pos2 / 75) % 60;
888     SQPp->trel_frame    = sim_pos2 % 75;
889
890     return (subq_chnl *)(SubQbuffer);
891 }
892
893 static void SelectSpeed_sim(SCSI *x, unsigned sp);
894 /* ARGSUSED */
895 static void SelectSpeed_sim(SCSI *x, unsigned sp)
896 {
897 }
898
899 static void trash_cache_sim(UINT4 *p, unsigned lSector, 
900                                                                          unsigned SectorBurstVal);
901
902 /* ARGSUSED */
903 static void trash_cache_sim(UINT4 *p, unsigned lSector, 
904                                                                          unsigned SectorBurstVal)
905 {
906 }
907
908 static void SetupSimCd(void);
909
910 static void SetupSimCd()
911 {
912     EnableCdda = (void (*)(SCSI *, int, unsigned))Dummy;
913     ReadCdRom = ReadCdRom_sim;
914     ReadCdRomData = (int (*)(SCSI *, unsigned char *, unsigned, unsigned))ReadCdRom_sim;
915     doReadToc = ReadToc_sim;
916     ReadTocText = NULL;
917     ReadSubQ = ReadSubQ_sim;
918     ReadSubChannels = NULL;
919     ReadLastAudio = NULL;
920     SelectSpeed = SelectSpeed_sim;
921     Play_at = Play_at_sim;
922     StopPlay = (int (*)(SCSI *))Dummy;
923     trash_cache = trash_cache_sim;
924  
925 }
926
927 #endif /* def SIM_CD */
928
929 /* perform initialization depending on the interface used. */
930 void SetupInterface()
931 {
932 #if     defined SIM_CD
933     fprintf( stderr, "SIMULATION MODE !!!!!!!!!!!\n");
934 #else
935     /* ensure interface is setup correctly */
936     global.cooked_fd = OpenCdRom ( global.dev_name );
937 #endif
938
939     global.pagesize = getpagesize();
940
941     /* request one sector for table of contents */
942     bufferTOC = malloc( CD_FRAMESIZE_RAW + 96 );      /* assumes sufficient aligned addresses */
943     /* SubQchannel buffer */
944     SubQbuffer = malloc( 48 );               /* assumes sufficient aligned addresses */
945     cmd = malloc( 18 );                      /* assumes sufficient aligned addresses */
946     if ( !bufferTOC || !SubQbuffer || !cmd ) {
947        fprintf( stderr, "Too low on memory. Giving up.\n");
948        exit(NOMEM_ERROR);
949     }
950
951 #if     defined SIM_CD
952     usalp = malloc(sizeof(* usalp));
953     if (usalp == NULL) {
954         FatalError("No memory for SCSI structure.\n");
955     }
956     usalp->silent = 0;
957     SetupSimCd();
958 #else
959     /* if drive is of type scsi, get vendor name */
960     if (interface == GENERIC_SCSI) {
961         unsigned sector_size;
962
963         SetupSCSI();
964         sector_size = get_orig_sectorsize(usalp, &orgmode4, &orgmode10, &orgmode11);
965         if (!SCSI_emulated_ATAPI_on(usalp)) {
966           if ( sector_size != 2048 && set_sectorsize(usalp, 2048) ) {
967             fprintf( stderr, "Could not change sector size from %d to 2048\n", sector_size );
968           }
969         } else {
970           sector_size = 2048;
971         }
972
973         /* get cache setting */
974
975         /* set cache to zero */
976
977     } else {
978 #if defined (HAVE_IOCTL_INTERFACE)
979         usalp = malloc(sizeof(* usalp));
980         if (usalp == NULL) {
981                 FatalError("No memory for SCSI structure.\n");
982         }
983         usalp->silent = 0;
984         SetupCookedIoctl( global.dev_name );
985 #else
986         FatalError("Sorry, there is no known method to access the device.\n");
987 #endif
988     }
989 #endif  /* if def SIM_CD */
990         /*
991          * The structure looks like a desaster :-(
992          * We do this more than once as it is impossible to understand where
993          * the right place would be to do this....
994          */
995         if (usalp != NULL) {
996                 usalp->verbose = global.scsi_verbose;
997         }
998 }
999
1000 #ifdef  HAVE_PRIV_H
1001 #include <priv.h>
1002 #endif
1003
1004 void
1005 priv_init()
1006 {
1007 #ifdef  HAVE_PRIV_SET
1008         /*
1009          * Give up privs we do not need anymore.
1010          * We no longer need:
1011          *      file_dac_read,sys_devices,proc_priocntl,net_privaddr
1012          */
1013         priv_set(PRIV_OFF, PRIV_EFFECTIVE,
1014                 PRIV_FILE_DAC_READ, PRIV_PROC_PRIOCNTL,
1015                 PRIV_NET_PRIVADDR, NULL);
1016         priv_set(PRIV_OFF, PRIV_INHERITABLE,
1017                 PRIV_FILE_DAC_READ, PRIV_PROC_PRIOCNTL,
1018                 PRIV_NET_PRIVADDR, PRIV_SYS_DEVICES, NULL);
1019 #endif
1020 }
1021
1022 void
1023 priv_on()
1024 {
1025 #ifdef  HAVE_PRIV_SET
1026         /*
1027          * Get back privs we may need now.
1028          * We need:
1029          *      file_dac_read,sys_devices,proc_priocntl,net_privaddr
1030          */
1031         priv_set(PRIV_ON, PRIV_EFFECTIVE,
1032                 PRIV_FILE_DAC_READ, PRIV_PROC_PRIOCNTL,
1033                 PRIV_NET_PRIVADDR, NULL);
1034 #endif
1035 }
1036
1037 void
1038 priv_off()
1039 {
1040 #ifdef  HAVE_PRIV_SET
1041         /*
1042          * Give up privs we do not need anymore.
1043          * We no longer need:
1044          *      file_dac_read,sys_devices,proc_priocntl,net_privaddr
1045          */
1046         priv_set(PRIV_OFF, PRIV_EFFECTIVE,
1047                 PRIV_FILE_DAC_READ, PRIV_PROC_PRIOCNTL,
1048                 PRIV_NET_PRIVADDR, NULL);
1049 #endif
1050 }