1 /*
2 $Id: scan_devices.c,v 1.33 2008/06/16 19:45:44 flameeyes Exp $
3
4 Copyright (C) 2004, 2005, 2007, 2008, 2009 Rocky Bernstein <rocky@gnu.org>
5 Copyright (C) 1998 Monty xiphmont@mit.edu
6
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 /******************************************************************
22 *
23 * Autoscan for or verify presence of a CD-ROM device
24 *
25 ******************************************************************/
26
27 #include "common_interface.h"
28 #include "low_interface.h"
29 #include "utils.h"
30 #include "cdio/mmc.h"
31 #include "cdio/util.h"
32 #include <limits.h>
33 #include <ctype.h>
34
35 #ifdef HAVE_PWD_H
36 #include <pwd.h>
37 #endif
38
39 #ifdef HAVE_SYS_STAT_H
40 #include <sys/stat.h>
41 #endif
42
43 #ifndef PATH_MAX
44 #define PATH_MAX 4096
45 #endif
46
47 static const char cdrom_devices[][32]={
48 "/dev/cdrom",
49 "/dev/cdroms/cdrom?",
50 "/dev/hd?",
51 "/dev/sg?",
52 "/dev/cdu31a",
53 "/dev/cdu535",
54 "/dev/sbpcd",
55 "/dev/sbpcd?",
56 "/dev/sonycd",
57 "/dev/mcd",
58 "/dev/sjcd",
59 /* "/dev/aztcd", timeout is too long */
60 "/dev/cm206cd",
61 "/dev/gscd",
62 "/dev/optcd",
63 ""};
64
65 static cdrom_drive_t *
66 cdda_identify_device_cdio(CdIo_t *p_cdio, const char *psz_device,
67 int messagedest, char **ppsz_messages);
68
69 /* Functions here look for a cdrom drive; full init of a drive type
70 happens in interface.c */
71
72 cdrom_drive_t *
cdio_cddap_find_a_cdrom(int messagedest,char ** ppsz_messages)73 cdio_cddap_find_a_cdrom(int messagedest, char **ppsz_messages){
74 /* Brute force... */
75
76 int i=0;
77 cdrom_drive_t *d;
78
79 while(*cdrom_devices[i]!='\0'){
80
81 /* is it a name or a pattern? */
82 char *pos;
83 if((pos=strchr(cdrom_devices[i],'?'))){
84 int j;
85 /* try first eight of each device */
86 for(j=0;j<4;j++){
87 char *buffer=strdup(cdrom_devices[i]);
88
89 /* number, then letter */
90
91 buffer[pos-(cdrom_devices[i])]=j+48;
92 if((d=cdda_identify(buffer, messagedest, ppsz_messages)))
93 return(d);
94 idmessage(messagedest, ppsz_messages, "", NULL);
95 buffer[pos-(cdrom_devices[i])]=j+97;
96 if((d=cdda_identify(buffer, messagedest, ppsz_messages)))
97 return(d);
98 idmessage(messagedest, ppsz_messages, "", NULL);
99 free(buffer);
100 }
101 }else{
102 /* Name. Go for it. */
103 if((d=cdda_identify(cdrom_devices[i], messagedest, ppsz_messages)))
104 return(d);
105
106 idmessage(messagedest, ppsz_messages, "", NULL);
107 }
108 i++;
109 }
110 {
111 #if defined(HAVE_GETPWUID) && defined(HAVE_GETEUID)
112 struct passwd *temp;
113 temp=getpwuid(geteuid());
114 idmessage(messagedest, ppsz_messages,
115 "\n\nNo cdrom drives accessible to %s found.\n",
116 temp->pw_name);
117 #else
118 idmessage(messagedest, ppsz_messages,
119 "\n\nNo cdrom drives accessible found.\n", NULL);
120 #endif
121 }
122 return(NULL);
123 }
124
125 #ifdef DEVICE_IN_FILESYSTEM
126 static char *
test_resolve_symlink(const char * file,int messagedest,char ** ppsz_messages)127 test_resolve_symlink(const char *file, int messagedest, char **ppsz_messages)
128 {
129 char resolved[PATH_MAX];
130 struct stat st;
131 if (lstat(file,&st)){
132 idperror(messagedest, ppsz_messages, "\t\tCould not stat %s",file);
133 return(NULL);
134 }
135
136 if (cdio_realpath(file,resolved))
137 return(strdup(resolved));
138
139 idperror(messagedest, ppsz_messages, "\t\tCould not resolve symlink %s",
140 file);
141 return(NULL);
142 }
143 #endif
144
145 /** Returns a paranoia CD-ROM drive object with a CD-DA in it or NULL
146 if there was an error.
147 @see cdio_cddap_identify_cdio
148 */
149 cdrom_drive_t *
cdio_cddap_identify(const char * psz_dev,int messagedest,char ** ppsz_messages)150 cdio_cddap_identify(const char *psz_dev, int messagedest,
151 char **ppsz_messages)
152 {
153 CdIo_t *p_cdio = NULL;
154
155 if (psz_dev)
156 idmessage(messagedest, ppsz_messages, "Checking %s for cdrom...",
157 psz_dev);
158 else
159 idmessage(messagedest, ppsz_messages, "Checking for cdrom...", NULL);
160
161 #ifdef DEVICE_IN_FILESYSTEM
162 if (psz_dev) {
163 char *psz_device = test_resolve_symlink(psz_dev, messagedest,
164 ppsz_messages);
165 if ( psz_device ) {
166 cdrom_drive_t *d=NULL;
167 p_cdio = cdio_open(psz_device, DRIVER_UNKNOWN);
168 d = cdda_identify_device_cdio(p_cdio, psz_device, messagedest,
169 ppsz_messages);
170 free(psz_device);
171 return d;
172 }
173 }
174 #endif
175
176 p_cdio = cdio_open(psz_dev, DRIVER_UNKNOWN);
177 if (p_cdio) {
178 if (!psz_dev) {
179 psz_dev = cdio_get_arg(p_cdio, "source");
180 }
181 return cdda_identify_device_cdio(p_cdio, psz_dev, messagedest,
182 ppsz_messages);
183 }
184 return NULL;
185 }
186
187 /** Returns a paranoia CD-ROM drive object with a CD-DA in it or NULL
188 if there was an error. In contrast to cdio_cddap_identify, we
189 start out with an initialized p_cdio object. For example you may
190 have used that for other purposes such as to get CDDB/CD-Text
191 information. @see cdio_cddap_identify
192 */
193 cdrom_drive_t *
cdio_cddap_identify_cdio(CdIo_t * p_cdio,int messagedest,char ** ppsz_messages)194 cdio_cddap_identify_cdio(CdIo_t *p_cdio, int messagedest, char **ppsz_messages)
195 {
196 if (!p_cdio) return NULL;
197 {
198 const char *psz_device = cdio_get_arg(p_cdio, "source");
199 idmessage(messagedest, ppsz_messages, "Checking %s for cdrom...",
200 psz_device);
201 return cdda_identify_device_cdio(p_cdio, psz_device, messagedest,
202 ppsz_messages);
203 }
204
205 }
206
207 static cdrom_drive_t *
cdda_identify_device_cdio(CdIo_t * p_cdio,const char * psz_device,int messagedest,char ** ppsz_messages)208 cdda_identify_device_cdio(CdIo_t *p_cdio, const char *psz_device,
209 int messagedest, char **ppsz_messages)
210 {
211 cdrom_drive_t *d=NULL;
212 int drive_type = 0;
213 char *description=NULL;
214 #ifdef HAVE_LINUX_MAJOR_H
215 struct stat st;
216 #endif
217
218 if (!p_cdio) {
219 idperror(messagedest, ppsz_messages, "\t\tUnable to open %s", psz_device);
220 return NULL;
221 }
222
223 #ifdef HAVE_LINUX_MAJOR_H
224 if ( 0 == stat(psz_device, &st) ) {
225 if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) {
226 drive_type=(int)(st.st_rdev>>8);
227 switch (drive_type) {
228 case IDE0_MAJOR:
229 case IDE1_MAJOR:
230 case IDE2_MAJOR:
231 case IDE3_MAJOR:
232 /* Yay, ATAPI... */
233 description=strdup("ATAPI compatible ");
234 break;
235 case CDU31A_CDROM_MAJOR:
236 /* major indicates this is a cdrom; no ping necessary. */
237 description=strdup("Sony CDU31A or compatible");
238 break;
239 case CDU535_CDROM_MAJOR:
240 /* major indicates this is a cdrom; no ping necessary. */
241 description=strdup("Sony CDU535 or compatible");
242 break;
243
244 case MATSUSHITA_CDROM_MAJOR:
245 case MATSUSHITA_CDROM2_MAJOR:
246 case MATSUSHITA_CDROM3_MAJOR:
247 case MATSUSHITA_CDROM4_MAJOR:
248 /* major indicates this is a cdrom; no ping necessary. */
249 description=strdup("non-ATAPI IDE-style Matsushita/Panasonic CR-5xx or compatible");
250 break;
251 case SANYO_CDROM_MAJOR:
252 description=strdup("Sanyo proprietary or compatible: NOT CDDA CAPABLE");
253 break;
254 case MITSUMI_CDROM_MAJOR:
255 case MITSUMI_X_CDROM_MAJOR:
256 description=strdup("Mitsumi proprietary or compatible: NOT CDDA CAPABLE");
257 break;
258 case OPTICS_CDROM_MAJOR:
259 description=strdup("Optics Dolphin or compatible: NOT CDDA CAPABLE");
260 break;
261 case AZTECH_CDROM_MAJOR:
262 description=strdup("Aztech proprietary or compatible: NOT CDDA CAPABLE");
263 break;
264 case GOLDSTAR_CDROM_MAJOR:
265 description=strdup("Goldstar proprietary: NOT CDDA CAPABLE");
266 break;
267 case CM206_CDROM_MAJOR:
268 description=strdup("Philips/LMS CM206 proprietary: NOT CDDA CAPABLE");
269 break;
270
271 case SCSI_CDROM_MAJOR:
272 case SCSI_GENERIC_MAJOR:
273 /* Nope nope nope */
274 description=strdup("SCSI CD-ROM");
275 break;
276 default:
277 /* What the hell is this? */
278 idmessage(messagedest, ppsz_messages,
279 "\t\t%s is not a cooked ioctl CDROM.",
280 psz_device);
281 return(NULL);
282 }
283 }
284 }
285 #endif /*HAVE_LINUX_MAJOR_H*/
286
287 /* Minimum init */
288
289 d=calloc(1, sizeof(cdrom_drive_t));
290 d->p_cdio = p_cdio;
291 d->cdda_device_name = strdup(psz_device);
292 d->drive_type = drive_type;
293 d->bigendianp = -1; /* We don't know yet... */
294 d->nsectors = -1; /* We don't know yet... */
295 d->messagedest = messagedest;
296 d->b_swap_bytes = true;
297
298 {
299 cdio_hwinfo_t hw_info = {
300 "UNKNOWN", "Unknown model", "????"
301 };
302
303 if ( mmc_get_hwinfo( p_cdio, &hw_info ) ) {
304 unsigned int i_len = strlen(hw_info.psz_vendor)
305 + strlen(hw_info.psz_model)
306 + strlen(hw_info.psz_revision) + 5;
307
308 if (description) {
309 i_len += strlen(description);
310 d->drive_model=malloc( i_len );
311 snprintf( d->drive_model, i_len, "%s %s %s %s",
312 hw_info.psz_vendor, hw_info.psz_model, hw_info.psz_revision,
313 description );
314 } else {
315 d->drive_model=malloc( i_len );
316 snprintf( d->drive_model, i_len, "%s %s %s",
317 hw_info.psz_vendor, hw_info.psz_model, hw_info.psz_revision
318 );
319 }
320 idmessage(messagedest, ppsz_messages, "\t\tCDROM sensed: %s\n",
321 d->drive_model);
322 }
323 }
324
325 if (description)
326 free(description);
327
328 return(d);
329 }
330