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