thomasvs / morituri

For those about to RIP - a Unix CD ripper preferring accuracy over speed
GNU General Public License v3.0
300 stars 42 forks source link

"rip cd info" crashes with IOError: [Errno 2] No such file or directory: '/proc/mounts' on Mac OS X 10.5.8 #69

Open JDLH opened 10 years ago

JDLH commented 10 years ago

I am using morituri 0.2.2 on Mac OS X 10.5.8 . Certain CD-related commands crash. I believe this is because morituri relies on Linux-specific CD-handing shell commands, and the equivalent commends on Mac OS X are different.

To reproduce

  1. Put a popular CD into a CD-ROM drive which Morituri uses.
  2. Command rip cd info

    Observed behaviour

% rip cd info
Checking device /dev/rdisk1
sh: eject: command not found
Traceback (most recent call last):
  File "/usr/local/bin/rip", line 41, in <module>
    sys.exit(main.main(sys.argv[1:]))
  File "/Users/jdlh/workspace/morituri/morituri/rip/main.py", line 45, in main
    ret = c.parse(argv)
  File "/Users/jdlh/workspace/morituri/morituri/rip/main.py", line 123, in parse
    logcommand.LogCommand.parse(self, argv)
  File "/Users/jdlh/workspace/morituri/morituri/extern/command/command.py", line 401, in parse
    return self.subCommands[command].parse(args[1:])
  File "/Users/jdlh/workspace/morituri/morituri/extern/command/command.py", line 401, in parse
    return self.subCommands[command].parse(args[1:])
  File "/Users/jdlh/workspace/morituri/morituri/extern/command/command.py", line 363, in parse
    ret = self.do(args)
  File "/Users/jdlh/workspace/morituri/morituri/rip/cd.py", line 74, in do
    self.program.unmountDevice(self.device)
  File "/Users/jdlh/workspace/morituri/morituri/common/program.py", line 112, in unmountDevice
    proc = open('/proc/mounts').read()
IOError: [Errno 2] No such file or directory: '/proc/mounts'

Expected behaviour

Command runs successfully, and returns info on inserted CD.

Further observations

rip offset find yields similar error messages. I suspect more commands might also use the same underlying code, and also be affected.

morituri/morituri/common/program.py invokes a number of shell commands. We should expect them to have OS-related differences. But I see no code there to check the current OS or to select alternate commands based on the OS.

JDLH commented 10 years ago

From a quick look at morituri/morituri/common/program.py, I see three places where OS-specific code is used:

I don't see any other OS-specific code of this sort in this module.

These methods are in class Program(log.Loggable), so one approach is to write ProgramMacOS, a subclass of Program which overrides these methods with Mac-specific versions. That would require changing the code which instantiates Program to choose the right implementation.

Another approach is to put an OS test and OS-specific code in each of these methods.

JDLH commented 10 years ago

The Picard tagger from MusicBrainz has been over this territory before. See their issue, Picard should auto detect the CD on MacOS X, http://tickets.musicbrainz.org/browse/PICARD-123 . Their conclusion: the Mac drutil system command is the right way to accomplish this. See also their libdiscid, and their https://github.com/musicbrainz/picard/blob/master/picard/util/cdrom.py .

JDLH commented 10 years ago

morituri invokes cdrdao to get CD TOC information. The command line which morituri would like to use is ['cdrdao', 'disk-info', '--device', '/dev/rdisk4'] (where the final parameter is the morituri device identifier.

Unfortunately, on Mac OS X, cdrdao appears to require a long and very involved value for --device. On my machine, it is 'IOService:/AppleACPIPlatformExpert/PCI0/AppleACPIPCI/``EHC1@1D,7/AppleUSBEHCI/USB Mass Storage Device @fd100000/``IOUSBInterface@0/IOUSBMassStorageClass/IOSCSIPeripheralDeviceNub/``IOSCSIPeripheralDeviceType05/IODVDServices' (line breaks added).

Where on earth can we get that string from? Well, one way is to run cdrdao scanbus, which gives, for each drive, the "device" value, and a make string and a model string for the drive. I expect it's possible to write code to map from a device value like "/dev/rdisk4" to "IOService:/AppleACPIPlatformExpert/PCI0/AppleACPIPCI/``EHC1@1D,7/AppleUSBEHCI/USB Mass Storage Device @fd100000/``IOUSBInterface@0/IOUSBMassStorageClass/IOSCSIPeripheralDeviceNub/``IOSCSIPeripheralDeviceType05/IODVDServices", but I'm not expecting it to be easy.

Is there a better way?

JDLH commented 10 years ago

It turns out that on Mac OS X, cdrdao will also accept a device parameter of the form 0,0,0. It transforms this into a 1-based integer into a list of CD/DVD devices as listed by command ioreg. There are many details, but essentially what I've been able to implement so far is to pass cdrdao the constant device parameter 0,0,0, which means that morituri can work on a Mac with only one CD in any of its drives at a time. When I publish my patch, there will be detailed documentation on cdrdao's device parameter there.

Maybe there will be a better way discovered, which lets morituri convert the user's device pathname (e.g. /dev/rdisk3) into the appropriate 0,0,%i for cdrdao. Then morituri could work on a Mac with multiple CD's inserted.

JDLH commented 10 years ago

Another complication: after every cdrdao command, the CD re-mounts. This may be a feature of cdrdao on Mac OS X, or Mac OS's automount feature. Since cdrdao requires that the CD be dismounted to do its work, that means I need to add some way to unmount the CD from the file system before each invocation of cdrdao.

JDLH commented 10 years ago

I have been working on a branch which a) has Mac OS X ("Darwin") alternatives for unmountDevice() and friends, b) unmounts the CD driver before calling cdrdao, and c) manipulates device names into various of three forms needed on Mac OS X. I will push this branch to my fork of morituri, but I don't think it's worth pushing it to this repository yet.

The current problem is that cdparanoia is not behaving as expected on Mac OS X 10.5.8. When called from morituri, it frequently exits from a read track task having returned no data. Sometimes the return code indicates an error, sometimes not. When I run cdparanoia -A alone from the command line targeting a USB CD/DVD RW drive, it reports many errors with the drive. When I move to a Linux machine, plug in the same drive, and run the Linux port of the same version of cdparanoia, it reports no errors with that drive. Thus I think the MacPorts port of CDParanoia is buggy. This is a blocker for using morituri on Mac OS X 10.5.8, I think.

JDLH commented 10 years ago

It is true that cdparanoia appears not to work correctly on Mac OS X 10.5.8, and that this prevents full use of morituri on Mac OS X 10.5. However, I think that to include that problem in this issue will be scope creep, and a bad idea.

This issue was defined by the buggy behaviour rip cd info on this platform. The expected behaviour is, "Command runs successfully, and returns info on inserted CD." I think it's appropriate to limit the scope of this issue to rip cd info. Fixing that will improve morituri's Mac OS X support greatly. There are other problems, but they should be tracked in other issues. I will create another issue to deal with problems with rip offset find and friends on Mac OS X.

I have a tentative fix for this issue's limited scope on branch fix-69-mac-system-commands of my morituri fork. With it, the command runs successfully, and returns info on the inserted CD. When I'm done testing it, I'll turn that work into a pull request which proposes to fix this issue.