Files
whipper-gui/morituri/program/cdrdao.py
Samantha Baldwin a1eb3377ea cdrdao no-disc ejection & --eject (#93)
* cdrdao: eject empty disc while reading toc

- introduce EjectError
- move {eject,load,unmount}_device to program.utils

* remove duplicated eject

* remove unnecessary ejection

* add --eject option
2017-01-01 19:41:23 +01:00

83 lines
2.5 KiB
Python

import os
import re
import tempfile
from subprocess import Popen, PIPE
from morituri.common.common import EjectError
from morituri.image.toc import TocFile
import logging
logger = logging.getLogger(__name__)
CDRDAO = 'cdrdao'
def read_toc(device, fast_toc=False):
"""
Return cdrdao-generated table of contents for 'device'.
"""
# cdrdao MUST be passed a non-existing filename as its last argument
# to write the TOC to; it does not support writing to stdout or
# overwriting an existing file, nor does linux seem to support
# locking a non-existant file. Thus, this race-condition introducing
# hack is carried from morituri to whipper and will be removed when
# cdrdao is fixed.
fd, tocfile = tempfile.mkstemp(suffix=u'.cdrdao.read-toc.whipper')
os.close(fd)
os.unlink(tocfile)
cmd = [CDRDAO, 'read-toc'] + (['--fast-toc'] if fast_toc else []) + [
'--device', device, tocfile]
# PIPE is the closest to >/dev/null we can get
logger.debug("executing %r", cmd)
p = Popen(cmd, stdout=PIPE, stderr=PIPE)
_, stderr = p.communicate()
if p.returncode != 0:
msg = 'cdrdao read-toc failed: return code is non-zero: ' + \
str(p.returncode)
logger.critical(msg)
# Gracefully handle missing disc
if "ERROR: Unit not ready, giving up." in stderr:
raise EjectError(device, "no disc detected")
raise IOError(msg)
toc = TocFile(tocfile)
toc.parse()
os.unlink(tocfile)
return toc
def version():
"""
Return cdrdao version as a string.
"""
cdrdao = Popen(CDRDAO, stderr=PIPE)
out, err = cdrdao.communicate()
if cdrdao.returncode != 1:
logger.warning("cdrdao version detection failed: "
"return code is " + str(cdrdao.returncode))
return None
m = re.compile(r'^Cdrdao version (?P<version>.*) - \(C\)').search(
err.decode('utf-8'))
if not m:
logger.warning("cdrdao version detection failed: "
"could not find version")
return None
return m.group('version')
def ReadTOCTask(device):
"""
stopgap morituri-insanity compatibility layer
"""
return read_toc(device, fast_toc=True)
def ReadTableTask(device):
"""
stopgap morituri-insanity compatibility layer
"""
return read_toc(device)
def getCDRDAOVersion():
"""
stopgap morituri-insanity compatibility layer
"""
return version()