"""Optical drive helpers for the Ekklesia Classroom shell. Everything here is deliberately dependency free and non-blocking so the dock can poll drive state from its GTK main loop without stalling and without spinning the drive up. """ import fcntl import glob import os # linux/cdrom.h CDROM_DRIVE_STATUS = 0x5326 CDROM_DISC_STATUS = 0x5327 CDROMEJECT = 0x5309 CDROMCLOSETRAY = 0x5319 # CDSL_CURRENT: "whatever slot is loaded right now". CDSL_CURRENT = 0x7FFFFFFF # Drive status values. CDS_NO_INFO = 0 CDS_NO_DISC = 1 CDS_TRAY_OPEN = 2 CDS_DRIVE_NOT_READY = 3 CDS_DISC_OK = 4 # Disc status values. CDS_AUDIO = 100 CDS_DATA_1 = 101 CDS_DATA_2 = 102 CDS_XA_2_1 = 103 CDS_XA_2_2 = 104 CDS_MIXED = 105 def devices(): """Every optical device node currently present.""" return sorted(glob.glob("/dev/sr[0-9]*")) def default_device(): """The optical device the classroom should use, if any.""" found = devices() if not found: return None return found[0] def _ioctl(device, request, argument=CDSL_CURRENT): """Run a CD-ROM ioctl, returning None when the drive cannot be read.""" try: fd = os.open(device, os.O_RDONLY | os.O_NONBLOCK) except OSError: return None try: return fcntl.ioctl(fd, request, argument) except OSError: return None finally: os.close(fd) def drive_status(device=None): """CDS_* drive status, or None when there is no readable drive.""" if device is None: device = default_device() if device is None: return None return _ioctl(device, CDROM_DRIVE_STATUS) def disc_status(device=None): """CDS_* disc type. Only call this once a disc has become ready.""" if device is None: device = default_device() if device is None: return None return _ioctl(device, CDROM_DISC_STATUS) def has_disc(device=None): """True when a disc is loaded and the drive has finished reading it.""" return drive_status(device) == CDS_DISC_OK def eject(device=None): """Open the tray. Returns True when the drive accepted the request.""" if device is None: device = default_device() if device is None: return False return _ioctl(device, CDROMEJECT, 0) is not None def close_tray(device=None): """Close the tray. Returns True when the drive accepted the request.""" if device is None: device = default_device() if device is None: return False return _ioctl(device, CDROMCLOSETRAY, 0) is not None def describe(status): """Human readable drive status, used by classroom-dvd status.""" return { None: "no drive", CDS_NO_INFO: "unknown", CDS_NO_DISC: "no disc", CDS_TRAY_OPEN: "tray open", CDS_DRIVE_NOT_READY: "drive not ready", CDS_DISC_OK: "disc ready", }.get(status, "unknown")