]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/udev/cdrom_id/cdrom_id.c
tree-wide: drop copyright headers from frequent contributors
[thirdparty/systemd.git] / src / udev / cdrom_id / cdrom_id.c
1 /* SPDX-License-Identifier: GPL-2.0+ */
2 /*
3 * cdrom_id - optical drive and media information prober
4 *
5 *
6 */
7
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <getopt.h>
11 #include <limits.h>
12 #include <linux/cdrom.h>
13 #include <scsi/sg.h>
14 #include <stddef.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <sys/ioctl.h>
19 #include <sys/stat.h>
20 #include <sys/time.h>
21 #include <sys/types.h>
22 #include <time.h>
23 #include <unistd.h>
24
25 #include "libudev.h"
26
27 #include "libudev-private.h"
28 #include "random-util.h"
29 #include "udev-util.h"
30
31 /* device info */
32 static unsigned int cd_cd_rom;
33 static unsigned int cd_cd_r;
34 static unsigned int cd_cd_rw;
35 static unsigned int cd_dvd_rom;
36 static unsigned int cd_dvd_r;
37 static unsigned int cd_dvd_rw;
38 static unsigned int cd_dvd_ram;
39 static unsigned int cd_dvd_plus_r;
40 static unsigned int cd_dvd_plus_rw;
41 static unsigned int cd_dvd_plus_r_dl;
42 static unsigned int cd_dvd_plus_rw_dl;
43 static unsigned int cd_bd;
44 static unsigned int cd_bd_r;
45 static unsigned int cd_bd_re;
46 static unsigned int cd_hddvd;
47 static unsigned int cd_hddvd_r;
48 static unsigned int cd_hddvd_rw;
49 static unsigned int cd_mo;
50 static unsigned int cd_mrw;
51 static unsigned int cd_mrw_w;
52
53 /* media info */
54 static unsigned int cd_media;
55 static unsigned int cd_media_cd_rom;
56 static unsigned int cd_media_cd_r;
57 static unsigned int cd_media_cd_rw;
58 static unsigned int cd_media_dvd_rom;
59 static unsigned int cd_media_dvd_r;
60 static unsigned int cd_media_dvd_rw;
61 static unsigned int cd_media_dvd_rw_ro; /* restricted overwrite mode */
62 static unsigned int cd_media_dvd_rw_seq; /* sequential mode */
63 static unsigned int cd_media_dvd_ram;
64 static unsigned int cd_media_dvd_plus_r;
65 static unsigned int cd_media_dvd_plus_rw;
66 static unsigned int cd_media_dvd_plus_r_dl;
67 static unsigned int cd_media_dvd_plus_rw_dl;
68 static unsigned int cd_media_bd;
69 static unsigned int cd_media_bd_r;
70 static unsigned int cd_media_bd_re;
71 static unsigned int cd_media_hddvd;
72 static unsigned int cd_media_hddvd_r;
73 static unsigned int cd_media_hddvd_rw;
74 static unsigned int cd_media_mo;
75 static unsigned int cd_media_mrw;
76 static unsigned int cd_media_mrw_w;
77
78 static const char *cd_media_state = NULL;
79 static unsigned int cd_media_session_next;
80 static unsigned int cd_media_session_count;
81 static unsigned int cd_media_track_count;
82 static unsigned int cd_media_track_count_data;
83 static unsigned int cd_media_track_count_audio;
84 static unsigned long long int cd_media_session_last_offset;
85
86 #define ERRCODE(s) ((((s)[2] & 0x0F) << 16) | ((s)[12] << 8) | ((s)[13]))
87 #define SK(errcode) (((errcode) >> 16) & 0xF)
88 #define ASC(errcode) (((errcode) >> 8) & 0xFF)
89 #define ASCQ(errcode) ((errcode) & 0xFF)
90
91 static bool is_mounted(const char *device)
92 {
93 struct stat statbuf;
94 FILE *fp;
95 int maj, min;
96 bool mounted = false;
97
98 if (stat(device, &statbuf) < 0)
99 return false;
100
101 fp = fopen("/proc/self/mountinfo", "re");
102 if (fp == NULL)
103 return false;
104 while (fscanf(fp, "%*s %*s %i:%i %*[^\n]", &maj, &min) == 2) {
105 if (makedev(maj, min) == statbuf.st_rdev) {
106 mounted = true;
107 break;
108 }
109 }
110 fclose(fp);
111 return mounted;
112 }
113
114 static void info_scsi_cmd_err(struct udev *udev, const char *cmd, int err)
115 {
116 if (err == -1) {
117 log_debug("%s failed", cmd);
118 return;
119 }
120 log_debug("%s failed with SK=%Xh/ASC=%02Xh/ACQ=%02Xh", cmd, SK(err), ASC(err), ASCQ(err));
121 }
122
123 struct scsi_cmd {
124 struct cdrom_generic_command cgc;
125 union {
126 struct request_sense s;
127 unsigned char u[18];
128 } _sense;
129 struct sg_io_hdr sg_io;
130 };
131
132 static void scsi_cmd_init(struct udev *udev, struct scsi_cmd *cmd)
133 {
134 memzero(cmd, sizeof(struct scsi_cmd));
135 cmd->cgc.quiet = 1;
136 cmd->cgc.sense = &cmd->_sense.s;
137 cmd->sg_io.interface_id = 'S';
138 cmd->sg_io.mx_sb_len = sizeof(cmd->_sense);
139 cmd->sg_io.cmdp = cmd->cgc.cmd;
140 cmd->sg_io.sbp = cmd->_sense.u;
141 cmd->sg_io.flags = SG_FLAG_LUN_INHIBIT | SG_FLAG_DIRECT_IO;
142 }
143
144 static void scsi_cmd_set(struct udev *udev, struct scsi_cmd *cmd, size_t i, unsigned char arg)
145 {
146 cmd->sg_io.cmd_len = i + 1;
147 cmd->cgc.cmd[i] = arg;
148 }
149
150 #define CHECK_CONDITION 0x01
151
152 static int scsi_cmd_run(struct udev *udev, struct scsi_cmd *cmd, int fd, unsigned char *buf, size_t bufsize)
153 {
154 int ret = 0;
155
156 if (bufsize > 0) {
157 cmd->sg_io.dxferp = buf;
158 cmd->sg_io.dxfer_len = bufsize;
159 cmd->sg_io.dxfer_direction = SG_DXFER_FROM_DEV;
160 } else {
161 cmd->sg_io.dxfer_direction = SG_DXFER_NONE;
162 }
163 if (ioctl(fd, SG_IO, &cmd->sg_io))
164 return -1;
165
166 if ((cmd->sg_io.info & SG_INFO_OK_MASK) != SG_INFO_OK) {
167 errno = EIO;
168 ret = -1;
169 if (cmd->sg_io.masked_status & CHECK_CONDITION) {
170 ret = ERRCODE(cmd->_sense.u);
171 if (ret == 0)
172 ret = -1;
173 }
174 }
175 return ret;
176 }
177
178 static int media_lock(struct udev *udev, int fd, bool lock)
179 {
180 int err;
181
182 /* disable the kernel's lock logic */
183 err = ioctl(fd, CDROM_CLEAR_OPTIONS, CDO_LOCK);
184 if (err < 0)
185 log_debug("CDROM_CLEAR_OPTIONS, CDO_LOCK failed");
186
187 err = ioctl(fd, CDROM_LOCKDOOR, lock ? 1 : 0);
188 if (err < 0)
189 log_debug("CDROM_LOCKDOOR failed");
190
191 return err;
192 }
193
194 static int media_eject(struct udev *udev, int fd)
195 {
196 struct scsi_cmd sc;
197 int err;
198
199 scsi_cmd_init(udev, &sc);
200 scsi_cmd_set(udev, &sc, 0, 0x1b);
201 scsi_cmd_set(udev, &sc, 4, 0x02);
202 scsi_cmd_set(udev, &sc, 5, 0);
203 err = scsi_cmd_run(udev, &sc, fd, NULL, 0);
204 if ((err != 0)) {
205 info_scsi_cmd_err(udev, "START_STOP_UNIT", err);
206 return -1;
207 }
208 return 0;
209 }
210
211 static int cd_capability_compat(struct udev *udev, int fd)
212 {
213 int capability;
214
215 capability = ioctl(fd, CDROM_GET_CAPABILITY, NULL);
216 if (capability < 0) {
217 log_debug("CDROM_GET_CAPABILITY failed");
218 return -1;
219 }
220
221 if (capability & CDC_CD_R)
222 cd_cd_r = 1;
223 if (capability & CDC_CD_RW)
224 cd_cd_rw = 1;
225 if (capability & CDC_DVD)
226 cd_dvd_rom = 1;
227 if (capability & CDC_DVD_R)
228 cd_dvd_r = 1;
229 if (capability & CDC_DVD_RAM)
230 cd_dvd_ram = 1;
231 if (capability & CDC_MRW)
232 cd_mrw = 1;
233 if (capability & CDC_MRW_W)
234 cd_mrw_w = 1;
235 return 0;
236 }
237
238 static int cd_media_compat(struct udev *udev, int fd)
239 {
240 if (ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT) != CDS_DISC_OK) {
241 log_debug("CDROM_DRIVE_STATUS != CDS_DISC_OK");
242 return -1;
243 }
244 cd_media = 1;
245 return 0;
246 }
247
248 static int cd_inquiry(struct udev *udev, int fd)
249 {
250 struct scsi_cmd sc;
251 unsigned char inq[128];
252 int err;
253
254 scsi_cmd_init(udev, &sc);
255 scsi_cmd_set(udev, &sc, 0, 0x12);
256 scsi_cmd_set(udev, &sc, 4, 36);
257 scsi_cmd_set(udev, &sc, 5, 0);
258 err = scsi_cmd_run(udev, &sc, fd, inq, 36);
259 if ((err != 0)) {
260 info_scsi_cmd_err(udev, "INQUIRY", err);
261 return -1;
262 }
263
264 if ((inq[0] & 0x1F) != 5) {
265 log_debug("not an MMC unit");
266 return -1;
267 }
268
269 log_debug("INQUIRY: [%.8s][%.16s][%.4s]", inq + 8, inq + 16, inq + 32);
270 return 0;
271 }
272
273 static void feature_profile_media(struct udev *udev, int cur_profile)
274 {
275 switch (cur_profile) {
276 case 0x03:
277 case 0x04:
278 case 0x05:
279 log_debug("profile 0x%02x ", cur_profile);
280 cd_media = 1;
281 cd_media_mo = 1;
282 break;
283 case 0x08:
284 log_debug("profile 0x%02x media_cd_rom", cur_profile);
285 cd_media = 1;
286 cd_media_cd_rom = 1;
287 break;
288 case 0x09:
289 log_debug("profile 0x%02x media_cd_r", cur_profile);
290 cd_media = 1;
291 cd_media_cd_r = 1;
292 break;
293 case 0x0a:
294 log_debug("profile 0x%02x media_cd_rw", cur_profile);
295 cd_media = 1;
296 cd_media_cd_rw = 1;
297 break;
298 case 0x10:
299 log_debug("profile 0x%02x media_dvd_ro", cur_profile);
300 cd_media = 1;
301 cd_media_dvd_rom = 1;
302 break;
303 case 0x11:
304 log_debug("profile 0x%02x media_dvd_r", cur_profile);
305 cd_media = 1;
306 cd_media_dvd_r = 1;
307 break;
308 case 0x12:
309 log_debug("profile 0x%02x media_dvd_ram", cur_profile);
310 cd_media = 1;
311 cd_media_dvd_ram = 1;
312 break;
313 case 0x13:
314 log_debug("profile 0x%02x media_dvd_rw_ro", cur_profile);
315 cd_media = 1;
316 cd_media_dvd_rw = 1;
317 cd_media_dvd_rw_ro = 1;
318 break;
319 case 0x14:
320 log_debug("profile 0x%02x media_dvd_rw_seq", cur_profile);
321 cd_media = 1;
322 cd_media_dvd_rw = 1;
323 cd_media_dvd_rw_seq = 1;
324 break;
325 case 0x1B:
326 log_debug("profile 0x%02x media_dvd_plus_r", cur_profile);
327 cd_media = 1;
328 cd_media_dvd_plus_r = 1;
329 break;
330 case 0x1A:
331 log_debug("profile 0x%02x media_dvd_plus_rw", cur_profile);
332 cd_media = 1;
333 cd_media_dvd_plus_rw = 1;
334 break;
335 case 0x2A:
336 log_debug("profile 0x%02x media_dvd_plus_rw_dl", cur_profile);
337 cd_media = 1;
338 cd_media_dvd_plus_rw_dl = 1;
339 break;
340 case 0x2B:
341 log_debug("profile 0x%02x media_dvd_plus_r_dl", cur_profile);
342 cd_media = 1;
343 cd_media_dvd_plus_r_dl = 1;
344 break;
345 case 0x40:
346 log_debug("profile 0x%02x media_bd", cur_profile);
347 cd_media = 1;
348 cd_media_bd = 1;
349 break;
350 case 0x41:
351 case 0x42:
352 log_debug("profile 0x%02x media_bd_r", cur_profile);
353 cd_media = 1;
354 cd_media_bd_r = 1;
355 break;
356 case 0x43:
357 log_debug("profile 0x%02x media_bd_re", cur_profile);
358 cd_media = 1;
359 cd_media_bd_re = 1;
360 break;
361 case 0x50:
362 log_debug("profile 0x%02x media_hddvd", cur_profile);
363 cd_media = 1;
364 cd_media_hddvd = 1;
365 break;
366 case 0x51:
367 log_debug("profile 0x%02x media_hddvd_r", cur_profile);
368 cd_media = 1;
369 cd_media_hddvd_r = 1;
370 break;
371 case 0x52:
372 log_debug("profile 0x%02x media_hddvd_rw", cur_profile);
373 cd_media = 1;
374 cd_media_hddvd_rw = 1;
375 break;
376 default:
377 log_debug("profile 0x%02x <ignored>", cur_profile);
378 break;
379 }
380 }
381
382 static int feature_profiles(struct udev *udev, const unsigned char *profiles, size_t size)
383 {
384 unsigned int i;
385
386 for (i = 0; i+4 <= size; i += 4) {
387 int profile;
388
389 profile = profiles[i] << 8 | profiles[i+1];
390 switch (profile) {
391 case 0x03:
392 case 0x04:
393 case 0x05:
394 log_debug("profile 0x%02x mo", profile);
395 cd_mo = 1;
396 break;
397 case 0x08:
398 log_debug("profile 0x%02x cd_rom", profile);
399 cd_cd_rom = 1;
400 break;
401 case 0x09:
402 log_debug("profile 0x%02x cd_r", profile);
403 cd_cd_r = 1;
404 break;
405 case 0x0A:
406 log_debug("profile 0x%02x cd_rw", profile);
407 cd_cd_rw = 1;
408 break;
409 case 0x10:
410 log_debug("profile 0x%02x dvd_rom", profile);
411 cd_dvd_rom = 1;
412 break;
413 case 0x12:
414 log_debug("profile 0x%02x dvd_ram", profile);
415 cd_dvd_ram = 1;
416 break;
417 case 0x13:
418 case 0x14:
419 log_debug("profile 0x%02x dvd_rw", profile);
420 cd_dvd_rw = 1;
421 break;
422 case 0x1B:
423 log_debug("profile 0x%02x dvd_plus_r", profile);
424 cd_dvd_plus_r = 1;
425 break;
426 case 0x1A:
427 log_debug("profile 0x%02x dvd_plus_rw", profile);
428 cd_dvd_plus_rw = 1;
429 break;
430 case 0x2A:
431 log_debug("profile 0x%02x dvd_plus_rw_dl", profile);
432 cd_dvd_plus_rw_dl = 1;
433 break;
434 case 0x2B:
435 log_debug("profile 0x%02x dvd_plus_r_dl", profile);
436 cd_dvd_plus_r_dl = 1;
437 break;
438 case 0x40:
439 cd_bd = 1;
440 log_debug("profile 0x%02x bd", profile);
441 break;
442 case 0x41:
443 case 0x42:
444 cd_bd_r = 1;
445 log_debug("profile 0x%02x bd_r", profile);
446 break;
447 case 0x43:
448 cd_bd_re = 1;
449 log_debug("profile 0x%02x bd_re", profile);
450 break;
451 case 0x50:
452 cd_hddvd = 1;
453 log_debug("profile 0x%02x hddvd", profile);
454 break;
455 case 0x51:
456 cd_hddvd_r = 1;
457 log_debug("profile 0x%02x hddvd_r", profile);
458 break;
459 case 0x52:
460 cd_hddvd_rw = 1;
461 log_debug("profile 0x%02x hddvd_rw", profile);
462 break;
463 default:
464 log_debug("profile 0x%02x <ignored>", profile);
465 break;
466 }
467 }
468 return 0;
469 }
470
471 /* returns 0 if media was detected */
472 static int cd_profiles_old_mmc(struct udev *udev, int fd)
473 {
474 struct scsi_cmd sc;
475 int err;
476
477 unsigned char header[32];
478
479 scsi_cmd_init(udev, &sc);
480 scsi_cmd_set(udev, &sc, 0, 0x51);
481 scsi_cmd_set(udev, &sc, 8, sizeof(header));
482 scsi_cmd_set(udev, &sc, 9, 0);
483 err = scsi_cmd_run(udev, &sc, fd, header, sizeof(header));
484 if ((err != 0)) {
485 info_scsi_cmd_err(udev, "READ DISC INFORMATION", err);
486 if (cd_media == 1) {
487 log_debug("no current profile, but disc is present; assuming CD-ROM");
488 cd_media_cd_rom = 1;
489 cd_media_track_count = 1;
490 cd_media_track_count_data = 1;
491 return 0;
492 } else {
493 log_debug("no current profile, assuming no media");
494 return -1;
495 }
496 };
497
498 cd_media = 1;
499
500 if (header[2] & 16) {
501 cd_media_cd_rw = 1;
502 log_debug("profile 0x0a media_cd_rw");
503 } else if ((header[2] & 3) < 2 && cd_cd_r) {
504 cd_media_cd_r = 1;
505 log_debug("profile 0x09 media_cd_r");
506 } else {
507 cd_media_cd_rom = 1;
508 log_debug("profile 0x08 media_cd_rom");
509 }
510 return 0;
511 }
512
513 /* returns 0 if media was detected */
514 static int cd_profiles(struct udev *udev, int fd)
515 {
516 struct scsi_cmd sc;
517 unsigned char features[65530];
518 unsigned int cur_profile = 0;
519 unsigned int len;
520 unsigned int i;
521 int err;
522 int ret;
523
524 ret = -1;
525
526 /* First query the current profile */
527 scsi_cmd_init(udev, &sc);
528 scsi_cmd_set(udev, &sc, 0, 0x46);
529 scsi_cmd_set(udev, &sc, 8, 8);
530 scsi_cmd_set(udev, &sc, 9, 0);
531 err = scsi_cmd_run(udev, &sc, fd, features, 8);
532 if ((err != 0)) {
533 info_scsi_cmd_err(udev, "GET CONFIGURATION", err);
534 /* handle pre-MMC2 drives which do not support GET CONFIGURATION */
535 if (SK(err) == 0x5 && IN_SET(ASC(err), 0x20, 0x24)) {
536 log_debug("drive is pre-MMC2 and does not support 46h get configuration command");
537 log_debug("trying to work around the problem");
538 ret = cd_profiles_old_mmc(udev, fd);
539 }
540 goto out;
541 }
542
543 cur_profile = features[6] << 8 | features[7];
544 if (cur_profile > 0) {
545 log_debug("current profile 0x%02x", cur_profile);
546 feature_profile_media (udev, cur_profile);
547 ret = 0; /* we have media */
548 } else {
549 log_debug("no current profile, assuming no media");
550 }
551
552 len = features[0] << 24 | features[1] << 16 | features[2] << 8 | features[3];
553 log_debug("GET CONFIGURATION: size of features buffer 0x%04x", len);
554
555 if (len > sizeof(features)) {
556 log_debug("cannot get features in a single query, truncating");
557 len = sizeof(features);
558 } else if (len <= 8)
559 len = sizeof(features);
560
561 /* Now get the full feature buffer */
562 scsi_cmd_init(udev, &sc);
563 scsi_cmd_set(udev, &sc, 0, 0x46);
564 scsi_cmd_set(udev, &sc, 7, ( len >> 8 ) & 0xff);
565 scsi_cmd_set(udev, &sc, 8, len & 0xff);
566 scsi_cmd_set(udev, &sc, 9, 0);
567 err = scsi_cmd_run(udev, &sc, fd, features, len);
568 if ((err != 0)) {
569 info_scsi_cmd_err(udev, "GET CONFIGURATION", err);
570 return -1;
571 }
572
573 /* parse the length once more, in case the drive decided to have other features suddenly :) */
574 len = features[0] << 24 | features[1] << 16 | features[2] << 8 | features[3];
575 log_debug("GET CONFIGURATION: size of features buffer 0x%04x", len);
576
577 if (len > sizeof(features)) {
578 log_debug("cannot get features in a single query, truncating");
579 len = sizeof(features);
580 }
581
582 /* device features */
583 for (i = 8; i+4 < len; i += (4 + features[i+3])) {
584 unsigned int feature;
585
586 feature = features[i] << 8 | features[i+1];
587
588 switch (feature) {
589 case 0x00:
590 log_debug("GET CONFIGURATION: feature 'profiles', with %i entries", features[i+3] / 4);
591 feature_profiles(udev, &features[i]+4, MIN(features[i+3], len - i - 4));
592 break;
593 default:
594 log_debug("GET CONFIGURATION: feature 0x%04x <ignored>, with 0x%02x bytes", feature, features[i+3]);
595 break;
596 }
597 }
598 out:
599 return ret;
600 }
601
602 static int cd_media_info(struct udev *udev, int fd)
603 {
604 struct scsi_cmd sc;
605 unsigned char header[32];
606 static const char *media_status[] = {
607 "blank",
608 "appendable",
609 "complete",
610 "other"
611 };
612 int err;
613
614 scsi_cmd_init(udev, &sc);
615 scsi_cmd_set(udev, &sc, 0, 0x51);
616 scsi_cmd_set(udev, &sc, 8, sizeof(header) & 0xff);
617 scsi_cmd_set(udev, &sc, 9, 0);
618 err = scsi_cmd_run(udev, &sc, fd, header, sizeof(header));
619 if ((err != 0)) {
620 info_scsi_cmd_err(udev, "READ DISC INFORMATION", err);
621 return -1;
622 };
623
624 cd_media = 1;
625 log_debug("disk type %02x", header[8]);
626 log_debug("hardware reported media status: %s", media_status[header[2] & 3]);
627
628 /* exclude plain CDROM, some fake cdroms return 0 for "blank" media here */
629 if (!cd_media_cd_rom)
630 cd_media_state = media_status[header[2] & 3];
631
632 /* fresh DVD-RW in restricted overwite mode reports itself as
633 * "appendable"; change it to "blank" to make it consistent with what
634 * gets reported after blanking, and what userspace expects */
635 if (cd_media_dvd_rw_ro && (header[2] & 3) == 1)
636 cd_media_state = media_status[0];
637
638 /* DVD+RW discs (and DVD-RW in restricted mode) once formatted are
639 * always "complete", DVD-RAM are "other" or "complete" if the disc is
640 * write protected; we need to check the contents if it is blank */
641 if ((cd_media_dvd_rw_ro || cd_media_dvd_plus_rw || cd_media_dvd_plus_rw_dl || cd_media_dvd_ram) && (header[2] & 3) > 1) {
642 unsigned char buffer[32 * 2048];
643 unsigned char len;
644 int offset;
645
646 if (cd_media_dvd_ram) {
647 /* a write protected dvd-ram may report "complete" status */
648
649 unsigned char dvdstruct[8];
650 unsigned char format[12];
651
652 scsi_cmd_init(udev, &sc);
653 scsi_cmd_set(udev, &sc, 0, 0xAD);
654 scsi_cmd_set(udev, &sc, 7, 0xC0);
655 scsi_cmd_set(udev, &sc, 9, sizeof(dvdstruct));
656 scsi_cmd_set(udev, &sc, 11, 0);
657 err = scsi_cmd_run(udev, &sc, fd, dvdstruct, sizeof(dvdstruct));
658 if ((err != 0)) {
659 info_scsi_cmd_err(udev, "READ DVD STRUCTURE", err);
660 return -1;
661 }
662 if (dvdstruct[4] & 0x02) {
663 cd_media_state = media_status[2];
664 log_debug("write-protected DVD-RAM media inserted");
665 goto determined;
666 }
667
668 /* let's make sure we don't try to read unformatted media */
669 scsi_cmd_init(udev, &sc);
670 scsi_cmd_set(udev, &sc, 0, 0x23);
671 scsi_cmd_set(udev, &sc, 8, sizeof(format));
672 scsi_cmd_set(udev, &sc, 9, 0);
673 err = scsi_cmd_run(udev, &sc, fd, format, sizeof(format));
674 if ((err != 0)) {
675 info_scsi_cmd_err(udev, "READ DVD FORMAT CAPACITIES", err);
676 return -1;
677 }
678
679 len = format[3];
680 if (len & 7 || len < 16) {
681 log_debug("invalid format capacities length");
682 return -1;
683 }
684
685 switch(format[8] & 3) {
686 case 1:
687 log_debug("unformatted DVD-RAM media inserted");
688 /* This means that last format was interrupted
689 * or failed, blank dvd-ram discs are factory
690 * formatted. Take no action here as it takes
691 * quite a while to reformat a dvd-ram and it's
692 * not automatically started */
693 goto determined;
694
695 case 2:
696 log_debug("formatted DVD-RAM media inserted");
697 break;
698
699 case 3:
700 cd_media = 0; //return no media
701 log_debug("format capacities returned no media");
702 return -1;
703 }
704 }
705
706 /* Take a closer look at formatted media (unformatted DVD+RW
707 * has "blank" status", DVD-RAM was examined earlier) and check
708 * for ISO and UDF PVDs or a fs superblock presence and do it
709 * in one ioctl (we need just sectors 0 and 16) */
710 scsi_cmd_init(udev, &sc);
711 scsi_cmd_set(udev, &sc, 0, 0x28);
712 scsi_cmd_set(udev, &sc, 5, 0);
713 scsi_cmd_set(udev, &sc, 8, 32);
714 scsi_cmd_set(udev, &sc, 9, 0);
715 err = scsi_cmd_run(udev, &sc, fd, buffer, sizeof(buffer));
716 if ((err != 0)) {
717 cd_media = 0;
718 info_scsi_cmd_err(udev, "READ FIRST 32 BLOCKS", err);
719 return -1;
720 }
721
722 /* if any non-zero data is found in sector 16 (iso and udf) or
723 * eventually 0 (fat32 boot sector, ext2 superblock, etc), disc
724 * is assumed non-blank */
725
726 for (offset = 32768; offset < (32768 + 2048); offset++) {
727 if (buffer [offset]) {
728 log_debug("data in block 16, assuming complete");
729 goto determined;
730 }
731 }
732
733 for (offset = 0; offset < 2048; offset++) {
734 if (buffer [offset]) {
735 log_debug("data in block 0, assuming complete");
736 goto determined;
737 }
738 }
739
740 cd_media_state = media_status[0];
741 log_debug("no data in blocks 0 or 16, assuming blank");
742 }
743
744 determined:
745 /* "other" is e. g. DVD-RAM, can't append sessions there; DVDs in
746 * restricted overwrite mode can never append, only in sequential mode */
747 if ((header[2] & 3) < 2 && !cd_media_dvd_rw_ro)
748 cd_media_session_next = header[10] << 8 | header[5];
749 cd_media_session_count = header[9] << 8 | header[4];
750 cd_media_track_count = header[11] << 8 | header[6];
751
752 return 0;
753 }
754
755 static int cd_media_toc(struct udev *udev, int fd)
756 {
757 struct scsi_cmd sc;
758 unsigned char header[12];
759 unsigned char toc[65536];
760 unsigned int len, i, num_tracks;
761 unsigned char *p;
762 int err;
763
764 scsi_cmd_init(udev, &sc);
765 scsi_cmd_set(udev, &sc, 0, 0x43);
766 scsi_cmd_set(udev, &sc, 6, 1);
767 scsi_cmd_set(udev, &sc, 8, sizeof(header) & 0xff);
768 scsi_cmd_set(udev, &sc, 9, 0);
769 err = scsi_cmd_run(udev, &sc, fd, header, sizeof(header));
770 if ((err != 0)) {
771 info_scsi_cmd_err(udev, "READ TOC", err);
772 return -1;
773 }
774
775 len = (header[0] << 8 | header[1]) + 2;
776 log_debug("READ TOC: len: %d, start track: %d, end track: %d", len, header[2], header[3]);
777 if (len > sizeof(toc))
778 return -1;
779 if (len < 2)
780 return -1;
781 /* 2: first track, 3: last track */
782 num_tracks = header[3] - header[2] + 1;
783
784 /* empty media has no tracks */
785 if (len < 8)
786 return 0;
787
788 scsi_cmd_init(udev, &sc);
789 scsi_cmd_set(udev, &sc, 0, 0x43);
790 scsi_cmd_set(udev, &sc, 6, header[2]); /* First Track/Session Number */
791 scsi_cmd_set(udev, &sc, 7, (len >> 8) & 0xff);
792 scsi_cmd_set(udev, &sc, 8, len & 0xff);
793 scsi_cmd_set(udev, &sc, 9, 0);
794 err = scsi_cmd_run(udev, &sc, fd, toc, len);
795 if ((err != 0)) {
796 info_scsi_cmd_err(udev, "READ TOC (tracks)", err);
797 return -1;
798 }
799
800 /* Take care to not iterate beyond the last valid track as specified in
801 * the TOC, but also avoid going beyond the TOC length, just in case
802 * the last track number is invalidly large */
803 for (p = toc+4, i = 4; i < len-8 && num_tracks > 0; i += 8, p += 8, --num_tracks) {
804 unsigned int block;
805 unsigned int is_data_track;
806
807 is_data_track = (p[1] & 0x04) != 0;
808
809 block = p[4] << 24 | p[5] << 16 | p[6] << 8 | p[7];
810 log_debug("track=%u info=0x%x(%s) start_block=%u",
811 p[2], p[1] & 0x0f, is_data_track ? "data":"audio", block);
812
813 if (is_data_track)
814 cd_media_track_count_data++;
815 else
816 cd_media_track_count_audio++;
817 }
818
819 scsi_cmd_init(udev, &sc);
820 scsi_cmd_set(udev, &sc, 0, 0x43);
821 scsi_cmd_set(udev, &sc, 2, 1); /* Session Info */
822 scsi_cmd_set(udev, &sc, 8, sizeof(header));
823 scsi_cmd_set(udev, &sc, 9, 0);
824 err = scsi_cmd_run(udev, &sc, fd, header, sizeof(header));
825 if ((err != 0)) {
826 info_scsi_cmd_err(udev, "READ TOC (multi session)", err);
827 return -1;
828 }
829 len = header[4+4] << 24 | header[4+5] << 16 | header[4+6] << 8 | header[4+7];
830 log_debug("last track %u starts at block %u", header[4+2], len);
831 cd_media_session_last_offset = (unsigned long long int)len * 2048;
832 return 0;
833 }
834
835 int main(int argc, char *argv[]) {
836 struct udev *udev;
837 static const struct option options[] = {
838 { "lock-media", no_argument, NULL, 'l' },
839 { "unlock-media", no_argument, NULL, 'u' },
840 { "eject-media", no_argument, NULL, 'e' },
841 { "debug", no_argument, NULL, 'd' },
842 { "help", no_argument, NULL, 'h' },
843 {}
844 };
845 bool eject = false;
846 bool lock = false;
847 bool unlock = false;
848 const char *node = NULL;
849 int fd = -1;
850 int cnt;
851 int rc = 0;
852
853 log_set_target(LOG_TARGET_AUTO);
854 udev_parse_config();
855 log_parse_environment();
856 log_open();
857
858 udev = udev_new();
859 if (udev == NULL)
860 goto exit;
861
862 for (;;) {
863 int option;
864
865 option = getopt_long(argc, argv, "deluh", options, NULL);
866 if (option == -1)
867 break;
868
869 switch (option) {
870 case 'l':
871 lock = true;
872 break;
873 case 'u':
874 unlock = true;
875 break;
876 case 'e':
877 eject = true;
878 break;
879 case 'd':
880 log_set_target(LOG_TARGET_CONSOLE);
881 log_set_max_level(LOG_DEBUG);
882 log_open();
883 break;
884 case 'h':
885 printf("Usage: cdrom_id [options] <device>\n"
886 " -l,--lock-media lock the media (to enable eject request events)\n"
887 " -u,--unlock-media unlock the media\n"
888 " -e,--eject-media eject the media\n"
889 " -d,--debug debug to stderr\n"
890 " -h,--help print this help text\n\n");
891 goto exit;
892 default:
893 rc = 1;
894 goto exit;
895 }
896 }
897
898 node = argv[optind];
899 if (!node) {
900 log_error("no device");
901 fprintf(stderr, "no device\n");
902 rc = 1;
903 goto exit;
904 }
905
906 initialize_srand();
907 for (cnt = 20; cnt > 0; cnt--) {
908 struct timespec duration;
909
910 fd = open(node, O_RDONLY|O_NONBLOCK|O_CLOEXEC|(is_mounted(node) ? 0 : O_EXCL));
911 if (fd >= 0 || errno != EBUSY)
912 break;
913 duration.tv_sec = 0;
914 duration.tv_nsec = (100 * 1000 * 1000) + (rand() % 100 * 1000 * 1000);
915 nanosleep(&duration, NULL);
916 }
917 if (fd < 0) {
918 log_debug("unable to open '%s'", node);
919 fprintf(stderr, "unable to open '%s'\n", node);
920 rc = 1;
921 goto exit;
922 }
923 log_debug("probing: '%s'", node);
924
925 /* same data as original cdrom_id */
926 if (cd_capability_compat(udev, fd) < 0) {
927 rc = 1;
928 goto exit;
929 }
930
931 /* check for media - don't bail if there's no media as we still need to
932 * to read profiles */
933 cd_media_compat(udev, fd);
934
935 /* check if drive talks MMC */
936 if (cd_inquiry(udev, fd) < 0)
937 goto work;
938
939 /* read drive and possibly current profile */
940 if (cd_profiles(udev, fd) != 0)
941 goto work;
942
943 /* at this point we are guaranteed to have media in the drive - find out more about it */
944
945 /* get session/track info */
946 cd_media_toc(udev, fd);
947
948 /* get writable media state */
949 cd_media_info(udev, fd);
950
951 work:
952 /* lock the media, so we enable eject button events */
953 if (lock && cd_media) {
954 log_debug("PREVENT_ALLOW_MEDIUM_REMOVAL (lock)");
955 media_lock(udev, fd, true);
956 }
957
958 if (unlock && cd_media) {
959 log_debug("PREVENT_ALLOW_MEDIUM_REMOVAL (unlock)");
960 media_lock(udev, fd, false);
961 }
962
963 if (eject) {
964 log_debug("PREVENT_ALLOW_MEDIUM_REMOVAL (unlock)");
965 media_lock(udev, fd, false);
966 log_debug("START_STOP_UNIT (eject)");
967 media_eject(udev, fd);
968 }
969
970 printf("ID_CDROM=1\n");
971 if (cd_cd_rom)
972 printf("ID_CDROM_CD=1\n");
973 if (cd_cd_r)
974 printf("ID_CDROM_CD_R=1\n");
975 if (cd_cd_rw)
976 printf("ID_CDROM_CD_RW=1\n");
977 if (cd_dvd_rom)
978 printf("ID_CDROM_DVD=1\n");
979 if (cd_dvd_r)
980 printf("ID_CDROM_DVD_R=1\n");
981 if (cd_dvd_rw)
982 printf("ID_CDROM_DVD_RW=1\n");
983 if (cd_dvd_ram)
984 printf("ID_CDROM_DVD_RAM=1\n");
985 if (cd_dvd_plus_r)
986 printf("ID_CDROM_DVD_PLUS_R=1\n");
987 if (cd_dvd_plus_rw)
988 printf("ID_CDROM_DVD_PLUS_RW=1\n");
989 if (cd_dvd_plus_r_dl)
990 printf("ID_CDROM_DVD_PLUS_R_DL=1\n");
991 if (cd_dvd_plus_rw_dl)
992 printf("ID_CDROM_DVD_PLUS_RW_DL=1\n");
993 if (cd_bd)
994 printf("ID_CDROM_BD=1\n");
995 if (cd_bd_r)
996 printf("ID_CDROM_BD_R=1\n");
997 if (cd_bd_re)
998 printf("ID_CDROM_BD_RE=1\n");
999 if (cd_hddvd)
1000 printf("ID_CDROM_HDDVD=1\n");
1001 if (cd_hddvd_r)
1002 printf("ID_CDROM_HDDVD_R=1\n");
1003 if (cd_hddvd_rw)
1004 printf("ID_CDROM_HDDVD_RW=1\n");
1005 if (cd_mo)
1006 printf("ID_CDROM_MO=1\n");
1007 if (cd_mrw)
1008 printf("ID_CDROM_MRW=1\n");
1009 if (cd_mrw_w)
1010 printf("ID_CDROM_MRW_W=1\n");
1011
1012 if (cd_media)
1013 printf("ID_CDROM_MEDIA=1\n");
1014 if (cd_media_mo)
1015 printf("ID_CDROM_MEDIA_MO=1\n");
1016 if (cd_media_mrw)
1017 printf("ID_CDROM_MEDIA_MRW=1\n");
1018 if (cd_media_mrw_w)
1019 printf("ID_CDROM_MEDIA_MRW_W=1\n");
1020 if (cd_media_cd_rom)
1021 printf("ID_CDROM_MEDIA_CD=1\n");
1022 if (cd_media_cd_r)
1023 printf("ID_CDROM_MEDIA_CD_R=1\n");
1024 if (cd_media_cd_rw)
1025 printf("ID_CDROM_MEDIA_CD_RW=1\n");
1026 if (cd_media_dvd_rom)
1027 printf("ID_CDROM_MEDIA_DVD=1\n");
1028 if (cd_media_dvd_r)
1029 printf("ID_CDROM_MEDIA_DVD_R=1\n");
1030 if (cd_media_dvd_ram)
1031 printf("ID_CDROM_MEDIA_DVD_RAM=1\n");
1032 if (cd_media_dvd_rw)
1033 printf("ID_CDROM_MEDIA_DVD_RW=1\n");
1034 if (cd_media_dvd_plus_r)
1035 printf("ID_CDROM_MEDIA_DVD_PLUS_R=1\n");
1036 if (cd_media_dvd_plus_rw)
1037 printf("ID_CDROM_MEDIA_DVD_PLUS_RW=1\n");
1038 if (cd_media_dvd_plus_rw_dl)
1039 printf("ID_CDROM_MEDIA_DVD_PLUS_RW_DL=1\n");
1040 if (cd_media_dvd_plus_r_dl)
1041 printf("ID_CDROM_MEDIA_DVD_PLUS_R_DL=1\n");
1042 if (cd_media_bd)
1043 printf("ID_CDROM_MEDIA_BD=1\n");
1044 if (cd_media_bd_r)
1045 printf("ID_CDROM_MEDIA_BD_R=1\n");
1046 if (cd_media_bd_re)
1047 printf("ID_CDROM_MEDIA_BD_RE=1\n");
1048 if (cd_media_hddvd)
1049 printf("ID_CDROM_MEDIA_HDDVD=1\n");
1050 if (cd_media_hddvd_r)
1051 printf("ID_CDROM_MEDIA_HDDVD_R=1\n");
1052 if (cd_media_hddvd_rw)
1053 printf("ID_CDROM_MEDIA_HDDVD_RW=1\n");
1054
1055 if (cd_media_state != NULL)
1056 printf("ID_CDROM_MEDIA_STATE=%s\n", cd_media_state);
1057 if (cd_media_session_next > 0)
1058 printf("ID_CDROM_MEDIA_SESSION_NEXT=%u\n", cd_media_session_next);
1059 if (cd_media_session_count > 0)
1060 printf("ID_CDROM_MEDIA_SESSION_COUNT=%u\n", cd_media_session_count);
1061 if (cd_media_session_count > 1 && cd_media_session_last_offset > 0)
1062 printf("ID_CDROM_MEDIA_SESSION_LAST_OFFSET=%llu\n", cd_media_session_last_offset);
1063 if (cd_media_track_count > 0)
1064 printf("ID_CDROM_MEDIA_TRACK_COUNT=%u\n", cd_media_track_count);
1065 if (cd_media_track_count_audio > 0)
1066 printf("ID_CDROM_MEDIA_TRACK_COUNT_AUDIO=%u\n", cd_media_track_count_audio);
1067 if (cd_media_track_count_data > 0)
1068 printf("ID_CDROM_MEDIA_TRACK_COUNT_DATA=%u\n", cd_media_track_count_data);
1069 exit:
1070 if (fd >= 0)
1071 close(fd);
1072 udev_unref(udev);
1073 log_close();
1074 return rc;
1075 }