cdrom_id.c revision a14f14976094650e17d39f3a7d15a1c68c93c333
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering * cdrom_id - optical drive and media information prober
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering * Copyright (C) 2008-2010 Kay Sievers <kay@vrfy.org>
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering * This program is free software: you can redistribute it and/or modify
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering * it under the terms of the GNU General Public License as published by
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering * the Free Software Foundation, either version 2 of the License, or
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering * (at your option) any later version.
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering * This program is distributed in the hope that it will be useful,
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering * but WITHOUT ANY WARRANTY; without even the implied warranty of
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering * GNU General Public License for more details.
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering * You should have received a copy of the GNU General Public License
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering * along with this program. If not, see <http://www.gnu.org/licenses/>.
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic void log_fn(struct udev *udev, int priority,
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering const char *file, int line, const char *fn,
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering/* device info */
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_cd_rom;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_cd_r;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_cd_rw;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_dvd_rom;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_dvd_r;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_dvd_rw;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_dvd_ram;
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poetteringstatic unsigned int cd_dvd_plus_r;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_dvd_plus_rw;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_dvd_plus_r_dl;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_dvd_plus_rw_dl;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_bd;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_bd_r;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_bd_re;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_hddvd;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_hddvd_r;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_hddvd_rw;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_mo;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_mrw;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_mrw_w;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering/* media info */
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poetteringstatic unsigned int cd_media;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_media_cd_rom;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_media_cd_r;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_media_cd_rw;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_media_dvd_rom;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_media_dvd_r;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_media_dvd_rw;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_media_dvd_rw_ro; /* restricted overwrite mode */
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_media_dvd_rw_seq; /* sequential mode */
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_media_dvd_ram;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_media_dvd_plus_r;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_media_dvd_plus_rw;
b7c9ae91d111b3e89d1ffc00e08f9ed97a8ff5dbLennart Poetteringstatic unsigned int cd_media_dvd_plus_r_dl;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_media_dvd_plus_rw_dl;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_media_bd;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_media_bd_r;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_media_bd_re;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_media_hddvd;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_media_hddvd_r;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_media_hddvd_rw;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_media_mo;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_media_mrw;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_media_mrw_w;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_media_session_next;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_media_session_count;
b7c9ae91d111b3e89d1ffc00e08f9ed97a8ff5dbLennart Poetteringstatic unsigned int cd_media_track_count;
b7c9ae91d111b3e89d1ffc00e08f9ed97a8ff5dbLennart Poetteringstatic unsigned int cd_media_track_count_data;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned int cd_media_track_count_audio;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic unsigned long long int cd_media_session_last_offset;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering#define ERRCODE(s) ((((s)[2] & 0x0F) << 16) | ((s)[12] << 8) | ((s)[13]))
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering#define SK(errcode) (((errcode) >> 16) & 0xF)
b7c9ae91d111b3e89d1ffc00e08f9ed97a8ff5dbLennart Poettering#define ASC(errcode) (((errcode) >> 8) & 0xFF)
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic bool is_mounted(const char *device)
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering fp = fopen("/proc/self/mountinfo", "re");
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering while (fscanf(fp, "%*s %*s %i:%i %*[^\n]", &maj, &min) == 2) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering if (makedev(maj, min) == statbuf.st_rdev) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic void info_scsi_cmd_err(struct udev *udev, const char *cmd, int err)
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("%s failed with SK=%Xh/ASC=%02Xh/ACQ=%02Xh", cmd, SK(err), ASC(err), ASCQ(err));
b7c9ae91d111b3e89d1ffc00e08f9ed97a8ff5dbLennart Poettering unsigned char u[18];
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic void scsi_cmd_init(struct udev *udev, struct scsi_cmd *cmd)
b7c9ae91d111b3e89d1ffc00e08f9ed97a8ff5dbLennart Poettering cmd->sg_io.mx_sb_len = sizeof(cmd->_sense);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering cmd->sg_io.flags = SG_FLAG_LUN_INHIBIT | SG_FLAG_DIRECT_IO;
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poetteringstatic void scsi_cmd_set(struct udev *udev, struct scsi_cmd *cmd, size_t i, unsigned char arg)
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poetteringstatic int scsi_cmd_run(struct udev *udev, struct scsi_cmd *cmd, int fd, unsigned char *buf, size_t bufsize)
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering cmd->sg_io.dxfer_direction = SG_DXFER_FROM_DEV;
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering cmd->sg_io.dxfer_direction = SG_DXFER_NONE;
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering if ((cmd->sg_io.info & SG_INFO_OK_MASK) != SG_INFO_OK) {
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poettering if (cmd->sg_io.masked_status & CHECK_CONDITION) {
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poetteringstatic int media_lock(struct udev *udev, int fd, bool lock)
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering /* disable the kernel's lock logic */
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering err = ioctl(fd, CDROM_CLEAR_OPTIONS, CDO_LOCK);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("CDROM_CLEAR_OPTIONS, CDO_LOCK failed");
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering err = ioctl(fd, CDROM_LOCKDOOR, lock ? 1 : 0);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic int media_eject(struct udev *udev, int fd)
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering err = scsi_cmd_run(udev, &sc, fd, NULL, 0);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering info_scsi_cmd_err(udev, "START_STOP_UNIT", err);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic int cd_capability_compat(struct udev *udev, int fd)
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering capability = ioctl(fd, CDROM_GET_CAPABILITY, NULL);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("CDROM_GET_CAPABILITY failed");
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic int cd_media_compat(struct udev *udev, int fd)
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering if (ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT) != CDS_DISC_OK) {
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("CDROM_DRIVE_STATUS != CDS_DISC_OK");
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poetteringstatic int cd_inquiry(struct udev *udev, int fd)
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering err = scsi_cmd_run(udev, &sc, fd, inq, 36);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("INQUIRY: [%.8s][%.16s][%.4s]", inq + 8, inq + 16, inq + 32);
14d10188de1fd58e663d73683a400d8d7dc67dbaLennart Poetteringstatic void feature_profile_media(struct udev *udev, int cur_profile)
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("profile 0x%02x ", cur_profile);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("profile 0x%02x media_cd_rom", cur_profile);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("profile 0x%02x media_cd_r", cur_profile);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("profile 0x%02x media_cd_rw", cur_profile);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("profile 0x%02x media_dvd_ro", cur_profile);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("profile 0x%02x media_dvd_r", cur_profile);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("profile 0x%02x media_dvd_ram", cur_profile);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("profile 0x%02x media_dvd_rw_ro", cur_profile);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("profile 0x%02x media_dvd_rw_seq", cur_profile);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("profile 0x%02x media_dvd_plus_r", cur_profile);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("profile 0x%02x media_dvd_plus_rw", cur_profile);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("profile 0x%02x media_dvd_plus_rw_dl", cur_profile);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("profile 0x%02x media_dvd_plus_r_dl", cur_profile);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("profile 0x%02x media_bd", cur_profile);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("profile 0x%02x media_bd_r", cur_profile);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("profile 0x%02x media_bd_re", cur_profile);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("profile 0x%02x media_hddvd", cur_profile);
b7c9ae91d111b3e89d1ffc00e08f9ed97a8ff5dbLennart Poettering log_debug("profile 0x%02x media_hddvd_r", cur_profile);
b7c9ae91d111b3e89d1ffc00e08f9ed97a8ff5dbLennart Poettering log_debug("profile 0x%02x media_hddvd_rw", cur_profile);
b7c9ae91d111b3e89d1ffc00e08f9ed97a8ff5dbLennart Poettering log_debug("profile 0x%02x <ignored>", cur_profile);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poetteringstatic int feature_profiles(struct udev *udev, const unsigned char *profiles, size_t size)
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering unsigned int i;
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering profile = profiles[i] << 8 | profiles[i+1];
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("profile 0x%02x cd_rom", profile);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("profile 0x%02x cd_r", profile);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("profile 0x%02x cd_rw", profile);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("profile 0x%02x dvd_rom", profile);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("profile 0x%02x dvd_ram", profile);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("profile 0x%02x dvd_rw", profile);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("profile 0x%02x dvd_plus_r", profile);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("profile 0x%02x dvd_plus_rw", profile);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("profile 0x%02x dvd_plus_rw_dl", profile);
0284adc6a60ce0af1107cb0b50041a65d731f39eLennart Poettering log_debug("profile 0x%02x dvd_plus_r_dl", profile);
4da416aa20b956571d74720bc91222881443e24bLennart Poettering log_debug("profile 0x%02x bd_r", profile);
int err;
if ((err != 0)) {
unsigned int cur_profile = 0;
unsigned int len;
int err;
int ret;
if ((err != 0)) {
goto out;
if (cur_profile > 0) {
if ((err != 0)) {
unsigned int feature;
switch (feature) {
log_debug("GET CONFIGURATION: feature 0x%04x <ignored>, with 0x%02x bytes", feature, features[i+3]);
out:
return ret;
static const char *media_status[] = {
int err;
if ((err != 0)) {
if (!cd_media_cd_rom)
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) {
if (cd_media_dvd_ram) {
if ((err != 0)) {
goto determined;
if ((err != 0)) {
goto determined;
if ((err != 0)) {
cd_media = 0;
result = 0;
offset++;
if (!result) {
int err;
if ((err != 0)) {
if ((err != 0)) {
unsigned int block;
unsigned int is_data_track;
if (is_data_track)
if ((err != 0)) {
bool eject = false;
bool lock = false;
bool unlock = false;
int cnt;
int rc = 0;
goto exit;
log_open();
int option;
switch (option) {
lock = true;
unlock = true;
eject = true;
debug = true;
goto exit;
goto exit;
if (!node) {
goto exit;
if (fd < 0) {
goto exit;
goto exit;
goto work;
goto work;
work:
if (eject) {
if (cd_cd_rom)
if (cd_cd_r)
if (cd_cd_rw)
if (cd_dvd_rom)
if (cd_dvd_r)
if (cd_dvd_rw)
if (cd_dvd_ram)
if (cd_dvd_plus_r)
if (cd_dvd_plus_rw)
if (cd_dvd_plus_r_dl)
if (cd_dvd_plus_rw_dl)
if (cd_bd)
if (cd_bd_r)
if (cd_bd_re)
if (cd_hddvd)
if (cd_hddvd_r)
if (cd_hddvd_rw)
if (cd_mo)
if (cd_mrw)
if (cd_mrw_w)
if (cd_media)
if (cd_media_mo)
if (cd_media_mrw)
if (cd_media_mrw_w)
if (cd_media_cd_rom)
if (cd_media_cd_r)
if (cd_media_cd_rw)
if (cd_media_dvd_rom)
if (cd_media_dvd_r)
if (cd_media_dvd_ram)
if (cd_media_dvd_rw)
if (cd_media_dvd_plus_r)
if (cd_media_dvd_plus_rw)
if (cd_media_bd)
if (cd_media_bd_r)
if (cd_media_bd_re)
if (cd_media_hddvd)
if (cd_media_hddvd_r)
if (cd_media_hddvd_rw)
if (cd_media_session_next > 0)
if (cd_media_session_count > 0)
if (cd_media_track_count > 0)
if (cd_media_track_count_audio > 0)
if (cd_media_track_count_data > 0)
exit:
if (fd >= 0)
log_close();
return rc;