14

I know my CD-ROM device (/dev/sr0) but how can I detect from a script whether the drive is empty or whether there is a disk in it?

1

7 Answers 7

11

You can get information about any block device using the command blkid.

[root@arch32-vm ~]# blkid /dev/sr0
/dev/sr0: UUID="2013-05-31-23-04-19-00" LABEL="ARCH_201306" TYPE="iso9660" PTTYPE="dos"
[root@arch32-vm ~]# echo $?
0

If I remove the disk, I don't get any output and exit value is 2. (0 means success. A non-zero value will typically mean something abnormal happen or an error occurred)

[root@arch32-vm ~]# blkid /dev/sr0
[root@arch32-vm ~]# echo $?
2
2
  • 5
    blkid detects partitions, If i put a audio CD, it is not detected. Didn't find a easier solution than create a program using ioctl as described in stackoverflow.com/questions/15652520/…
    – BatchyX
    May 17, 2014 at 19:55
  • 2
    blkid causes the CD/DVD drive to close. I want something that can check if the platter is OPEN / CLOSED first, I think. Once closed (by a person), then it makes sense to see if there's media present. Any thoughts on that?
    – will
    Nov 5, 2018 at 10:56
11

setcd -i (in the setcd package, at least on Debian) can tell you the state of the drive. Unlike some of the other approaches (mount at least, probably blkid too), this will not attempt to close the tray, even on drives capable of that. (Which is really annoying if it tries to close on you while you're putting a disc in).

With the tray open:

$ setcd -i /dev/sr0
/dev/sr0:
  CD tray is open

Right after closing the tray:

$ setcd -i /dev/sr0
/dev/sr0:
  Drive is not ready

After it's ready:

$ setcd -i /dev/sr0
/dev/sr0:
  Disc found in drive: data disc type 1
    Volume name: «name»
    Publisher:                                                                                                                                                                                                                                                                 MKISOFS ISO 9660/HFS FILESYSTEM BUILDER & CDRECORD CD-R/DVD CREATOR (C) 1993 E.YOUNGDALE (C) 1997 J.PEARSON/J.SCHILLING                                                                                                                        2005030913034700�2005030913034700�0000000000000000
    Data preparer:                                                                                                                                 MKISOFS ISO 9660/HFS FILESYSTEM BUILDER & CDRECORD CD-R/DVD CREATOR (C) 1993 E.YOUNGDALE (C) 1997 J.PEARSON/J.SCHILLING                                                                                                                        2005030913034700�2005030913034700�0000000000000000

Closed, but no disc:

$ setcd -i /dev/sr0
/dev/sr0:
  No disc is inserted

You can fairly easily script it:

while true; do
    cdinfo=$(setcd -i "$dev")
    case "$cdinfo" in
        *'Disc found'*)
            break;
            ;;
        *'not ready'*)
            echo '(waiting for drive to be ready)' >&2;
            sleep 3;
            ;;
        *'is open'*)
            echo '(drive is open)' >&2;
            sleep 5;
            ;;
        *)
            printf 'Confused by setcd -i, bailing out:\n%s\n' "$cdinfo" &2
            exit 1
    esac
done
6

You can do the following with Python3 and the standard library:

import fcntl
import os

CDROM_DRIVE = '/dev/sr0'

def detect_tray(CDROM_DRIVE):
    """detect_tray reads status of the CDROM_DRIVE.
    Statuses:
    1 = no disk in tray
    2 = tray open
    3 = reading tray
    4 = disk in tray
    """
    fd = os.open(CDROM_DRIVE, os.O_RDONLY | os.O_NONBLOCK)
    rv = fcntl.ioctl(fd, 0x5326)
    os.close(fd)
    print(rv)
4

You can try with lsblk command:

lsblk -fp

If under FSTYPE for line /dev/sr0 there is nothing -> media not loaded into cdrom drive. If there is something under FSTYPE, probably iso9660 -> media is loaded into cdrom drive.

Another, I think the simplest way:

cat /dev/sr0 | head -1

If output is:

cat: /dev/sr0: No medium found

-> no media loaded.

If output is anything but this:

cat: /dev/sr0: No medium found

-> media is loaded.

Notice: I didn't try this with audio nor empty cds, but I believe result would be the same.

1
  • With an audio CD, lsblk did not show any information, and trying to retrieve data gives Input/output error or no simply no data, while it works accessing a track through nautilus with a standard media player.
    – Pysis
    Nov 3, 2022 at 4:44
1

Try mounting the device.

mount -t iso9660 /dev/sr0 /mnt/cdrom

Then check the return value $?

If the return is 0, "good" then there was disc present. Else, it will return not good "1" or anything but "0"

So to check silently, I would script it as so.

cdrom_mount=0
mount -t iso9660 /dev/sr0 /mnt/cdrom >/dev/null 2>&1
if [[ $? -gt 0 ]]
    then
    cdrom_mount=true
else
    cdrom_mount=false
fi

This is a very simplistic example, but you could do something similar...

2
  • Isn't that -gt should be -eq ?
    – SHW
    Feb 11, 2014 at 6:56
  • A blank CD will fail to be mounted, so using mount does not really work. A broken CD will also fail to be mounted, but it is however present in the drive.
    – Étienne
    Jan 7, 2016 at 16:22
1

The issue with this shell-scripting approach is that none of the shell commands, mount, lsblk, blkid, can wait/block/pause and determine whether a cdrom is reporting "no medium found" because the tray has just closed and it is initializing itself to read the cd, or because there is no cd in the device, and "no medium found" will be reported forever. So you can choose a reasonable number of tries to pester the cdrom device at a certain sleep interval before giving up, as in the shell script below, or you can write a piece of c code with a few ioctl calls, and get some information from the cdrom, directly through the kernel.

#!/bin/sh

# cd.close
#
# Close the CD-ROM tray, and mount the CD-ROM device:
#
# mount status codes: see man mount(8)
# ------------------------------------
# 0   success
# 1   incorrect invocation or permissions
# 2   system error (out of memory, cannot fork, no more loop devices)
# 4   internal mount bug
# 8   user interrupt
# 16  problems writing or locking /etc/mtab
# 32  mount failure
# 64  some mount succeeded (in the case of mount -a)

CDROM=/dev/sr0
TRIES="1 2 3"
INTERVAL=5
MOUNT=0

TOKENS=( $TRIES )
STOP=${TOKENS[-1]}

for i in $TRIES; do
echo close: ATTEMPT $i of $STOP
output=`mount $CDROM -t iso9660 /cdrom 2>&1`
status=$?
echo mount: OUTPUT $output
echo mount: STATUS $status
if [ $status -eq 0 ]; then
  MOUNT=1
  break
else
  if [[ "$output" =~ "already mounted" ]]; then
    MOUNT=1
    break
  fi
fi
if [ $i -eq $STOP ]; then
  break
fi
echo sleep: $INTERVAL SECONDS...
sleep $INTERVAL
done

if [ $MOUNT -eq 1 ]; then
  echo final: MOUNTED $CDROM
  printf "final: LABEL "
  volname $CDROM
else
  echo final: NO MEDIUM
fi
0

Here is the shell script I use for my own purposes. It's partially based on Allan's answer.

The reasoning behind it is basically that I was using it in an extended shell command using && and needed it to wait for the device to be ready to mount.

#!/bin/bash
# mountdvd:
#   A shell script to wait until the optical drive can be mounted.
#
#   Important Notes:
#    - By default, this will wait about 10 seconds for the drive to finish reading a newly
#      inserted disk.
#    - Works best already be given a mount point in /etc/fstab
#    - Works best if fs type is set to auto
#    - Assumes /etc/fstab allows user to mount device
#
#   Example /etc/fstab listing:
#    /dev/cdrom /media/dvd auto nofail,auto,user,exec,utf8,noatime,ro,uid=plex,gid=pi 0 0

# Command name
COMMAND=`basename $0`

# Device to mount
DVD_DEVICE=/dev/cdrom
MOUNT_POINT=/media/dvd

# Number of attempts before giving up (Total time = ATTEMPTS * WAIT_TIME, default: 10 seconds)
ATTEMPTS=20

# Wait time in seconds
WAIT_TIME=0.5

# Check if already mounted first
MOUTPUT=`mountpoint -q $MOUNT_POINT`
MSTATUS=$?

if [ $MSTATUS -eq 0 ]; then
    echo "$COMMAND: $DVD_DEVICE was already mounted."
    exit 0
fi

#for ATTEMPT in {1..$ATTEMPTS}
while [ $ATTEMPTS -gt 0 ];
do
    # Attempt to mount device
    OUTPUT=`mount $DVD_DEVICE 2>&1`
    STATUS=$?

    if [ $STATUS -eq 0 ]; then
        # Device mounted
        exit 0
    else
        # Double check here, just in case earlier check failed.
        if [[ "$OUTPUT" =~ "already mounted" ]]; then
            # Device was already mounted
            echo "$COMMAND: $DVD_DEVICE was already mounted."
            exit 0
        fi
    fi

    if [ $ATTEMPTS -ne 1 ]; then
        # Wait a moment before trying again.
        sleep $WAIT_TIME
    fi

    let ATTEMPTS=ATTEMPTS-1
done

echo "$COMMAND: ERROR: Unable to mount $DVD_DEVICE."
exit 1

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .