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