refinements/compat fixes to fisrt-stage cache/timing tests
[xiph.git] / cdparanoia / interface / scan_devices.c
blobfc58110ec43dc63ba1f27e9cd1d584e221d14731
1 /******************************************************************
2 * CopyPolicy: GNU Lesser General Public License 2.1 applies
3 * Copyright (C) 1998-2008 Monty xiphmont@mit.edu
4 *
5 * Autoscan for or verify presence of a cdrom device
6 *
7 ******************************************************************/
9 #define _GNU_SOURCE /* get cuserid */
10 #define _USE_XOPEN /* get cuserid */
11 #include <limits.h>
12 #include <stdio.h>
13 #include <unistd.h>
14 #include <stdlib.h>
15 #include <ctype.h>
16 #include <pwd.h>
17 #include <time.h>
18 #include <sys/stat.h>
19 #include <sys/types.h>
20 #include "cdda_interface.h"
21 #include "low_interface.h"
22 #include "common_interface.h"
23 #include "utils.h"
25 #define MAX_DEV_LEN 20 /* Safe because strings only come from below */
26 /* must be absolute paths! */
27 static char *scsi_cdrom_prefixes[]={
28 "/dev/scd",
29 "/dev/sr",
30 NULL};
31 static char *scsi_generic_prefixes[]={
32 "/dev/sg",
33 NULL};
35 static char *devfs_scsi_test="/dev/scsi/";
36 static char *devfs_scsi_cd="cd";
37 static char *devfs_scsi_generic="generic";
39 static char *cdrom_devices[]={
40 "/dev/cdrom",
41 "/dev/cdroms/cdrom?",
42 "/dev/hd?",
43 "/dev/sg?",
44 "/dev/cdu31a",
45 "/dev/cdu535",
46 "/dev/sbpcd",
47 "/dev/sbpcd?",
48 "/dev/sonycd",
49 "/dev/mcd",
50 "/dev/sjcd",
51 /* "/dev/aztcd", timeout is too long */
52 "/dev/cm206cd",
53 "/dev/gscd",
54 "/dev/optcd",NULL};
56 /* Functions here look for a cdrom drive; full init of a drive type
57 happens in interface.c */
59 cdrom_drive *cdda_find_a_cdrom(int messagedest,char **messages){
60 /* Brute force... */
62 int i=0;
63 cdrom_drive *d;
65 while(cdrom_devices[i]!=NULL){
67 /* is it a name or a pattern? */
68 char *pos;
69 if((pos=strchr(cdrom_devices[i],'?'))){
70 int j;
71 /* try first eight of each device */
72 for(j=0;j<4;j++){
73 char *buffer=copystring(cdrom_devices[i]);
75 /* number, then letter */
77 buffer[pos-(cdrom_devices[i])]=j+48;
78 if((d=cdda_identify(buffer,messagedest,messages)))
79 return(d);
80 idmessage(messagedest,messages,"",NULL);
81 buffer[pos-(cdrom_devices[i])]=j+97;
82 if((d=cdda_identify(buffer,messagedest,messages)))
83 return(d);
84 idmessage(messagedest,messages,"",NULL);
86 }else{
87 /* Name. Go for it. */
88 if((d=cdda_identify(cdrom_devices[i],messagedest,messages)))
89 return(d);
91 idmessage(messagedest,messages,"",NULL);
93 i++;
95 idmessage(messagedest,messages,
96 "\n\nNo cdrom drives accessible to %s found.\n",
97 cuserid(NULL));
98 return(NULL);
101 cdrom_drive *cdda_identify(const char *device, int messagedest,char **messages){
102 struct stat st;
103 cdrom_drive *d=NULL;
105 idmessage(messagedest,messages,"Checking %s for cdrom...",device);
107 if(stat(device,&st)){
108 idperror(messagedest,messages,"\tCould not stat %s",device);
109 return(NULL);
112 #ifndef CDDA_TEST
113 if (!S_ISCHR(st.st_mode) &&
114 !S_ISBLK(st.st_mode)){
115 idmessage(messagedest,messages,"\t%s is not a block or character device",device);
116 return(NULL);
118 #endif
120 /* an IDE device may have scsi-ide support, SG_IO support and cooked
121 support. Prefer the SCSI variants, they give the most control */
122 d=cdda_identify_scsi(NULL,device,messagedest,messages);
123 if(!d)d=cdda_identify_cooked(device,messagedest,messages);
125 #ifdef CDDA_TEST
126 if(!d)d=cdda_identify_test(device,messagedest,messages);
127 #endif
129 return(d);
132 char *test_resolve_symlink(const char *file,int messagedest,char **messages){
133 char resolved[PATH_MAX];
134 struct stat st;
135 if(lstat(file,&st)){
136 idperror(messagedest,messages,"\t\tCould not stat %s",file);
137 return(NULL);
140 if(realpath(file,resolved))
141 return(strdup(resolved));
143 idperror(messagedest,messages,"\t\tCould not resolve symlink %s",file);
144 return(NULL);
148 cdrom_drive *cdda_identify_cooked(const char *dev, int messagedest,
149 char **messages){
151 cdrom_drive *d=NULL;
152 struct stat st;
153 int fd=-1, i;
154 int type;
155 char *description=NULL;
156 char *device;
158 idmessage(messagedest,messages,"\tTesting %s for cooked ioctl() interface",dev);
160 device=test_resolve_symlink(dev,messagedest,messages);
161 if(device==NULL)return(NULL);
163 if(stat(device,&st)){
164 idperror(messagedest,messages,"\t\tCould not stat %s",device);
165 free(device);
166 return(NULL);
169 if (!S_ISCHR(st.st_mode) &&
170 !S_ISBLK(st.st_mode)){
171 idmessage(messagedest,messages,"\t\t%s is not a block or character device",device);
172 free(device);
173 return(NULL);
176 type=(int)(st.st_rdev>>8);
177 switch (type) {
178 case IDE0_MAJOR:
179 case IDE1_MAJOR:
180 case IDE2_MAJOR:
181 case IDE3_MAJOR:
182 /* Yay, ATAPI... */
183 /* Ping for CDROM-ness */
185 fd=open(device,O_RDONLY|O_NONBLOCK);
186 if(fd==-1){
187 idperror(messagedest,messages,"\t\tUnable to open %s",device);
188 free(device);
189 return(NULL);
192 if(ioctl_ping_cdrom(fd)){
193 idmessage(messagedest,messages,"\t\tDevice %s is not a CDROM",device);
194 close(fd);
195 free(device);
196 return(NULL);
199 char *temp=atapi_drive_info(fd);
200 description=catstring(NULL,"ATAPI compatible ");
201 description=catstring(description,temp);
202 free(temp);
205 break;
206 case CDU31A_CDROM_MAJOR:
207 /* major indicates this is a cdrom; no ping necessary. */
208 description=copystring("Sony CDU31A or compatible");
209 break;
210 case CDU535_CDROM_MAJOR:
211 /* major indicates this is a cdrom; no ping necessary. */
212 description=copystring("Sony CDU535 or compatible");
213 break;
215 case MATSUSHITA_CDROM_MAJOR:
216 case MATSUSHITA_CDROM2_MAJOR:
217 case MATSUSHITA_CDROM3_MAJOR:
218 case MATSUSHITA_CDROM4_MAJOR:
219 /* major indicates this is a cdrom; no ping necessary. */
220 description=copystring("non-ATAPI IDE-style Matsushita/Panasonic CR-5xx or compatible");
221 break;
222 case SANYO_CDROM_MAJOR:
223 description=copystring("Sanyo proprietary or compatible: NOT CDDA CAPABLE");
224 break;
225 case MITSUMI_CDROM_MAJOR:
226 case MITSUMI_X_CDROM_MAJOR:
227 description=copystring("Mitsumi proprietary or compatible: NOT CDDA CAPABLE");
228 break;
229 case OPTICS_CDROM_MAJOR:
230 description=copystring("Optics Dolphin or compatible: NOT CDDA CAPABLE");
231 break;
232 case AZTECH_CDROM_MAJOR:
233 description=copystring("Aztech proprietary or compatible: NOT CDDA CAPABLE");
234 break;
235 case GOLDSTAR_CDROM_MAJOR:
236 description=copystring("Goldstar proprietary: NOT CDDA CAPABLE");
237 break;
238 case CM206_CDROM_MAJOR:
239 description=copystring("Philips/LMS CM206 proprietary: NOT CDDA CAPABLE");
240 break;
242 case SCSI_CDROM_MAJOR:
243 case SCSI_GENERIC_MAJOR:
244 /* Nope nope nope */
245 idmessage(messagedest,messages,"\t\t%s is not a cooked ioctl CDROM.",device);
246 free(device);
247 return(NULL);
248 default:
249 /* What the hell is this? */
250 idmessage(messagedest,messages,"\t\t%s is not a cooked ioctl CDROM.",device);
251 free(device);
252 return(NULL);
255 /* Minimum init */
257 d=calloc(1,sizeof(cdrom_drive));
258 d->cdda_device_name=device;
259 d->ioctl_device_name=copystring(device);
260 d->drive_model=description;
261 d->drive_type=type;
262 d->cdda_fd=fd;
263 d->ioctl_fd=fd;
264 d->interface=COOKED_IOCTL;
265 d->bigendianp=-1; /* We don't know yet... */
266 d->nsectors=-1;
267 d->private=calloc(1,sizeof(*d->private));
269 /* goddamnit */
270 struct timespec tv;
271 d->private->clock=(clock_gettime(CLOCK_MONOTONIC,&tv)<0?CLOCK_REALTIME:CLOCK_MONOTONIC);
273 idmessage(messagedest,messages,"\t\tCDROM sensed: %s\n",description);
274 return(d);
277 struct sg_id {
278 long l1; /* target | lun << 8 | channel << 16 | low_ino << 24 */
279 long l2; /* Unique id */
280 } sg_id;
282 typedef struct scsiid{
283 int bus;
284 int id;
285 int lun;
286 } scsiid;
288 /* Even *this* isn't as simple as it bloody well should be :-P */
289 /* SG has an easy interface, but SCSI overall does not */
290 static int get_scsi_id(int fd, scsiid *id){
291 struct sg_id argid;
292 int busarg;
294 /* get the host/id/lun */
296 if(fd==-1)return(-1);
297 if(ioctl(fd,SCSI_IOCTL_GET_IDLUN,&argid))return(-1);
298 id->bus=argid.l2; /* for now */
299 id->id=argid.l1&0xff;
300 id->lun=(argid.l1>>8)&0xff;
302 if(ioctl(fd,SCSI_IOCTL_GET_BUS_NUMBER,&busarg)==0)
303 id->bus=busarg;
305 return(0);
308 /* slightly wasteful, but a clean abstraction */
309 static char *scsi_match(const char *device,char **prefixes,
310 char *devfs_test,
311 char *devfs_other,
312 char *prompt,int messagedest,char **messages){
313 int dev=open(device,O_RDONLY|O_NONBLOCK);
314 scsiid a,b;
316 int i,j;
317 char buffer[200];
319 /* if we're running under /devfs, build the device name from the
320 device we already have */
321 if(!strncmp(device,devfs_test,strlen(devfs_test))){
322 char *pos;
323 strcpy(buffer,device);
324 pos=strrchr(buffer,'/');
325 if(pos){
326 int matchf;
327 sprintf(pos,"/%s",devfs_other);
328 matchf=open(buffer,O_RDONLY|O_NONBLOCK);
329 for (i = 0; (i<10) && (matchf==-1); i++) {
330 fprintf(stderr, "Error trying to open %s exclusively (%s). retrying in 1 seconds.\n", buffer, strerror(errno));
331 usleep(1000000 + 100000.0 * rand()/(RAND_MAX+1.0));
332 matchf = open(buffer,O_RDONLY|O_NONBLOCK);
334 if(matchf!=-1){
335 close(matchf);
336 close(dev);
337 return(strdup(buffer));
342 /* get the host/id/lun */
343 if(dev==-1){
344 idperror(messagedest,messages,"\t\tCould not access device %s",
345 device);
347 goto matchfail;
349 if(get_scsi_id(dev,&a)){
350 idperror(messagedest,messages,"\t\tDevice %s could not perform ioctl()",
351 device);
353 goto matchfail;
356 /* go through most likely /dev nodes for a match */
357 for(i=0;i<25;i++){
358 for(j=0;j<2;j++){
359 int pattern=0;
360 int matchf, k;
362 while(prefixes[pattern]!=NULL){
363 switch(j){
364 case 0:
365 /* number */
366 sprintf(buffer,"%s%d",prefixes[pattern],i);
367 break;
368 case 1:
369 /* number */
370 sprintf(buffer,"%s%c",prefixes[pattern],i+'a');
371 break;
374 matchf=open(buffer,O_RDONLY|O_NONBLOCK);
375 for (k = 0; (k<10) && (matchf==-1); k++) {
376 fprintf(stderr, "Error trying to open %s exclusively (%s). retrying in 1 second.\n", buffer, strerror(errno));
377 usleep(1000000 + 100000.0 * rand()/(RAND_MAX+1.0));
378 matchf=open(buffer,O_RDONLY|O_NONBLOCK);
381 if(matchf!=-1){
382 if(get_scsi_id(matchf,&b)==0){
383 if(a.bus==b.bus && a.id==b.id && a.lun==b.lun){
384 close(matchf);
385 close(dev);
386 return(strdup(buffer));
389 close(matchf);
391 pattern++;
396 idmessage(messagedest,messages,prompt,device);
398 matchfail:
400 if(dev!=-1)close(dev);
401 return(NULL);
404 void strscat(char *a,char *b,int n){
405 int i;
407 for(i=n;i>0;i--)
408 if(b[i-1]>' ')break;
410 strncat(a,b,i);
411 strcat(a," ");
414 /* At this point, we're going to punt compatability before SG2, and
415 allow only SG2 and SG3 */
416 static int verify_SG_version(cdrom_drive *d,int messagedest,
417 char **messages){
418 /* are we using the new SG driver by Doug Gilbert? If not, punt */
419 int version,major,minor;
420 char buffer[256];
421 idmessage(messagedest,messages,
422 "\nFound an accessible SCSI CDROM drive."
423 "\nLooking at revision of the SG interface in use...","");
425 if(ioctl(d->cdda_fd,SG_GET_VERSION_NUM,&version)){
426 /* Up, guess not. */
427 idmessage(messagedest,messages,
428 "\tOOPS! Old 2.0/early 2.1/early 2.2.x (non-ac patch) style "
429 "SG.\n\tCdparanoia no longer supports the old interface.\n","");
430 return(0);
432 major=version/10000;
433 version-=major*10000;
434 minor=version/100;
435 version-=minor*100;
437 sprintf(buffer,"\tSG interface version %d.%d.%d; OK.",
438 major,minor,version);
440 idmessage(messagedest,messages,buffer,"");
441 return(major);
444 int check_sgio(const char *device, int messagedest, char **messages){
445 int fd;
446 struct sg_io_hdr hdr;
448 if (!device) return 0;
450 /* we don't really care what type of device it is -- if it can do
451 * SG_IO, then we'll put it through the normal mmc/atapi/etc tests
452 * later, but it's good enough for now. */
453 fd = open(device, O_RDWR|O_NONBLOCK);
454 if (fd < 0){
455 idperror(messagedest,messages,
456 "\t\tCould not access device %s to test for SG_IO support",device);
457 return 0;
460 memset(&hdr, 0, sizeof (struct sg_io_hdr));
461 /* First try with interface_id = 'A'; for all but the sg case,
462 * that'll get us a -EINVAL if it supports SG_IO, and some other
463 * error for all other cases. */
464 hdr.interface_id = 'A';
465 if (ioctl(fd, SG_IO, &hdr)) {
466 switch (errno) {
467 case EINVAL: /* sr and ata give us EINVAL when SG_IO is
468 * supported but interface_id is bad. */
470 case ENOSYS: /* sg gives us ENOSYS when SG_IO is supported but
471 * interface_id is bad. IMHO, this is wrong and
472 * needs fixing in the kernel. */
474 close(fd);
475 return 1;
477 default: /* everything else gives ENOTTY, I think. I'm just
478 * going to be paranoid and reject everything else. */
480 close(fd);
481 return 0;
485 /* if we get here, something is dreadfuly wrong. ioctl(fd,SG_IO,&hdr)
486 * handled SG_IO, but took hdr.interface_id = 'A' as valid, and an empty
487 * command as good. Don't trust it. */
488 close(fd);
489 return 0;
492 /* scanning is always done by specifying a device name in
493 specialized_device; generic_device is only filled when the generic device
494 force option is used, and in that case, use of SG (not SGIO) should indeed be
495 forced */
496 cdrom_drive *cdda_identify_scsi(const char *generic_device,
497 const char *specialized_device, int messagedest,
498 char **messages){
500 cdrom_drive *d=NULL;
501 struct stat i_st;
502 struct stat g_st;
503 int use_sgio=1;
504 int i_fd=-1, i;
505 int g_fd=-1;
506 int version;
507 int type;
508 char *p;
510 if(generic_device)
511 idmessage(messagedest,messages,"\tTesting %s for SCSI/MMC interface",
512 generic_device);
513 else
514 if(specialized_device)
515 idmessage(messagedest,messages,"\tTesting %s for SCSI/MMC interface",
516 specialized_device);
519 if(generic_device){
520 use_sgio = 0;
521 idmessage(messagedest,messages,"\t\tgeneric device forced; not testing for SG_IO interface",
522 generic_device);
524 if(stat(generic_device,&g_st)){
525 idperror(messagedest,messages,"\t\tCould not access device %s",
526 generic_device);
527 return(NULL);
530 if((int)(g_st.st_rdev>>8)!=SCSI_GENERIC_MAJOR){
531 idmessage(messagedest,messages,"\t\t%s is not a generic SCSI device",
532 generic_device);
533 return(NULL);
537 if(specialized_device){
538 if(stat(specialized_device,&i_st)){
539 idperror(messagedest,messages,"\t\tCould not access device %s",
540 specialized_device);
541 return(NULL);
545 /* we need to resolve any symlinks for the lookup code to work */
547 if(generic_device){
548 generic_device=test_resolve_symlink(generic_device,messagedest,messages);
549 if(generic_device==NULL)goto cdda_identify_scsi_fail;
551 if(specialized_device){
552 specialized_device=test_resolve_symlink(specialized_device,messagedest,messages);
553 if(specialized_device==NULL)goto cdda_identify_scsi_fail;
556 /* sgio is always preferred if it's there, unless user has forced the generic scsi device name */
557 if(use_sgio){
558 if(check_sgio(specialized_device,messagedest,messages)){
559 idmessage(messagedest,messages,"\t\tSG_IO device: %s",specialized_device);
560 }else{
561 idmessage(messagedest,messages,"\t\tno SG_IO support for device: %s",specialized_device);
562 use_sgio=0;
566 if(!use_sgio){
568 /* was a generic device passed in as the specialized device name? */
569 if(specialized_device){
570 if((int)(i_st.st_rdev>>8)==SCSI_GENERIC_MAJOR){
571 char *temp=(char *)generic_device;
572 generic_device=specialized_device;
573 specialized_device=temp;
576 if(!generic_device || !specialized_device){
577 if(generic_device){
578 specialized_device=
579 scsi_match(generic_device,scsi_cdrom_prefixes,
580 devfs_scsi_test,devfs_scsi_cd,
581 "\t\tNo cdrom device found to match generic device %s",
582 messagedest,messages);
583 }else{
584 generic_device=
585 scsi_match(specialized_device,scsi_generic_prefixes,
586 devfs_scsi_test,devfs_scsi_generic,
587 "\t\tNo generic SCSI device found to match CDROM device %s",
588 messagedest,messages);
589 if(!generic_device)
590 goto cdda_identify_scsi_fail;
595 idmessage(messagedest,messages,"\t\tgeneric device: %s",generic_device);
596 idmessage(messagedest,messages,"\t\tioctl device: %s",(specialized_device?
597 specialized_device:
598 "not found"));
599 if(specialized_device){
600 if(stat(specialized_device,&i_st)){
601 idperror(messagedest,messages,"\t\tCould not access cdrom device "
602 "%s",specialized_device);
603 goto cdda_identify_scsi_fail;
607 if(stat(generic_device,&g_st)){
608 idperror(messagedest,messages,"\t\tCould not access generic SCSI device "
609 "%s",generic_device);
611 goto cdda_identify_scsi_fail;
615 if(specialized_device) {
616 if(use_sgio)
617 i_fd=open(specialized_device,O_RDWR|O_NONBLOCK);
618 else
619 i_fd=open(specialized_device,O_RDONLY|O_NONBLOCK);
622 if(generic_device)
623 g_fd=open(generic_device,O_RDWR);
626 if(specialized_device && i_fd==-1){
627 idperror(messagedest,messages,"\t\tCould not open cdrom device "
628 "%s (continuing)",specialized_device);
629 goto cdda_identify_scsi_fail;
632 if(generic_device && g_fd==-1){
633 idperror(messagedest,messages,"\t\tCould not open generic SCSI device "
634 "%s",generic_device);
635 goto cdda_identify_scsi_fail;
638 if(i_fd!=-1){
639 type=(int)(i_st.st_rdev>>8);
641 if(!use_sgio){
642 if(type==SCSI_CDROM_MAJOR){
643 if (!S_ISBLK(i_st.st_mode)) {
644 idmessage(messagedest,messages,"\t\tSCSI CDROM device %s not a "
645 "block device",specialized_device);
646 goto cdda_identify_scsi_fail;
648 }else{
649 idmessage(messagedest,messages,"\t\tSCSI CDROM device %s has wrong "
650 "major number",specialized_device);
651 goto cdda_identify_scsi_fail;
656 if(g_fd != -1){
657 if((int)(g_st.st_rdev>>8)==SCSI_GENERIC_MAJOR){
658 if (!S_ISCHR(g_st.st_mode)) {
659 idmessage(messagedest,messages,"\t\tGeneric SCSI device %s not a "
660 "char device",generic_device);
661 goto cdda_identify_scsi_fail;
663 }else{
664 idmessage(messagedest,messages,"\t\tGeneric SCSI device %s has wrong "
665 "major number",generic_device);
666 goto cdda_identify_scsi_fail;
670 d=calloc(1,sizeof(cdrom_drive));
671 d->drive_type=type;
672 d->cdda_fd=g_fd;
673 d->ioctl_fd=i_fd;
674 d->bigendianp=-1; /* We don't know yet... */
675 d->nsectors=-1;
676 d->messagedest = messagedest;
677 d->private=calloc(1,sizeof(*d->private));
679 /* goddamnit */
680 struct timespec tv;
681 d->private->clock=(clock_gettime(CLOCK_MONOTONIC,&tv)<0?CLOCK_REALTIME:CLOCK_MONOTONIC);
683 if(use_sgio){
684 d->interface=SGIO_SCSI;
685 d->private->sg_buffer=(unsigned char *)(d->private->sg_hd=malloc(MAX_BIG_BUFF_SIZE));
686 g_fd=d->cdda_fd=dup(d->ioctl_fd);
687 }else{
688 version=verify_SG_version(d,messagedest,messages);
689 switch(version){
690 case -1:case 0:case 1:
691 d->interface=GENERIC_SCSI;
692 goto cdda_identify_scsi_fail;
693 case 2:case 3:
694 d->interface=GENERIC_SCSI;
695 break;
698 /* malloc our big buffer for scsi commands */
699 d->private->sg_hd=malloc(MAX_BIG_BUFF_SIZE);
700 d->private->sg_buffer=((unsigned char *)d->private->sg_hd)+SG_OFF;
704 /* get the lun */
705 scsiid lun;
706 if(get_scsi_id(i_fd,&lun))
707 d->lun=0; /* a reasonable guess on a failed ioctl */
708 else
709 d->lun=lun.lun;
712 p = (char *)scsi_inquiry(d);
714 if (!p){
716 /* 2.6 kernels have a bug where the block layer implements
717 SG_DXFER_TO_FROM_DEVICE as a write operation instead of read.
718 I've submitted a kernel patch, but it will take a while to
719 propogate. Work around it for now. --Monty */
721 if(d->interface == SGIO_SCSI){
722 /* test the inquiry with the workaround */
723 d->interface = SGIO_SCSI_BUGGY1;
724 p = (char *)scsi_inquiry(d);
726 if(p){
727 idmessage(messagedest,messages,
728 "\t\tThis kernel's block layer has a buggy SG_DXFER_TO_FROM_DEVICE;\n\t\t activating workaround.\n",NULL);
729 }else{
730 /* Failed for some reason other than the buggy ioctl(); set the interface type back */
731 d->interface = SGIO_SCSI;
736 if (!p){
737 idmessage(messagedest,messages,
738 "\t\tInquiry command failed; unable to probe drive\n",NULL);
739 goto cdda_identify_scsi_fail;
742 /* It would seem some TOSHIBA CDROMs gets things wrong */
743 if (p &&
744 !strncmp (p + 8, "TOSHIBA", 7) &&
745 !strncmp (p + 16, "CD-ROM", 6) &&
746 p[0] == TYPE_DISK) {
747 p[0] = TYPE_ROM;
748 p[1] |= 0x80; /* removable */
751 if (*p != TYPE_ROM && *p != TYPE_WORM) {
752 idmessage(messagedest,messages,
753 "\t\tDrive is neither a CDROM nor a WORM device\n",NULL);
754 goto cdda_identify_scsi_fail;
757 d->drive_model=calloc(36,1);
758 memcpy(d->inqbytes,p,4);
759 d->cdda_device_name=copystring(generic_device);
760 d->ioctl_device_name=copystring(specialized_device);
761 d->drive_model=calloc(36,1);
762 strscat(d->drive_model,p+8,8);
763 strscat(d->drive_model,p+16,16);
764 strscat(d->drive_model,p+32,4);
766 idmessage(messagedest,messages,"\nCDROM model sensed sensed: %s",d->drive_model);
767 return(d);
769 cdda_identify_scsi_fail:
770 if(generic_device)free((char *)generic_device);
771 if(specialized_device)free((char *)specialized_device);
772 if(i_fd!=-1)close(i_fd);
773 if(g_fd!=-1)close(g_fd);
774 if(d){
775 if(d->private){
776 if(d->private->sg_hd)free(d->private->sg_hd);
777 free(d->private);
779 free(d);
781 return(NULL);
784 #ifdef CDDA_TEST
786 cdrom_drive *cdda_identify_test(const char *filename, int messagedest,
787 char **messages){
789 cdrom_drive *d=NULL;
790 struct stat st;
791 int fd=-1,i;
793 idmessage(messagedest,messages,"\tTesting %s for file/test interface",
794 filename);
796 if(stat(filename,&st)){
797 idperror(messagedest,messages,"\t\tCould not access file %s",
798 filename);
799 return(NULL);
802 if(!S_ISREG(st.st_mode)){
803 idmessage(messagedest,messages,"\t\t%s is not a regular file",
804 filename);
805 return(NULL);
808 fd=open(filename,O_RDONLY);
809 if(fd==-1){
810 idperror(messagedest,messages,"\t\tCould not open file %s",filename);
811 return(NULL);
814 d=calloc(1,sizeof(cdrom_drive));
816 d->cdda_device_name=copystring(filename);
817 d->ioctl_device_name=copystring(filename);
818 d->drive_type=-1;
819 d->cdda_fd=fd;
820 d->ioctl_fd=fd;
821 d->interface=TEST_INTERFACE;
822 d->bigendianp=-1; /* We don't know yet... */
823 d->nsectors=-1;
824 d->private=calloc(1,sizeof(*d->private));
825 d->drive_model=copystring("File based test interface");
826 idmessage(messagedest,messages,"\t\tCDROM sensed: %s\n",d->drive_model);
828 return(d);
831 #endif