199ca880aSopenharmony_ci/*
299ca880aSopenharmony_ci * cdrom_id - optical drive and media information prober
399ca880aSopenharmony_ci *
499ca880aSopenharmony_ci * Copyright (C) 2008-2010 Kay Sievers <kay@vrfy.org>
599ca880aSopenharmony_ci *
699ca880aSopenharmony_ci * This program is free software: you can redistribute it and/or modify
799ca880aSopenharmony_ci * it under the terms of the GNU General Public License as published by
899ca880aSopenharmony_ci * the Free Software Foundation, either version 2 of the License, or
999ca880aSopenharmony_ci * (at your option) any later version.
1099ca880aSopenharmony_ci *
1199ca880aSopenharmony_ci * This program is distributed in the hope that it will be useful,
1299ca880aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
1399ca880aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1499ca880aSopenharmony_ci * GNU General Public License for more details.
1599ca880aSopenharmony_ci *
1699ca880aSopenharmony_ci * You should have received a copy of the GNU General Public License
1799ca880aSopenharmony_ci * along with this program.  If not, see <http://www.gnu.org/licenses/>.
1899ca880aSopenharmony_ci */
1999ca880aSopenharmony_ci
2099ca880aSopenharmony_ci#ifndef _GNU_SOURCE
2199ca880aSopenharmony_ci#define _GNU_SOURCE 1
2299ca880aSopenharmony_ci#endif
2399ca880aSopenharmony_ci
2499ca880aSopenharmony_ci#include <stdio.h>
2599ca880aSopenharmony_ci#include <stddef.h>
2699ca880aSopenharmony_ci#include <stdlib.h>
2799ca880aSopenharmony_ci#include <unistd.h>
2899ca880aSopenharmony_ci#include <string.h>
2999ca880aSopenharmony_ci#include <limits.h>
3099ca880aSopenharmony_ci#include <fcntl.h>
3199ca880aSopenharmony_ci#include <errno.h>
3299ca880aSopenharmony_ci#include <getopt.h>
3399ca880aSopenharmony_ci#include <time.h>
3499ca880aSopenharmony_ci#include <scsi/sg.h>
3599ca880aSopenharmony_ci#include <sys/types.h>
3699ca880aSopenharmony_ci#include <sys/stat.h>
3799ca880aSopenharmony_ci#include <sys/time.h>
3899ca880aSopenharmony_ci#include <sys/ioctl.h>
3999ca880aSopenharmony_ci#include <linux/cdrom.h>
4099ca880aSopenharmony_ci#include <sys/sysmacros.h>
4199ca880aSopenharmony_ci
4299ca880aSopenharmony_ci#include "libudev.h"
4399ca880aSopenharmony_ci#include "libudev-private.h"
4499ca880aSopenharmony_ci#include "random-util.h"
4599ca880aSopenharmony_ci
4699ca880aSopenharmony_ci/* device info */
4799ca880aSopenharmony_cistatic unsigned int cd_cd_rom;
4899ca880aSopenharmony_cistatic unsigned int cd_cd_r;
4999ca880aSopenharmony_cistatic unsigned int cd_cd_rw;
5099ca880aSopenharmony_cistatic unsigned int cd_dvd_rom;
5199ca880aSopenharmony_cistatic unsigned int cd_dvd_r;
5299ca880aSopenharmony_cistatic unsigned int cd_dvd_rw;
5399ca880aSopenharmony_cistatic unsigned int cd_dvd_ram;
5499ca880aSopenharmony_cistatic unsigned int cd_dvd_plus_r;
5599ca880aSopenharmony_cistatic unsigned int cd_dvd_plus_rw;
5699ca880aSopenharmony_cistatic unsigned int cd_dvd_plus_r_dl;
5799ca880aSopenharmony_cistatic unsigned int cd_dvd_plus_rw_dl;
5899ca880aSopenharmony_cistatic unsigned int cd_bd;
5999ca880aSopenharmony_cistatic unsigned int cd_bd_r;
6099ca880aSopenharmony_cistatic unsigned int cd_bd_re;
6199ca880aSopenharmony_cistatic unsigned int cd_hddvd;
6299ca880aSopenharmony_cistatic unsigned int cd_hddvd_r;
6399ca880aSopenharmony_cistatic unsigned int cd_hddvd_rw;
6499ca880aSopenharmony_cistatic unsigned int cd_mo;
6599ca880aSopenharmony_cistatic unsigned int cd_mrw;
6699ca880aSopenharmony_cistatic unsigned int cd_mrw_w;
6799ca880aSopenharmony_ci
6899ca880aSopenharmony_ci/* media info */
6999ca880aSopenharmony_cistatic unsigned int cd_media;
7099ca880aSopenharmony_cistatic unsigned int cd_media_cd_rom;
7199ca880aSopenharmony_cistatic unsigned int cd_media_cd_r;
7299ca880aSopenharmony_cistatic unsigned int cd_media_cd_rw;
7399ca880aSopenharmony_cistatic unsigned int cd_media_dvd_rom;
7499ca880aSopenharmony_cistatic unsigned int cd_media_dvd_r;
7599ca880aSopenharmony_cistatic unsigned int cd_media_dvd_rw;
7699ca880aSopenharmony_cistatic unsigned int cd_media_dvd_rw_ro; /* restricted overwrite mode */
7799ca880aSopenharmony_cistatic unsigned int cd_media_dvd_rw_seq; /* sequential mode */
7899ca880aSopenharmony_cistatic unsigned int cd_media_dvd_ram;
7999ca880aSopenharmony_cistatic unsigned int cd_media_dvd_plus_r;
8099ca880aSopenharmony_cistatic unsigned int cd_media_dvd_plus_rw;
8199ca880aSopenharmony_cistatic unsigned int cd_media_dvd_plus_r_dl;
8299ca880aSopenharmony_cistatic unsigned int cd_media_dvd_plus_rw_dl;
8399ca880aSopenharmony_cistatic unsigned int cd_media_bd;
8499ca880aSopenharmony_cistatic unsigned int cd_media_bd_r;
8599ca880aSopenharmony_cistatic unsigned int cd_media_bd_re;
8699ca880aSopenharmony_cistatic unsigned int cd_media_hddvd;
8799ca880aSopenharmony_cistatic unsigned int cd_media_hddvd_r;
8899ca880aSopenharmony_cistatic unsigned int cd_media_hddvd_rw;
8999ca880aSopenharmony_cistatic unsigned int cd_media_mo;
9099ca880aSopenharmony_cistatic unsigned int cd_media_mrw;
9199ca880aSopenharmony_cistatic unsigned int cd_media_mrw_w;
9299ca880aSopenharmony_ci
9399ca880aSopenharmony_cistatic const char *cd_media_state = NULL;
9499ca880aSopenharmony_cistatic unsigned int cd_media_session_next;
9599ca880aSopenharmony_cistatic unsigned int cd_media_session_count;
9699ca880aSopenharmony_cistatic unsigned int cd_media_track_count;
9799ca880aSopenharmony_cistatic unsigned int cd_media_track_count_data;
9899ca880aSopenharmony_cistatic unsigned int cd_media_track_count_audio;
9999ca880aSopenharmony_cistatic unsigned long long int cd_media_session_last_offset;
10099ca880aSopenharmony_ci
10199ca880aSopenharmony_ci#define ERRCODE(s)        ((((s)[2] & 0x0F) << 16) | ((s)[12] << 8) | ((s)[13]))
10299ca880aSopenharmony_ci#define SK(errcode)        (((errcode) >> 16) & 0xF)
10399ca880aSopenharmony_ci#define ASC(errcode)        (((errcode) >> 8) & 0xFF)
10499ca880aSopenharmony_ci#define ASCQ(errcode)        ((errcode) & 0xFF)
10599ca880aSopenharmony_ci
10699ca880aSopenharmony_cistatic bool is_mounted(const char *device)
10799ca880aSopenharmony_ci{
10899ca880aSopenharmony_ci        struct stat statbuf;
10999ca880aSopenharmony_ci        FILE *fp;
11099ca880aSopenharmony_ci        int maj, min;
11199ca880aSopenharmony_ci        bool mounted = false;
11299ca880aSopenharmony_ci
11399ca880aSopenharmony_ci        if (stat(device, &statbuf) < 0)
11499ca880aSopenharmony_ci                return -ENODEV;
11599ca880aSopenharmony_ci
11699ca880aSopenharmony_ci        fp = fopen("/proc/self/mountinfo", "re");
11799ca880aSopenharmony_ci        if (fp == NULL)
11899ca880aSopenharmony_ci                return -ENOSYS;
11999ca880aSopenharmony_ci        while (fscanf(fp, "%*s %*s %i:%i %*[^\n]", &maj, &min) == 2) {
12099ca880aSopenharmony_ci                if (makedev(maj, min) == statbuf.st_rdev) {
12199ca880aSopenharmony_ci                        mounted = true;
12299ca880aSopenharmony_ci                        break;
12399ca880aSopenharmony_ci                }
12499ca880aSopenharmony_ci        }
12599ca880aSopenharmony_ci        fclose(fp);
12699ca880aSopenharmony_ci        return mounted;
12799ca880aSopenharmony_ci}
12899ca880aSopenharmony_ci
12999ca880aSopenharmony_cistatic void info_scsi_cmd_err(struct udev *udev, const char *cmd, int err)
13099ca880aSopenharmony_ci{
13199ca880aSopenharmony_ci        if (err == -1) {
13299ca880aSopenharmony_ci                log_debug("%s failed", cmd);
13399ca880aSopenharmony_ci                return;
13499ca880aSopenharmony_ci        }
13599ca880aSopenharmony_ci        log_debug("%s failed with SK=%Xh/ASC=%02Xh/ACQ=%02Xh", cmd, SK(err), ASC(err), ASCQ(err));
13699ca880aSopenharmony_ci}
13799ca880aSopenharmony_ci
13899ca880aSopenharmony_cistruct scsi_cmd {
13999ca880aSopenharmony_ci        struct cdrom_generic_command cgc;
14099ca880aSopenharmony_ci        union {
14199ca880aSopenharmony_ci                struct request_sense s;
14299ca880aSopenharmony_ci                unsigned char u[18];
14399ca880aSopenharmony_ci        } _sense;
14499ca880aSopenharmony_ci        struct sg_io_hdr sg_io;
14599ca880aSopenharmony_ci};
14699ca880aSopenharmony_ci
14799ca880aSopenharmony_cistatic void scsi_cmd_init(struct udev *udev, struct scsi_cmd *cmd)
14899ca880aSopenharmony_ci{
14999ca880aSopenharmony_ci        memzero(cmd, sizeof(struct scsi_cmd));
15099ca880aSopenharmony_ci        cmd->cgc.quiet = 1;
15199ca880aSopenharmony_ci        cmd->cgc.sense = &cmd->_sense.s;
15299ca880aSopenharmony_ci        cmd->sg_io.interface_id = 'S';
15399ca880aSopenharmony_ci        cmd->sg_io.mx_sb_len = sizeof(cmd->_sense);
15499ca880aSopenharmony_ci        cmd->sg_io.cmdp = cmd->cgc.cmd;
15599ca880aSopenharmony_ci        cmd->sg_io.sbp = cmd->_sense.u;
15699ca880aSopenharmony_ci        cmd->sg_io.flags = SG_FLAG_LUN_INHIBIT | SG_FLAG_DIRECT_IO;
15799ca880aSopenharmony_ci}
15899ca880aSopenharmony_ci
15999ca880aSopenharmony_cistatic void scsi_cmd_set(struct udev *udev, struct scsi_cmd *cmd, size_t i, unsigned char arg)
16099ca880aSopenharmony_ci{
16199ca880aSopenharmony_ci        cmd->sg_io.cmd_len = i + 1;
16299ca880aSopenharmony_ci        cmd->cgc.cmd[i] = arg;
16399ca880aSopenharmony_ci}
16499ca880aSopenharmony_ci
16599ca880aSopenharmony_ci#define CHECK_CONDITION 0x01
16699ca880aSopenharmony_ci
16799ca880aSopenharmony_cistatic int scsi_cmd_run(struct udev *udev, struct scsi_cmd *cmd, int fd, unsigned char *buf, size_t bufsize)
16899ca880aSopenharmony_ci{
16999ca880aSopenharmony_ci        int ret = 0;
17099ca880aSopenharmony_ci
17199ca880aSopenharmony_ci        if (bufsize > 0) {
17299ca880aSopenharmony_ci                cmd->sg_io.dxferp = buf;
17399ca880aSopenharmony_ci                cmd->sg_io.dxfer_len = bufsize;
17499ca880aSopenharmony_ci                cmd->sg_io.dxfer_direction = SG_DXFER_FROM_DEV;
17599ca880aSopenharmony_ci        } else {
17699ca880aSopenharmony_ci                cmd->sg_io.dxfer_direction = SG_DXFER_NONE;
17799ca880aSopenharmony_ci        }
17899ca880aSopenharmony_ci        if (ioctl(fd, SG_IO, &cmd->sg_io))
17999ca880aSopenharmony_ci                return -1;
18099ca880aSopenharmony_ci
18199ca880aSopenharmony_ci        if ((cmd->sg_io.info & SG_INFO_OK_MASK) != SG_INFO_OK) {
18299ca880aSopenharmony_ci                errno = EIO;
18399ca880aSopenharmony_ci                ret = -1;
18499ca880aSopenharmony_ci                if (cmd->sg_io.masked_status & CHECK_CONDITION) {
18599ca880aSopenharmony_ci                        ret = ERRCODE(cmd->_sense.u);
18699ca880aSopenharmony_ci                        if (ret == 0)
18799ca880aSopenharmony_ci                                ret = -1;
18899ca880aSopenharmony_ci                }
18999ca880aSopenharmony_ci        }
19099ca880aSopenharmony_ci        return ret;
19199ca880aSopenharmony_ci}
19299ca880aSopenharmony_ci
19399ca880aSopenharmony_cistatic int media_lock(struct udev *udev, int fd, bool lock)
19499ca880aSopenharmony_ci{
19599ca880aSopenharmony_ci        int err;
19699ca880aSopenharmony_ci
19799ca880aSopenharmony_ci        /* disable the kernel's lock logic */
19899ca880aSopenharmony_ci        err = ioctl(fd, CDROM_CLEAR_OPTIONS, CDO_LOCK);
19999ca880aSopenharmony_ci        if (err < 0)
20099ca880aSopenharmony_ci                log_debug("CDROM_CLEAR_OPTIONS, CDO_LOCK failed");
20199ca880aSopenharmony_ci
20299ca880aSopenharmony_ci        err = ioctl(fd, CDROM_LOCKDOOR, lock ? 1 : 0);
20399ca880aSopenharmony_ci        if (err < 0)
20499ca880aSopenharmony_ci                log_debug("CDROM_LOCKDOOR failed");
20599ca880aSopenharmony_ci
20699ca880aSopenharmony_ci        return err;
20799ca880aSopenharmony_ci}
20899ca880aSopenharmony_ci
20999ca880aSopenharmony_cistatic int media_eject(struct udev *udev, int fd)
21099ca880aSopenharmony_ci{
21199ca880aSopenharmony_ci        struct scsi_cmd sc;
21299ca880aSopenharmony_ci        int err;
21399ca880aSopenharmony_ci
21499ca880aSopenharmony_ci        scsi_cmd_init(udev, &sc);
21599ca880aSopenharmony_ci        scsi_cmd_set(udev, &sc, 0, 0x1b);
21699ca880aSopenharmony_ci        scsi_cmd_set(udev, &sc, 4, 0x02);
21799ca880aSopenharmony_ci        scsi_cmd_set(udev, &sc, 5, 0);
21899ca880aSopenharmony_ci        err = scsi_cmd_run(udev, &sc, fd, NULL, 0);
21999ca880aSopenharmony_ci        if ((err != 0)) {
22099ca880aSopenharmony_ci                info_scsi_cmd_err(udev, "START_STOP_UNIT", err);
22199ca880aSopenharmony_ci                return -1;
22299ca880aSopenharmony_ci        }
22399ca880aSopenharmony_ci        return 0;
22499ca880aSopenharmony_ci}
22599ca880aSopenharmony_ci
22699ca880aSopenharmony_cistatic int cd_capability_compat(struct udev *udev, int fd)
22799ca880aSopenharmony_ci{
22899ca880aSopenharmony_ci        int capability;
22999ca880aSopenharmony_ci
23099ca880aSopenharmony_ci        capability = ioctl(fd, CDROM_GET_CAPABILITY, NULL);
23199ca880aSopenharmony_ci        if (capability < 0) {
23299ca880aSopenharmony_ci                log_debug("CDROM_GET_CAPABILITY failed");
23399ca880aSopenharmony_ci                return -1;
23499ca880aSopenharmony_ci        }
23599ca880aSopenharmony_ci
23699ca880aSopenharmony_ci        if (capability & CDC_CD_R)
23799ca880aSopenharmony_ci                cd_cd_r = 1;
23899ca880aSopenharmony_ci        if (capability & CDC_CD_RW)
23999ca880aSopenharmony_ci                cd_cd_rw = 1;
24099ca880aSopenharmony_ci        if (capability & CDC_DVD)
24199ca880aSopenharmony_ci                cd_dvd_rom = 1;
24299ca880aSopenharmony_ci        if (capability & CDC_DVD_R)
24399ca880aSopenharmony_ci                cd_dvd_r = 1;
24499ca880aSopenharmony_ci        if (capability & CDC_DVD_RAM)
24599ca880aSopenharmony_ci                cd_dvd_ram = 1;
24699ca880aSopenharmony_ci        if (capability & CDC_MRW)
24799ca880aSopenharmony_ci                cd_mrw = 1;
24899ca880aSopenharmony_ci        if (capability & CDC_MRW_W)
24999ca880aSopenharmony_ci                cd_mrw_w = 1;
25099ca880aSopenharmony_ci        return 0;
25199ca880aSopenharmony_ci}
25299ca880aSopenharmony_ci
25399ca880aSopenharmony_cistatic int cd_media_compat(struct udev *udev, int fd)
25499ca880aSopenharmony_ci{
25599ca880aSopenharmony_ci        if (ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT) != CDS_DISC_OK) {
25699ca880aSopenharmony_ci                log_debug("CDROM_DRIVE_STATUS != CDS_DISC_OK");
25799ca880aSopenharmony_ci                return -1;
25899ca880aSopenharmony_ci        }
25999ca880aSopenharmony_ci        cd_media = 1;
26099ca880aSopenharmony_ci        return 0;
26199ca880aSopenharmony_ci}
26299ca880aSopenharmony_ci
26399ca880aSopenharmony_cistatic int cd_inquiry(struct udev *udev, int fd)
26499ca880aSopenharmony_ci{
26599ca880aSopenharmony_ci        struct scsi_cmd sc;
26699ca880aSopenharmony_ci        unsigned char inq[128];
26799ca880aSopenharmony_ci        int err;
26899ca880aSopenharmony_ci
26999ca880aSopenharmony_ci        scsi_cmd_init(udev, &sc);
27099ca880aSopenharmony_ci        scsi_cmd_set(udev, &sc, 0, 0x12);
27199ca880aSopenharmony_ci        scsi_cmd_set(udev, &sc, 4, 36);
27299ca880aSopenharmony_ci        scsi_cmd_set(udev, &sc, 5, 0);
27399ca880aSopenharmony_ci        err = scsi_cmd_run(udev, &sc, fd, inq, 36);
27499ca880aSopenharmony_ci        if ((err != 0)) {
27599ca880aSopenharmony_ci                info_scsi_cmd_err(udev, "INQUIRY", err);
27699ca880aSopenharmony_ci                return -1;
27799ca880aSopenharmony_ci        }
27899ca880aSopenharmony_ci
27999ca880aSopenharmony_ci        if ((inq[0] & 0x1F) != 5) {
28099ca880aSopenharmony_ci                log_debug("not an MMC unit");
28199ca880aSopenharmony_ci                return -1;
28299ca880aSopenharmony_ci        }
28399ca880aSopenharmony_ci
28499ca880aSopenharmony_ci        log_debug("INQUIRY: [%.8s][%.16s][%.4s]", inq + 8, inq + 16, inq + 32);
28599ca880aSopenharmony_ci        return 0;
28699ca880aSopenharmony_ci}
28799ca880aSopenharmony_ci
28899ca880aSopenharmony_cistatic void feature_profile_media(struct udev *udev, int cur_profile)
28999ca880aSopenharmony_ci{
29099ca880aSopenharmony_ci        switch (cur_profile) {
29199ca880aSopenharmony_ci        case 0x03:
29299ca880aSopenharmony_ci        case 0x04:
29399ca880aSopenharmony_ci        case 0x05:
29499ca880aSopenharmony_ci                log_debug("profile 0x%02x ", cur_profile);
29599ca880aSopenharmony_ci                cd_media = 1;
29699ca880aSopenharmony_ci                cd_media_mo = 1;
29799ca880aSopenharmony_ci                break;
29899ca880aSopenharmony_ci        case 0x08:
29999ca880aSopenharmony_ci                log_debug("profile 0x%02x media_cd_rom", cur_profile);
30099ca880aSopenharmony_ci                cd_media = 1;
30199ca880aSopenharmony_ci                cd_media_cd_rom = 1;
30299ca880aSopenharmony_ci                break;
30399ca880aSopenharmony_ci        case 0x09:
30499ca880aSopenharmony_ci                log_debug("profile 0x%02x media_cd_r", cur_profile);
30599ca880aSopenharmony_ci                cd_media = 1;
30699ca880aSopenharmony_ci                cd_media_cd_r = 1;
30799ca880aSopenharmony_ci                break;
30899ca880aSopenharmony_ci        case 0x0a:
30999ca880aSopenharmony_ci                log_debug("profile 0x%02x media_cd_rw", cur_profile);
31099ca880aSopenharmony_ci                cd_media = 1;
31199ca880aSopenharmony_ci                cd_media_cd_rw = 1;
31299ca880aSopenharmony_ci                break;
31399ca880aSopenharmony_ci        case 0x10:
31499ca880aSopenharmony_ci                log_debug("profile 0x%02x media_dvd_ro", cur_profile);
31599ca880aSopenharmony_ci                cd_media = 1;
31699ca880aSopenharmony_ci                cd_media_dvd_rom = 1;
31799ca880aSopenharmony_ci                break;
31899ca880aSopenharmony_ci        case 0x11:
31999ca880aSopenharmony_ci                log_debug("profile 0x%02x media_dvd_r", cur_profile);
32099ca880aSopenharmony_ci                cd_media = 1;
32199ca880aSopenharmony_ci                cd_media_dvd_r = 1;
32299ca880aSopenharmony_ci                break;
32399ca880aSopenharmony_ci        case 0x12:
32499ca880aSopenharmony_ci                log_debug("profile 0x%02x media_dvd_ram", cur_profile);
32599ca880aSopenharmony_ci                cd_media = 1;
32699ca880aSopenharmony_ci                cd_media_dvd_ram = 1;
32799ca880aSopenharmony_ci                break;
32899ca880aSopenharmony_ci        case 0x13:
32999ca880aSopenharmony_ci                log_debug("profile 0x%02x media_dvd_rw_ro", cur_profile);
33099ca880aSopenharmony_ci                cd_media = 1;
33199ca880aSopenharmony_ci                cd_media_dvd_rw = 1;
33299ca880aSopenharmony_ci                cd_media_dvd_rw_ro = 1;
33399ca880aSopenharmony_ci                break;
33499ca880aSopenharmony_ci        case 0x14:
33599ca880aSopenharmony_ci                log_debug("profile 0x%02x media_dvd_rw_seq", cur_profile);
33699ca880aSopenharmony_ci                cd_media = 1;
33799ca880aSopenharmony_ci                cd_media_dvd_rw = 1;
33899ca880aSopenharmony_ci                cd_media_dvd_rw_seq = 1;
33999ca880aSopenharmony_ci                break;
34099ca880aSopenharmony_ci        case 0x1B:
34199ca880aSopenharmony_ci                log_debug("profile 0x%02x media_dvd_plus_r", cur_profile);
34299ca880aSopenharmony_ci                cd_media = 1;
34399ca880aSopenharmony_ci                cd_media_dvd_plus_r = 1;
34499ca880aSopenharmony_ci                break;
34599ca880aSopenharmony_ci        case 0x1A:
34699ca880aSopenharmony_ci                log_debug("profile 0x%02x media_dvd_plus_rw", cur_profile);
34799ca880aSopenharmony_ci                cd_media = 1;
34899ca880aSopenharmony_ci                cd_media_dvd_plus_rw = 1;
34999ca880aSopenharmony_ci                break;
35099ca880aSopenharmony_ci        case 0x2A:
35199ca880aSopenharmony_ci                log_debug("profile 0x%02x media_dvd_plus_rw_dl", cur_profile);
35299ca880aSopenharmony_ci                cd_media = 1;
35399ca880aSopenharmony_ci                cd_media_dvd_plus_rw_dl = 1;
35499ca880aSopenharmony_ci                break;
35599ca880aSopenharmony_ci        case 0x2B:
35699ca880aSopenharmony_ci                log_debug("profile 0x%02x media_dvd_plus_r_dl", cur_profile);
35799ca880aSopenharmony_ci                cd_media = 1;
35899ca880aSopenharmony_ci                cd_media_dvd_plus_r_dl = 1;
35999ca880aSopenharmony_ci                break;
36099ca880aSopenharmony_ci        case 0x40:
36199ca880aSopenharmony_ci                log_debug("profile 0x%02x media_bd", cur_profile);
36299ca880aSopenharmony_ci                cd_media = 1;
36399ca880aSopenharmony_ci                cd_media_bd = 1;
36499ca880aSopenharmony_ci                break;
36599ca880aSopenharmony_ci        case 0x41:
36699ca880aSopenharmony_ci        case 0x42:
36799ca880aSopenharmony_ci                log_debug("profile 0x%02x media_bd_r", cur_profile);
36899ca880aSopenharmony_ci                cd_media = 1;
36999ca880aSopenharmony_ci                cd_media_bd_r = 1;
37099ca880aSopenharmony_ci                break;
37199ca880aSopenharmony_ci        case 0x43:
37299ca880aSopenharmony_ci                log_debug("profile 0x%02x media_bd_re", cur_profile);
37399ca880aSopenharmony_ci                cd_media = 1;
37499ca880aSopenharmony_ci                cd_media_bd_re = 1;
37599ca880aSopenharmony_ci                break;
37699ca880aSopenharmony_ci        case 0x50:
37799ca880aSopenharmony_ci                log_debug("profile 0x%02x media_hddvd", cur_profile);
37899ca880aSopenharmony_ci                cd_media = 1;
37999ca880aSopenharmony_ci                cd_media_hddvd = 1;
38099ca880aSopenharmony_ci                break;
38199ca880aSopenharmony_ci        case 0x51:
38299ca880aSopenharmony_ci                log_debug("profile 0x%02x media_hddvd_r", cur_profile);
38399ca880aSopenharmony_ci                cd_media = 1;
38499ca880aSopenharmony_ci                cd_media_hddvd_r = 1;
38599ca880aSopenharmony_ci                break;
38699ca880aSopenharmony_ci        case 0x52:
38799ca880aSopenharmony_ci                log_debug("profile 0x%02x media_hddvd_rw", cur_profile);
38899ca880aSopenharmony_ci                cd_media = 1;
38999ca880aSopenharmony_ci                cd_media_hddvd_rw = 1;
39099ca880aSopenharmony_ci                break;
39199ca880aSopenharmony_ci        default:
39299ca880aSopenharmony_ci                log_debug("profile 0x%02x <ignored>", cur_profile);
39399ca880aSopenharmony_ci                break;
39499ca880aSopenharmony_ci        }
39599ca880aSopenharmony_ci}
39699ca880aSopenharmony_ci
39799ca880aSopenharmony_cistatic int feature_profiles(struct udev *udev, const unsigned char *profiles, size_t size)
39899ca880aSopenharmony_ci{
39999ca880aSopenharmony_ci        unsigned int i;
40099ca880aSopenharmony_ci
40199ca880aSopenharmony_ci        for (i = 0; i+4 <= size; i += 4) {
40299ca880aSopenharmony_ci                int profile;
40399ca880aSopenharmony_ci
40499ca880aSopenharmony_ci                profile = profiles[i] << 8 | profiles[i+1];
40599ca880aSopenharmony_ci                switch (profile) {
40699ca880aSopenharmony_ci                case 0x03:
40799ca880aSopenharmony_ci                case 0x04:
40899ca880aSopenharmony_ci                case 0x05:
40999ca880aSopenharmony_ci                        log_debug("profile 0x%02x mo", profile);
41099ca880aSopenharmony_ci                        cd_mo = 1;
41199ca880aSopenharmony_ci                        break;
41299ca880aSopenharmony_ci                case 0x08:
41399ca880aSopenharmony_ci                        log_debug("profile 0x%02x cd_rom", profile);
41499ca880aSopenharmony_ci                        cd_cd_rom = 1;
41599ca880aSopenharmony_ci                        break;
41699ca880aSopenharmony_ci                case 0x09:
41799ca880aSopenharmony_ci                        log_debug("profile 0x%02x cd_r", profile);
41899ca880aSopenharmony_ci                        cd_cd_r = 1;
41999ca880aSopenharmony_ci                        break;
42099ca880aSopenharmony_ci                case 0x0A:
42199ca880aSopenharmony_ci                        log_debug("profile 0x%02x cd_rw", profile);
42299ca880aSopenharmony_ci                        cd_cd_rw = 1;
42399ca880aSopenharmony_ci                        break;
42499ca880aSopenharmony_ci                case 0x10:
42599ca880aSopenharmony_ci                        log_debug("profile 0x%02x dvd_rom", profile);
42699ca880aSopenharmony_ci                        cd_dvd_rom = 1;
42799ca880aSopenharmony_ci                        break;
42899ca880aSopenharmony_ci                case 0x12:
42999ca880aSopenharmony_ci                        log_debug("profile 0x%02x dvd_ram", profile);
43099ca880aSopenharmony_ci                        cd_dvd_ram = 1;
43199ca880aSopenharmony_ci                        break;
43299ca880aSopenharmony_ci                case 0x13:
43399ca880aSopenharmony_ci                case 0x14:
43499ca880aSopenharmony_ci                        log_debug("profile 0x%02x dvd_rw", profile);
43599ca880aSopenharmony_ci                        cd_dvd_rw = 1;
43699ca880aSopenharmony_ci                        break;
43799ca880aSopenharmony_ci                case 0x1B:
43899ca880aSopenharmony_ci                        log_debug("profile 0x%02x dvd_plus_r", profile);
43999ca880aSopenharmony_ci                        cd_dvd_plus_r = 1;
44099ca880aSopenharmony_ci                        break;
44199ca880aSopenharmony_ci                case 0x1A:
44299ca880aSopenharmony_ci                        log_debug("profile 0x%02x dvd_plus_rw", profile);
44399ca880aSopenharmony_ci                        cd_dvd_plus_rw = 1;
44499ca880aSopenharmony_ci                        break;
44599ca880aSopenharmony_ci                case 0x2A:
44699ca880aSopenharmony_ci                        log_debug("profile 0x%02x dvd_plus_rw_dl", profile);
44799ca880aSopenharmony_ci                        cd_dvd_plus_rw_dl = 1;
44899ca880aSopenharmony_ci                        break;
44999ca880aSopenharmony_ci                case 0x2B:
45099ca880aSopenharmony_ci                        log_debug("profile 0x%02x dvd_plus_r_dl", profile);
45199ca880aSopenharmony_ci                        cd_dvd_plus_r_dl = 1;
45299ca880aSopenharmony_ci                        break;
45399ca880aSopenharmony_ci                case 0x40:
45499ca880aSopenharmony_ci                        cd_bd = 1;
45599ca880aSopenharmony_ci                        log_debug("profile 0x%02x bd", profile);
45699ca880aSopenharmony_ci                        break;
45799ca880aSopenharmony_ci                case 0x41:
45899ca880aSopenharmony_ci                case 0x42:
45999ca880aSopenharmony_ci                        cd_bd_r = 1;
46099ca880aSopenharmony_ci                        log_debug("profile 0x%02x bd_r", profile);
46199ca880aSopenharmony_ci                        break;
46299ca880aSopenharmony_ci                case 0x43:
46399ca880aSopenharmony_ci                        cd_bd_re = 1;
46499ca880aSopenharmony_ci                        log_debug("profile 0x%02x bd_re", profile);
46599ca880aSopenharmony_ci                        break;
46699ca880aSopenharmony_ci                case 0x50:
46799ca880aSopenharmony_ci                        cd_hddvd = 1;
46899ca880aSopenharmony_ci                        log_debug("profile 0x%02x hddvd", profile);
46999ca880aSopenharmony_ci                        break;
47099ca880aSopenharmony_ci                case 0x51:
47199ca880aSopenharmony_ci                        cd_hddvd_r = 1;
47299ca880aSopenharmony_ci                        log_debug("profile 0x%02x hddvd_r", profile);
47399ca880aSopenharmony_ci                        break;
47499ca880aSopenharmony_ci                case 0x52:
47599ca880aSopenharmony_ci                        cd_hddvd_rw = 1;
47699ca880aSopenharmony_ci                        log_debug("profile 0x%02x hddvd_rw", profile);
47799ca880aSopenharmony_ci                        break;
47899ca880aSopenharmony_ci                default:
47999ca880aSopenharmony_ci                        log_debug("profile 0x%02x <ignored>", profile);
48099ca880aSopenharmony_ci                        break;
48199ca880aSopenharmony_ci                }
48299ca880aSopenharmony_ci        }
48399ca880aSopenharmony_ci        return 0;
48499ca880aSopenharmony_ci}
48599ca880aSopenharmony_ci
48699ca880aSopenharmony_ci/* returns 0 if media was detected */
48799ca880aSopenharmony_cistatic int cd_profiles_old_mmc(struct udev *udev, int fd)
48899ca880aSopenharmony_ci{
48999ca880aSopenharmony_ci        struct scsi_cmd sc;
49099ca880aSopenharmony_ci        int err;
49199ca880aSopenharmony_ci
49299ca880aSopenharmony_ci        unsigned char header[32];
49399ca880aSopenharmony_ci
49499ca880aSopenharmony_ci        scsi_cmd_init(udev, &sc);
49599ca880aSopenharmony_ci        scsi_cmd_set(udev, &sc, 0, 0x51);
49699ca880aSopenharmony_ci        scsi_cmd_set(udev, &sc, 8, sizeof(header));
49799ca880aSopenharmony_ci        scsi_cmd_set(udev, &sc, 9, 0);
49899ca880aSopenharmony_ci        err = scsi_cmd_run(udev, &sc, fd, header, sizeof(header));
49999ca880aSopenharmony_ci        if ((err != 0)) {
50099ca880aSopenharmony_ci                info_scsi_cmd_err(udev, "READ DISC INFORMATION", err);
50199ca880aSopenharmony_ci                if (cd_media == 1) {
50299ca880aSopenharmony_ci                        log_debug("no current profile, but disc is present; assuming CD-ROM");
50399ca880aSopenharmony_ci                        cd_media_cd_rom = 1;
50499ca880aSopenharmony_ci                        cd_media_track_count = 1;
50599ca880aSopenharmony_ci                        cd_media_track_count_data = 1;
50699ca880aSopenharmony_ci                        return 0;
50799ca880aSopenharmony_ci                } else {
50899ca880aSopenharmony_ci                        log_debug("no current profile, assuming no media");
50999ca880aSopenharmony_ci                        return -1;
51099ca880aSopenharmony_ci                }
51199ca880aSopenharmony_ci        };
51299ca880aSopenharmony_ci
51399ca880aSopenharmony_ci        cd_media = 1;
51499ca880aSopenharmony_ci
51599ca880aSopenharmony_ci        if (header[2] & 16) {
51699ca880aSopenharmony_ci                cd_media_cd_rw = 1;
51799ca880aSopenharmony_ci                log_debug("profile 0x0a media_cd_rw");
51899ca880aSopenharmony_ci        } else if ((header[2] & 3) < 2 && cd_cd_r) {
51999ca880aSopenharmony_ci                cd_media_cd_r = 1;
52099ca880aSopenharmony_ci                log_debug("profile 0x09 media_cd_r");
52199ca880aSopenharmony_ci        } else {
52299ca880aSopenharmony_ci                cd_media_cd_rom = 1;
52399ca880aSopenharmony_ci                log_debug("profile 0x08 media_cd_rom");
52499ca880aSopenharmony_ci        }
52599ca880aSopenharmony_ci        return 0;
52699ca880aSopenharmony_ci}
52799ca880aSopenharmony_ci
52899ca880aSopenharmony_ci/* returns 0 if media was detected */
52999ca880aSopenharmony_cistatic int cd_profiles(struct udev *udev, int fd)
53099ca880aSopenharmony_ci{
53199ca880aSopenharmony_ci        struct scsi_cmd sc;
53299ca880aSopenharmony_ci        unsigned char features[65530];
53399ca880aSopenharmony_ci        unsigned int cur_profile = 0;
53499ca880aSopenharmony_ci        unsigned int len;
53599ca880aSopenharmony_ci        unsigned int i;
53699ca880aSopenharmony_ci        int err;
53799ca880aSopenharmony_ci        int ret;
53899ca880aSopenharmony_ci
53999ca880aSopenharmony_ci        ret = -1;
54099ca880aSopenharmony_ci
54199ca880aSopenharmony_ci        /* First query the current profile */
54299ca880aSopenharmony_ci        scsi_cmd_init(udev, &sc);
54399ca880aSopenharmony_ci        scsi_cmd_set(udev, &sc, 0, 0x46);
54499ca880aSopenharmony_ci        scsi_cmd_set(udev, &sc, 8, 8);
54599ca880aSopenharmony_ci        scsi_cmd_set(udev, &sc, 9, 0);
54699ca880aSopenharmony_ci        err = scsi_cmd_run(udev, &sc, fd, features, 8);
54799ca880aSopenharmony_ci        if ((err != 0)) {
54899ca880aSopenharmony_ci                info_scsi_cmd_err(udev, "GET CONFIGURATION", err);
54999ca880aSopenharmony_ci                /* handle pre-MMC2 drives which do not support GET CONFIGURATION */
55099ca880aSopenharmony_ci                if (SK(err) == 0x5 && (ASC(err) == 0x20 || ASC(err) == 0x24)) {
55199ca880aSopenharmony_ci                        log_debug("drive is pre-MMC2 and does not support 46h get configuration command");
55299ca880aSopenharmony_ci                        log_debug("trying to work around the problem");
55399ca880aSopenharmony_ci                        ret = cd_profiles_old_mmc(udev, fd);
55499ca880aSopenharmony_ci                }
55599ca880aSopenharmony_ci                goto out;
55699ca880aSopenharmony_ci        }
55799ca880aSopenharmony_ci
55899ca880aSopenharmony_ci        cur_profile = features[6] << 8 | features[7];
55999ca880aSopenharmony_ci        if (cur_profile > 0) {
56099ca880aSopenharmony_ci                log_debug("current profile 0x%02x", cur_profile);
56199ca880aSopenharmony_ci                feature_profile_media (udev, cur_profile);
56299ca880aSopenharmony_ci                ret = 0; /* we have media */
56399ca880aSopenharmony_ci        } else {
56499ca880aSopenharmony_ci                log_debug("no current profile, assuming no media");
56599ca880aSopenharmony_ci        }
56699ca880aSopenharmony_ci
56799ca880aSopenharmony_ci        len = features[0] << 24 | features[1] << 16 | features[2] << 8 | features[3];
56899ca880aSopenharmony_ci        log_debug("GET CONFIGURATION: size of features buffer 0x%04x", len);
56999ca880aSopenharmony_ci
57099ca880aSopenharmony_ci        if (len > sizeof(features)) {
57199ca880aSopenharmony_ci                log_debug("can not get features in a single query, truncating");
57299ca880aSopenharmony_ci                len = sizeof(features);
57399ca880aSopenharmony_ci        } else if (len <= 8) {
57499ca880aSopenharmony_ci                len = sizeof(features);
57599ca880aSopenharmony_ci        }
57699ca880aSopenharmony_ci
57799ca880aSopenharmony_ci        /* Now get the full feature buffer */
57899ca880aSopenharmony_ci        scsi_cmd_init(udev, &sc);
57999ca880aSopenharmony_ci        scsi_cmd_set(udev, &sc, 0, 0x46);
58099ca880aSopenharmony_ci        scsi_cmd_set(udev, &sc, 7, ( len >> 8 ) & 0xff);
58199ca880aSopenharmony_ci        scsi_cmd_set(udev, &sc, 8, len & 0xff);
58299ca880aSopenharmony_ci        scsi_cmd_set(udev, &sc, 9, 0);
58399ca880aSopenharmony_ci        err = scsi_cmd_run(udev, &sc, fd, features, len);
58499ca880aSopenharmony_ci        if ((err != 0)) {
58599ca880aSopenharmony_ci                info_scsi_cmd_err(udev, "GET CONFIGURATION", err);
58699ca880aSopenharmony_ci                return -1;
58799ca880aSopenharmony_ci        }
58899ca880aSopenharmony_ci
58999ca880aSopenharmony_ci        /* parse the length once more, in case the drive decided to have other features suddenly :) */
59099ca880aSopenharmony_ci        len = features[0] << 24 | features[1] << 16 | features[2] << 8 | features[3];
59199ca880aSopenharmony_ci        log_debug("GET CONFIGURATION: size of features buffer 0x%04x", len);
59299ca880aSopenharmony_ci
59399ca880aSopenharmony_ci        if (len > sizeof(features)) {
59499ca880aSopenharmony_ci                log_debug("can not get features in a single query, truncating");
59599ca880aSopenharmony_ci                len = sizeof(features);
59699ca880aSopenharmony_ci        }
59799ca880aSopenharmony_ci
59899ca880aSopenharmony_ci        /* device features */
59999ca880aSopenharmony_ci        for (i = 8; i+4 < len; i += (4 + features[i+3])) {
60099ca880aSopenharmony_ci                unsigned int feature;
60199ca880aSopenharmony_ci
60299ca880aSopenharmony_ci                feature = features[i] << 8 | features[i+1];
60399ca880aSopenharmony_ci
60499ca880aSopenharmony_ci                switch (feature) {
60599ca880aSopenharmony_ci                case 0x00:
60699ca880aSopenharmony_ci                        log_debug("GET CONFIGURATION: feature 'profiles', with %i entries", features[i+3] / 4);
60799ca880aSopenharmony_ci                        feature_profiles(udev, &features[i]+4, MIN(features[i+3], len - i - 4));
60899ca880aSopenharmony_ci                        break;
60999ca880aSopenharmony_ci                default:
61099ca880aSopenharmony_ci                        log_debug("GET CONFIGURATION: feature 0x%04x <ignored>, with 0x%02x bytes", feature, features[i+3]);
61199ca880aSopenharmony_ci                        break;
61299ca880aSopenharmony_ci                }
61399ca880aSopenharmony_ci        }
61499ca880aSopenharmony_ciout:
61599ca880aSopenharmony_ci        return ret;
61699ca880aSopenharmony_ci}
61799ca880aSopenharmony_ci
61899ca880aSopenharmony_cistatic int cd_media_info(struct udev *udev, int fd)
61999ca880aSopenharmony_ci{
62099ca880aSopenharmony_ci        struct scsi_cmd sc;
62199ca880aSopenharmony_ci        unsigned char header[32];
62299ca880aSopenharmony_ci        static const char *media_status[] = {
62399ca880aSopenharmony_ci                "blank",
62499ca880aSopenharmony_ci                "appendable",
62599ca880aSopenharmony_ci                "complete",
62699ca880aSopenharmony_ci                "other"
62799ca880aSopenharmony_ci        };
62899ca880aSopenharmony_ci        int err;
62999ca880aSopenharmony_ci
63099ca880aSopenharmony_ci        scsi_cmd_init(udev, &sc);
63199ca880aSopenharmony_ci        scsi_cmd_set(udev, &sc, 0, 0x51);
63299ca880aSopenharmony_ci        scsi_cmd_set(udev, &sc, 8, sizeof(header) & 0xff);
63399ca880aSopenharmony_ci        scsi_cmd_set(udev, &sc, 9, 0);
63499ca880aSopenharmony_ci        err = scsi_cmd_run(udev, &sc, fd, header, sizeof(header));
63599ca880aSopenharmony_ci        if ((err != 0)) {
63699ca880aSopenharmony_ci                info_scsi_cmd_err(udev, "READ DISC INFORMATION", err);
63799ca880aSopenharmony_ci                return -1;
63899ca880aSopenharmony_ci        };
63999ca880aSopenharmony_ci
64099ca880aSopenharmony_ci        cd_media = 1;
64199ca880aSopenharmony_ci        log_debug("disk type %02x", header[8]);
64299ca880aSopenharmony_ci        log_debug("hardware reported media status: %s", media_status[header[2] & 3]);
64399ca880aSopenharmony_ci
64499ca880aSopenharmony_ci        /* exclude plain CDROM, some fake cdroms return 0 for "blank" media here */
64599ca880aSopenharmony_ci        if (!cd_media_cd_rom)
64699ca880aSopenharmony_ci                cd_media_state = media_status[header[2] & 3];
64799ca880aSopenharmony_ci
64899ca880aSopenharmony_ci        /* fresh DVD-RW in restricted overwite mode reports itself as
64999ca880aSopenharmony_ci         * "appendable"; change it to "blank" to make it consistent with what
65099ca880aSopenharmony_ci         * gets reported after blanking, and what userspace expects  */
65199ca880aSopenharmony_ci        if (cd_media_dvd_rw_ro && (header[2] & 3) == 1)
65299ca880aSopenharmony_ci                cd_media_state = media_status[0];
65399ca880aSopenharmony_ci
65499ca880aSopenharmony_ci        /* DVD+RW discs (and DVD-RW in restricted mode) once formatted are
65599ca880aSopenharmony_ci         * always "complete", DVD-RAM are "other" or "complete" if the disc is
65699ca880aSopenharmony_ci         * write protected; we need to check the contents if it is blank */
65799ca880aSopenharmony_ci        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) {
65899ca880aSopenharmony_ci                unsigned char buffer[32 * 2048];
65999ca880aSopenharmony_ci                unsigned char len;
66099ca880aSopenharmony_ci                int offset;
66199ca880aSopenharmony_ci
66299ca880aSopenharmony_ci                if (cd_media_dvd_ram) {
66399ca880aSopenharmony_ci                        /* a write protected dvd-ram may report "complete" status */
66499ca880aSopenharmony_ci
66599ca880aSopenharmony_ci                        unsigned char dvdstruct[8];
66699ca880aSopenharmony_ci                        unsigned char format[12];
66799ca880aSopenharmony_ci
66899ca880aSopenharmony_ci                        scsi_cmd_init(udev, &sc);
66999ca880aSopenharmony_ci                        scsi_cmd_set(udev, &sc, 0, 0xAD);
67099ca880aSopenharmony_ci                        scsi_cmd_set(udev, &sc, 7, 0xC0);
67199ca880aSopenharmony_ci                        scsi_cmd_set(udev, &sc, 9, sizeof(dvdstruct));
67299ca880aSopenharmony_ci                        scsi_cmd_set(udev, &sc, 11, 0);
67399ca880aSopenharmony_ci                        err = scsi_cmd_run(udev, &sc, fd, dvdstruct, sizeof(dvdstruct));
67499ca880aSopenharmony_ci                        if ((err != 0)) {
67599ca880aSopenharmony_ci                                info_scsi_cmd_err(udev, "READ DVD STRUCTURE", err);
67699ca880aSopenharmony_ci                                return -1;
67799ca880aSopenharmony_ci                        }
67899ca880aSopenharmony_ci                        if (dvdstruct[4] & 0x02) {
67999ca880aSopenharmony_ci                                cd_media_state = media_status[2];
68099ca880aSopenharmony_ci                                log_debug("write-protected DVD-RAM media inserted");
68199ca880aSopenharmony_ci                                goto determined;
68299ca880aSopenharmony_ci                        }
68399ca880aSopenharmony_ci
68499ca880aSopenharmony_ci                        /* let's make sure we don't try to read unformatted media */
68599ca880aSopenharmony_ci                        scsi_cmd_init(udev, &sc);
68699ca880aSopenharmony_ci                        scsi_cmd_set(udev, &sc, 0, 0x23);
68799ca880aSopenharmony_ci                        scsi_cmd_set(udev, &sc, 8, sizeof(format));
68899ca880aSopenharmony_ci                        scsi_cmd_set(udev, &sc, 9, 0);
68999ca880aSopenharmony_ci                        err = scsi_cmd_run(udev, &sc, fd, format, sizeof(format));
69099ca880aSopenharmony_ci                        if ((err != 0)) {
69199ca880aSopenharmony_ci                                info_scsi_cmd_err(udev, "READ DVD FORMAT CAPACITIES", err);
69299ca880aSopenharmony_ci                                return -1;
69399ca880aSopenharmony_ci                        }
69499ca880aSopenharmony_ci
69599ca880aSopenharmony_ci                        len = format[3];
69699ca880aSopenharmony_ci                        if (len & 7 || len < 16) {
69799ca880aSopenharmony_ci                                log_debug("invalid format capacities length");
69899ca880aSopenharmony_ci                                return -1;
69999ca880aSopenharmony_ci                        }
70099ca880aSopenharmony_ci
70199ca880aSopenharmony_ci                        switch(format[8] & 3) {
70299ca880aSopenharmony_ci                            case 1:
70399ca880aSopenharmony_ci                                log_debug("unformatted DVD-RAM media inserted");
70499ca880aSopenharmony_ci                                /* This means that last format was interrupted
70599ca880aSopenharmony_ci                                 * or failed, blank dvd-ram discs are factory
70699ca880aSopenharmony_ci                                 * formatted. Take no action here as it takes
70799ca880aSopenharmony_ci                                 * quite a while to reformat a dvd-ram and it's
70899ca880aSopenharmony_ci                                 * not automatically started */
70999ca880aSopenharmony_ci                                goto determined;
71099ca880aSopenharmony_ci
71199ca880aSopenharmony_ci                            case 2:
71299ca880aSopenharmony_ci                                log_debug("formatted DVD-RAM media inserted");
71399ca880aSopenharmony_ci                                break;
71499ca880aSopenharmony_ci
71599ca880aSopenharmony_ci                            case 3:
71699ca880aSopenharmony_ci                                cd_media = 0; //return no media
71799ca880aSopenharmony_ci                                log_debug("format capacities returned no media");
71899ca880aSopenharmony_ci                                return -1;
71999ca880aSopenharmony_ci                        }
72099ca880aSopenharmony_ci                }
72199ca880aSopenharmony_ci
72299ca880aSopenharmony_ci                /* Take a closer look at formatted media (unformatted DVD+RW
72399ca880aSopenharmony_ci                 * has "blank" status", DVD-RAM was examined earlier) and check
72499ca880aSopenharmony_ci                 * for ISO and UDF PVDs or a fs superblock presence and do it
72599ca880aSopenharmony_ci                 * in one ioctl (we need just sectors 0 and 16) */
72699ca880aSopenharmony_ci                scsi_cmd_init(udev, &sc);
72799ca880aSopenharmony_ci                scsi_cmd_set(udev, &sc, 0, 0x28);
72899ca880aSopenharmony_ci                scsi_cmd_set(udev, &sc, 5, 0);
72999ca880aSopenharmony_ci                scsi_cmd_set(udev, &sc, 8, 32);
73099ca880aSopenharmony_ci                scsi_cmd_set(udev, &sc, 9, 0);
73199ca880aSopenharmony_ci                err = scsi_cmd_run(udev, &sc, fd, buffer, sizeof(buffer));
73299ca880aSopenharmony_ci                if ((err != 0)) {
73399ca880aSopenharmony_ci                        cd_media = 0;
73499ca880aSopenharmony_ci                        info_scsi_cmd_err(udev, "READ FIRST 32 BLOCKS", err);
73599ca880aSopenharmony_ci                        return -1;
73699ca880aSopenharmony_ci                }
73799ca880aSopenharmony_ci
73899ca880aSopenharmony_ci                /* if any non-zero data is found in sector 16 (iso and udf) or
73999ca880aSopenharmony_ci                 * eventually 0 (fat32 boot sector, ext2 superblock, etc), disc
74099ca880aSopenharmony_ci                 * is assumed non-blank */
74199ca880aSopenharmony_ci
74299ca880aSopenharmony_ci                for (offset = 32768; offset < (32768 + 2048); offset++) {
74399ca880aSopenharmony_ci                        if (buffer [offset]) {
74499ca880aSopenharmony_ci                                log_debug("data in block 16, assuming complete");
74599ca880aSopenharmony_ci                                goto determined;
74699ca880aSopenharmony_ci                        }
74799ca880aSopenharmony_ci                }
74899ca880aSopenharmony_ci
74999ca880aSopenharmony_ci                for (offset = 0; offset < 2048; offset++) {
75099ca880aSopenharmony_ci                        if (buffer [offset]) {
75199ca880aSopenharmony_ci                                log_debug("data in block 0, assuming complete");
75299ca880aSopenharmony_ci                                goto determined;
75399ca880aSopenharmony_ci                        }
75499ca880aSopenharmony_ci                }
75599ca880aSopenharmony_ci
75699ca880aSopenharmony_ci                cd_media_state = media_status[0];
75799ca880aSopenharmony_ci                log_debug("no data in blocks 0 or 16, assuming blank");
75899ca880aSopenharmony_ci        }
75999ca880aSopenharmony_ci
76099ca880aSopenharmony_cidetermined:
76199ca880aSopenharmony_ci        /* "other" is e. g. DVD-RAM, can't append sessions there; DVDs in
76299ca880aSopenharmony_ci         * restricted overwrite mode can never append, only in sequential mode */
76399ca880aSopenharmony_ci        if ((header[2] & 3) < 2 && !cd_media_dvd_rw_ro)
76499ca880aSopenharmony_ci                cd_media_session_next = header[10] << 8 | header[5];
76599ca880aSopenharmony_ci        cd_media_session_count = header[9] << 8 | header[4];
76699ca880aSopenharmony_ci        cd_media_track_count = header[11] << 8 | header[6];
76799ca880aSopenharmony_ci
76899ca880aSopenharmony_ci        return 0;
76999ca880aSopenharmony_ci}
77099ca880aSopenharmony_ci
77199ca880aSopenharmony_cistatic int cd_media_toc(struct udev *udev, int fd)
77299ca880aSopenharmony_ci{
77399ca880aSopenharmony_ci        struct scsi_cmd sc;
77499ca880aSopenharmony_ci        unsigned char header[12];
77599ca880aSopenharmony_ci        unsigned char toc[65536];
77699ca880aSopenharmony_ci        unsigned int len, i, num_tracks;
77799ca880aSopenharmony_ci        unsigned char *p;
77899ca880aSopenharmony_ci        int err;
77999ca880aSopenharmony_ci
78099ca880aSopenharmony_ci        scsi_cmd_init(udev, &sc);
78199ca880aSopenharmony_ci        scsi_cmd_set(udev, &sc, 0, 0x43);
78299ca880aSopenharmony_ci        scsi_cmd_set(udev, &sc, 6, 1);
78399ca880aSopenharmony_ci        scsi_cmd_set(udev, &sc, 8, sizeof(header) & 0xff);
78499ca880aSopenharmony_ci        scsi_cmd_set(udev, &sc, 9, 0);
78599ca880aSopenharmony_ci        err = scsi_cmd_run(udev, &sc, fd, header, sizeof(header));
78699ca880aSopenharmony_ci        if ((err != 0)) {
78799ca880aSopenharmony_ci                info_scsi_cmd_err(udev, "READ TOC", err);
78899ca880aSopenharmony_ci                return -1;
78999ca880aSopenharmony_ci        }
79099ca880aSopenharmony_ci
79199ca880aSopenharmony_ci        len = (header[0] << 8 | header[1]) + 2;
79299ca880aSopenharmony_ci        log_debug("READ TOC: len: %d, start track: %d, end track: %d", len, header[2], header[3]);
79399ca880aSopenharmony_ci        if (len > sizeof(toc))
79499ca880aSopenharmony_ci                return -1;
79599ca880aSopenharmony_ci        if (len < 2)
79699ca880aSopenharmony_ci                return -1;
79799ca880aSopenharmony_ci        /* 2: first track, 3: last track */
79899ca880aSopenharmony_ci        num_tracks = header[3] - header[2] + 1;
79999ca880aSopenharmony_ci
80099ca880aSopenharmony_ci        /* empty media has no tracks */
80199ca880aSopenharmony_ci        if (len < 8)
80299ca880aSopenharmony_ci                return 0;
80399ca880aSopenharmony_ci
80499ca880aSopenharmony_ci        scsi_cmd_init(udev, &sc);
80599ca880aSopenharmony_ci        scsi_cmd_set(udev, &sc, 0, 0x43);
80699ca880aSopenharmony_ci        scsi_cmd_set(udev, &sc, 6, header[2]); /* First Track/Session Number */
80799ca880aSopenharmony_ci        scsi_cmd_set(udev, &sc, 7, (len >> 8) & 0xff);
80899ca880aSopenharmony_ci        scsi_cmd_set(udev, &sc, 8, len & 0xff);
80999ca880aSopenharmony_ci        scsi_cmd_set(udev, &sc, 9, 0);
81099ca880aSopenharmony_ci        err = scsi_cmd_run(udev, &sc, fd, toc, len);
81199ca880aSopenharmony_ci        if ((err != 0)) {
81299ca880aSopenharmony_ci                info_scsi_cmd_err(udev, "READ TOC (tracks)", err);
81399ca880aSopenharmony_ci                return -1;
81499ca880aSopenharmony_ci        }
81599ca880aSopenharmony_ci
81699ca880aSopenharmony_ci        /* Take care to not iterate beyond the last valid track as specified in
81799ca880aSopenharmony_ci         * the TOC, but also avoid going beyond the TOC length, just in case
81899ca880aSopenharmony_ci         * the last track number is invalidly large */
81999ca880aSopenharmony_ci        for (p = toc+4, i = 4; i < len-8 && num_tracks > 0; i += 8, p += 8, --num_tracks) {
82099ca880aSopenharmony_ci                unsigned int block;
82199ca880aSopenharmony_ci                unsigned int is_data_track;
82299ca880aSopenharmony_ci
82399ca880aSopenharmony_ci                is_data_track = (p[1] & 0x04) != 0;
82499ca880aSopenharmony_ci
82599ca880aSopenharmony_ci                block = p[4] << 24 | p[5] << 16 | p[6] << 8 | p[7];
82699ca880aSopenharmony_ci                log_debug("track=%u info=0x%x(%s) start_block=%u",
82799ca880aSopenharmony_ci                     p[2], p[1] & 0x0f, is_data_track ? "data":"audio", block);
82899ca880aSopenharmony_ci
82999ca880aSopenharmony_ci                if (is_data_track)
83099ca880aSopenharmony_ci                        cd_media_track_count_data++;
83199ca880aSopenharmony_ci                else
83299ca880aSopenharmony_ci                        cd_media_track_count_audio++;
83399ca880aSopenharmony_ci        }
83499ca880aSopenharmony_ci
83599ca880aSopenharmony_ci        scsi_cmd_init(udev, &sc);
83699ca880aSopenharmony_ci        scsi_cmd_set(udev, &sc, 0, 0x43);
83799ca880aSopenharmony_ci        scsi_cmd_set(udev, &sc, 2, 1); /* Session Info */
83899ca880aSopenharmony_ci        scsi_cmd_set(udev, &sc, 8, sizeof(header));
83999ca880aSopenharmony_ci        scsi_cmd_set(udev, &sc, 9, 0);
84099ca880aSopenharmony_ci        err = scsi_cmd_run(udev, &sc, fd, header, sizeof(header));
84199ca880aSopenharmony_ci        if ((err != 0)) {
84299ca880aSopenharmony_ci                info_scsi_cmd_err(udev, "READ TOC (multi session)", err);
84399ca880aSopenharmony_ci                return -1;
84499ca880aSopenharmony_ci        }
84599ca880aSopenharmony_ci        len = header[4+4] << 24 | header[4+5] << 16 | header[4+6] << 8 | header[4+7];
84699ca880aSopenharmony_ci        log_debug("last track %u starts at block %u", header[4+2], len);
84799ca880aSopenharmony_ci        cd_media_session_last_offset = (unsigned long long int)len * 2048;
84899ca880aSopenharmony_ci        return 0;
84999ca880aSopenharmony_ci}
85099ca880aSopenharmony_ci
85199ca880aSopenharmony_ciint main(int argc, char *argv[])
85299ca880aSopenharmony_ci{
85399ca880aSopenharmony_ci        struct udev *udev;
85499ca880aSopenharmony_ci        static const struct option options[] = {
85599ca880aSopenharmony_ci                { "lock-media", no_argument, NULL, 'l' },
85699ca880aSopenharmony_ci                { "unlock-media", no_argument, NULL, 'u' },
85799ca880aSopenharmony_ci                { "eject-media", no_argument, NULL, 'e' },
85899ca880aSopenharmony_ci                { "debug", no_argument, NULL, 'd' },
85999ca880aSopenharmony_ci                { "help", no_argument, NULL, 'h' },
86099ca880aSopenharmony_ci                {}
86199ca880aSopenharmony_ci        };
86299ca880aSopenharmony_ci        bool eject = false;
86399ca880aSopenharmony_ci        bool lock = false;
86499ca880aSopenharmony_ci        bool unlock = false;
86599ca880aSopenharmony_ci        const char *node = NULL;
86699ca880aSopenharmony_ci        int fd = -1;
86799ca880aSopenharmony_ci        int cnt;
86899ca880aSopenharmony_ci        int rc = 0;
86999ca880aSopenharmony_ci
87099ca880aSopenharmony_ci        log_open();
87199ca880aSopenharmony_ci
87299ca880aSopenharmony_ci        udev = udev_new();
87399ca880aSopenharmony_ci        if (udev == NULL)
87499ca880aSopenharmony_ci                goto exit;
87599ca880aSopenharmony_ci
87699ca880aSopenharmony_ci        while (1) {
87799ca880aSopenharmony_ci                int option;
87899ca880aSopenharmony_ci
87999ca880aSopenharmony_ci                option = getopt_long(argc, argv, "deluh", options, NULL);
88099ca880aSopenharmony_ci                if (option == -1)
88199ca880aSopenharmony_ci                        break;
88299ca880aSopenharmony_ci
88399ca880aSopenharmony_ci                switch (option) {
88499ca880aSopenharmony_ci                case 'l':
88599ca880aSopenharmony_ci                        lock = true;
88699ca880aSopenharmony_ci                        break;
88799ca880aSopenharmony_ci                case 'u':
88899ca880aSopenharmony_ci                        unlock = true;
88999ca880aSopenharmony_ci                        break;
89099ca880aSopenharmony_ci                case 'e':
89199ca880aSopenharmony_ci                        eject = true;
89299ca880aSopenharmony_ci                        break;
89399ca880aSopenharmony_ci                case 'd':
89499ca880aSopenharmony_ci                        log_set_target(LOG_TARGET_CONSOLE);
89599ca880aSopenharmony_ci                        log_set_max_level(LOG_DEBUG);
89699ca880aSopenharmony_ci                        log_open();
89799ca880aSopenharmony_ci                        break;
89899ca880aSopenharmony_ci                case 'h':
89999ca880aSopenharmony_ci                        printf("Usage: cdrom_id [options] <device>\n"
90099ca880aSopenharmony_ci                               "  -l,--lock-media    lock the media (to enable eject request events)\n"
90199ca880aSopenharmony_ci                               "  -u,--unlock-media  unlock the media\n"
90299ca880aSopenharmony_ci                               "  -e,--eject-media   eject the media\n"
90399ca880aSopenharmony_ci                               "  -d,--debug         debug to stderr\n"
90499ca880aSopenharmony_ci                               "  -h,--help          print this help text\n\n");
90599ca880aSopenharmony_ci                        goto exit;
90699ca880aSopenharmony_ci                default:
90799ca880aSopenharmony_ci                        rc = 1;
90899ca880aSopenharmony_ci                        goto exit;
90999ca880aSopenharmony_ci                }
91099ca880aSopenharmony_ci        }
91199ca880aSopenharmony_ci
91299ca880aSopenharmony_ci        node = argv[optind];
91399ca880aSopenharmony_ci        if (!node) {
91499ca880aSopenharmony_ci                log_error("no device");
91599ca880aSopenharmony_ci                fprintf(stderr, "no device\n");
91699ca880aSopenharmony_ci                rc = 1;
91799ca880aSopenharmony_ci                goto exit;
91899ca880aSopenharmony_ci        }
91999ca880aSopenharmony_ci
92099ca880aSopenharmony_ci        initialize_srand();
92199ca880aSopenharmony_ci        for (cnt = 20; cnt > 0; cnt--) {
92299ca880aSopenharmony_ci                struct timespec duration;
92399ca880aSopenharmony_ci
92499ca880aSopenharmony_ci                fd = open(node, O_RDONLY|O_NONBLOCK|O_CLOEXEC|(is_mounted(node) ? 0 : O_EXCL));
92599ca880aSopenharmony_ci                if (fd >= 0 || errno != EBUSY)
92699ca880aSopenharmony_ci                        break;
92799ca880aSopenharmony_ci                duration.tv_sec = 0;
92899ca880aSopenharmony_ci                duration.tv_nsec = (100 * 1000 * 1000) + (rand() % 100 * 1000 * 1000);
92999ca880aSopenharmony_ci                nanosleep(&duration, NULL);
93099ca880aSopenharmony_ci        }
93199ca880aSopenharmony_ci        if (fd < 0) {
93299ca880aSopenharmony_ci                log_debug("unable to open '%s'", node);
93399ca880aSopenharmony_ci                fprintf(stderr, "unable to open '%s'\n", node);
93499ca880aSopenharmony_ci                rc = 1;
93599ca880aSopenharmony_ci                goto exit;
93699ca880aSopenharmony_ci        }
93799ca880aSopenharmony_ci        log_debug("probing: '%s'", node);
93899ca880aSopenharmony_ci
93999ca880aSopenharmony_ci        /* same data as original cdrom_id */
94099ca880aSopenharmony_ci        if (cd_capability_compat(udev, fd) < 0) {
94199ca880aSopenharmony_ci                rc = 1;
94299ca880aSopenharmony_ci                goto exit;
94399ca880aSopenharmony_ci        }
94499ca880aSopenharmony_ci
94599ca880aSopenharmony_ci        /* check for media - don't bail if there's no media as we still need to
94699ca880aSopenharmony_ci         * to read profiles */
94799ca880aSopenharmony_ci        cd_media_compat(udev, fd);
94899ca880aSopenharmony_ci
94999ca880aSopenharmony_ci        /* check if drive talks MMC */
95099ca880aSopenharmony_ci        if (cd_inquiry(udev, fd) < 0)
95199ca880aSopenharmony_ci                goto work;
95299ca880aSopenharmony_ci
95399ca880aSopenharmony_ci        /* read drive and possibly current profile */
95499ca880aSopenharmony_ci        if (cd_profiles(udev, fd) != 0)
95599ca880aSopenharmony_ci                goto work;
95699ca880aSopenharmony_ci
95799ca880aSopenharmony_ci        /* at this point we are guaranteed to have media in the drive - find out more about it */
95899ca880aSopenharmony_ci
95999ca880aSopenharmony_ci        /* get session/track info */
96099ca880aSopenharmony_ci        cd_media_toc(udev, fd);
96199ca880aSopenharmony_ci
96299ca880aSopenharmony_ci        /* get writable media state */
96399ca880aSopenharmony_ci        cd_media_info(udev, fd);
96499ca880aSopenharmony_ci
96599ca880aSopenharmony_ciwork:
96699ca880aSopenharmony_ci        /* lock the media, so we enable eject button events */
96799ca880aSopenharmony_ci        if (lock && cd_media) {
96899ca880aSopenharmony_ci                log_debug("PREVENT_ALLOW_MEDIUM_REMOVAL (lock)");
96999ca880aSopenharmony_ci                media_lock(udev, fd, true);
97099ca880aSopenharmony_ci        }
97199ca880aSopenharmony_ci
97299ca880aSopenharmony_ci        if (unlock && cd_media) {
97399ca880aSopenharmony_ci                log_debug("PREVENT_ALLOW_MEDIUM_REMOVAL (unlock)");
97499ca880aSopenharmony_ci                media_lock(udev, fd, false);
97599ca880aSopenharmony_ci        }
97699ca880aSopenharmony_ci
97799ca880aSopenharmony_ci        if (eject) {
97899ca880aSopenharmony_ci                log_debug("PREVENT_ALLOW_MEDIUM_REMOVAL (unlock)");
97999ca880aSopenharmony_ci                media_lock(udev, fd, false);
98099ca880aSopenharmony_ci                log_debug("START_STOP_UNIT (eject)");
98199ca880aSopenharmony_ci                media_eject(udev, fd);
98299ca880aSopenharmony_ci        }
98399ca880aSopenharmony_ci
98499ca880aSopenharmony_ci        printf("ID_CDROM=1\n");
98599ca880aSopenharmony_ci        if (cd_cd_rom)
98699ca880aSopenharmony_ci                printf("ID_CDROM_CD=1\n");
98799ca880aSopenharmony_ci        if (cd_cd_r)
98899ca880aSopenharmony_ci                printf("ID_CDROM_CD_R=1\n");
98999ca880aSopenharmony_ci        if (cd_cd_rw)
99099ca880aSopenharmony_ci                printf("ID_CDROM_CD_RW=1\n");
99199ca880aSopenharmony_ci        if (cd_dvd_rom)
99299ca880aSopenharmony_ci                printf("ID_CDROM_DVD=1\n");
99399ca880aSopenharmony_ci        if (cd_dvd_r)
99499ca880aSopenharmony_ci                printf("ID_CDROM_DVD_R=1\n");
99599ca880aSopenharmony_ci        if (cd_dvd_rw)
99699ca880aSopenharmony_ci                printf("ID_CDROM_DVD_RW=1\n");
99799ca880aSopenharmony_ci        if (cd_dvd_ram)
99899ca880aSopenharmony_ci                printf("ID_CDROM_DVD_RAM=1\n");
99999ca880aSopenharmony_ci        if (cd_dvd_plus_r)
100099ca880aSopenharmony_ci                printf("ID_CDROM_DVD_PLUS_R=1\n");
100199ca880aSopenharmony_ci        if (cd_dvd_plus_rw)
100299ca880aSopenharmony_ci                printf("ID_CDROM_DVD_PLUS_RW=1\n");
100399ca880aSopenharmony_ci        if (cd_dvd_plus_r_dl)
100499ca880aSopenharmony_ci                printf("ID_CDROM_DVD_PLUS_R_DL=1\n");
100599ca880aSopenharmony_ci        if (cd_dvd_plus_rw_dl)
100699ca880aSopenharmony_ci                printf("ID_CDROM_DVD_PLUS_RW_DL=1\n");
100799ca880aSopenharmony_ci        if (cd_bd)
100899ca880aSopenharmony_ci                printf("ID_CDROM_BD=1\n");
100999ca880aSopenharmony_ci        if (cd_bd_r)
101099ca880aSopenharmony_ci                printf("ID_CDROM_BD_R=1\n");
101199ca880aSopenharmony_ci        if (cd_bd_re)
101299ca880aSopenharmony_ci                printf("ID_CDROM_BD_RE=1\n");
101399ca880aSopenharmony_ci        if (cd_hddvd)
101499ca880aSopenharmony_ci                printf("ID_CDROM_HDDVD=1\n");
101599ca880aSopenharmony_ci        if (cd_hddvd_r)
101699ca880aSopenharmony_ci                printf("ID_CDROM_HDDVD_R=1\n");
101799ca880aSopenharmony_ci        if (cd_hddvd_rw)
101899ca880aSopenharmony_ci                printf("ID_CDROM_HDDVD_RW=1\n");
101999ca880aSopenharmony_ci        if (cd_mo)
102099ca880aSopenharmony_ci                printf("ID_CDROM_MO=1\n");
102199ca880aSopenharmony_ci        if (cd_mrw)
102299ca880aSopenharmony_ci                printf("ID_CDROM_MRW=1\n");
102399ca880aSopenharmony_ci        if (cd_mrw_w)
102499ca880aSopenharmony_ci                printf("ID_CDROM_MRW_W=1\n");
102599ca880aSopenharmony_ci
102699ca880aSopenharmony_ci        if (cd_media)
102799ca880aSopenharmony_ci                printf("ID_CDROM_MEDIA=1\n");
102899ca880aSopenharmony_ci        if (cd_media_mo)
102999ca880aSopenharmony_ci                printf("ID_CDROM_MEDIA_MO=1\n");
103099ca880aSopenharmony_ci        if (cd_media_mrw)
103199ca880aSopenharmony_ci                printf("ID_CDROM_MEDIA_MRW=1\n");
103299ca880aSopenharmony_ci        if (cd_media_mrw_w)
103399ca880aSopenharmony_ci                printf("ID_CDROM_MEDIA_MRW_W=1\n");
103499ca880aSopenharmony_ci        if (cd_media_cd_rom)
103599ca880aSopenharmony_ci                printf("ID_CDROM_MEDIA_CD=1\n");
103699ca880aSopenharmony_ci        if (cd_media_cd_r)
103799ca880aSopenharmony_ci                printf("ID_CDROM_MEDIA_CD_R=1\n");
103899ca880aSopenharmony_ci        if (cd_media_cd_rw)
103999ca880aSopenharmony_ci                printf("ID_CDROM_MEDIA_CD_RW=1\n");
104099ca880aSopenharmony_ci        if (cd_media_dvd_rom)
104199ca880aSopenharmony_ci                printf("ID_CDROM_MEDIA_DVD=1\n");
104299ca880aSopenharmony_ci        if (cd_media_dvd_r)
104399ca880aSopenharmony_ci                printf("ID_CDROM_MEDIA_DVD_R=1\n");
104499ca880aSopenharmony_ci        if (cd_media_dvd_ram)
104599ca880aSopenharmony_ci                printf("ID_CDROM_MEDIA_DVD_RAM=1\n");
104699ca880aSopenharmony_ci        if (cd_media_dvd_rw)
104799ca880aSopenharmony_ci                printf("ID_CDROM_MEDIA_DVD_RW=1\n");
104899ca880aSopenharmony_ci        if (cd_media_dvd_plus_r)
104999ca880aSopenharmony_ci                printf("ID_CDROM_MEDIA_DVD_PLUS_R=1\n");
105099ca880aSopenharmony_ci        if (cd_media_dvd_plus_rw)
105199ca880aSopenharmony_ci                printf("ID_CDROM_MEDIA_DVD_PLUS_RW=1\n");
105299ca880aSopenharmony_ci        if (cd_media_dvd_plus_rw_dl)
105399ca880aSopenharmony_ci                printf("ID_CDROM_MEDIA_DVD_PLUS_RW_DL=1\n");
105499ca880aSopenharmony_ci        if (cd_media_dvd_plus_r_dl)
105599ca880aSopenharmony_ci                printf("ID_CDROM_MEDIA_DVD_PLUS_R_DL=1\n");
105699ca880aSopenharmony_ci        if (cd_media_bd)
105799ca880aSopenharmony_ci                printf("ID_CDROM_MEDIA_BD=1\n");
105899ca880aSopenharmony_ci        if (cd_media_bd_r)
105999ca880aSopenharmony_ci                printf("ID_CDROM_MEDIA_BD_R=1\n");
106099ca880aSopenharmony_ci        if (cd_media_bd_re)
106199ca880aSopenharmony_ci                printf("ID_CDROM_MEDIA_BD_RE=1\n");
106299ca880aSopenharmony_ci        if (cd_media_hddvd)
106399ca880aSopenharmony_ci                printf("ID_CDROM_MEDIA_HDDVD=1\n");
106499ca880aSopenharmony_ci        if (cd_media_hddvd_r)
106599ca880aSopenharmony_ci                printf("ID_CDROM_MEDIA_HDDVD_R=1\n");
106699ca880aSopenharmony_ci        if (cd_media_hddvd_rw)
106799ca880aSopenharmony_ci                printf("ID_CDROM_MEDIA_HDDVD_RW=1\n");
106899ca880aSopenharmony_ci
106999ca880aSopenharmony_ci        if (cd_media_state != NULL)
107099ca880aSopenharmony_ci                printf("ID_CDROM_MEDIA_STATE=%s\n", cd_media_state);
107199ca880aSopenharmony_ci        if (cd_media_session_next > 0)
107299ca880aSopenharmony_ci                printf("ID_CDROM_MEDIA_SESSION_NEXT=%u\n", cd_media_session_next);
107399ca880aSopenharmony_ci        if (cd_media_session_count > 0)
107499ca880aSopenharmony_ci                printf("ID_CDROM_MEDIA_SESSION_COUNT=%u\n", cd_media_session_count);
107599ca880aSopenharmony_ci        if (cd_media_session_count > 1 && cd_media_session_last_offset > 0)
107699ca880aSopenharmony_ci                printf("ID_CDROM_MEDIA_SESSION_LAST_OFFSET=%llu\n", cd_media_session_last_offset);
107799ca880aSopenharmony_ci        if (cd_media_track_count > 0)
107899ca880aSopenharmony_ci                printf("ID_CDROM_MEDIA_TRACK_COUNT=%u\n", cd_media_track_count);
107999ca880aSopenharmony_ci        if (cd_media_track_count_audio > 0)
108099ca880aSopenharmony_ci                printf("ID_CDROM_MEDIA_TRACK_COUNT_AUDIO=%u\n", cd_media_track_count_audio);
108199ca880aSopenharmony_ci        if (cd_media_track_count_data > 0)
108299ca880aSopenharmony_ci                printf("ID_CDROM_MEDIA_TRACK_COUNT_DATA=%u\n", cd_media_track_count_data);
108399ca880aSopenharmony_ciexit:
108499ca880aSopenharmony_ci        if (fd >= 0)
108599ca880aSopenharmony_ci                close(fd);
108699ca880aSopenharmony_ci        udev_unref(udev);
108799ca880aSopenharmony_ci        log_close();
108899ca880aSopenharmony_ci        return rc;
108999ca880aSopenharmony_ci}
1090