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