CDEmu Daemon v.1.2.0 ~~~~~~~~~~~~~ Table of contents ~~~~~~~~~~~~~~~~~ 1. Introduction 2. Userspace-cdemu suite overview 3. Requirements 4. Installation and set-up 5. Troubleshooting 6. CDEmu daemon D-BUS interface 7. Device options 8. Debugging 9. Encrypted images and password supplying 10. Contact information 1. Introduction ~~~~~~~~~~~~~~~ This is CDEmu daemon, the userspace daemon part of the userspace-cdemu suite, a free, GPL CD/DVD-ROM device emulator for linux. This document describes both the userspace-cdemu suit in general, and the specifics of CDEmu daemon, such as installation quirks, troubleshooting, and daemon's D-Bus interface. 2. Userspace-cdemu suite overview ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The whole userspace-cdemu suite is intended as a rewrite of cdemu kernel module and userspace utility that has been written by Robert Penz. But instead of providing only block device and linux uniform CD-ROM driver interface, CDEmu daemon tries to implement packet command set as specified by MMC-3 and INF-8090, thus fully emulating an optical storage device. Main features: - full SCSI device emulation: CDEmu daemon attempts to implement MMC-3 packet command set, therefore allowing virtual devices to be used not only as block devices, but as full SCSI devices. Aside from mounting the device, you can use dd on it, use it with CD-player, or even copy the loaded image using one of linux's CD-ROM burning utilities. - multiple image format support: userspace-cdemu is based libMirage, an image access library, which attempts to provide unified access to various CD-ROM image formats (including B6T, CCD, CDI, CUE, ISO, MDS, NRG and TOC) - linux HAL support: userspace-cdemu devices are properly detected by HAL, thus giving you the same benefits as with the real devices; most notable are automount and detection in WINE - debugging: both CDEmu daemon and underlying libMirage library have debugging code that supports changing verbosity of debug messages while daemon is running, making it easier to discover and fix problems. The whole userspace-cdemu suite consists of three major components: - kernel module - userspace daemon - userspace clients 2.1. Kernel module ~~~~~~~~~~~~~~~~~~ Kernel module takes care of device emulation in the kernel; it registers virtual device with appripriate drivers and creates corresponding device nodes. It also creates a special character device that is used for communication with userspace. As device is accessed, requests are generated by kernel, which are in fact SCSI commands. These are passed to userspace daemon via afore-mentioned character device. Once daemon processes the request, it returns appropriate data and status to kernel, thus completing the request. The whole process is very similar to accessing real device, except that requests are passed to userspace daemon instead to hardware. Early, experimental versions of userspace-cdemu used a module that was called cdemu-module. This release is based on vhba module, which was written by Chia-I Wu. Contrary to cdemu-module, which implemented all the interfaces (i.e. block device, uniform CD-ROM driver, etc.) manually, vhba implements virtual SCSI host and lets the kernel's SCSI layer do the rest. This approach is cleaner, faster and more robust. 2.2. Daemon ~~~~~~~~~~~ This is the part that these docs (should) belong to. The daemon receives SCSI commands from kernel module and processes them, passing the requested data back to the kernel. Daemon implements the actual virtual device; one instance per each device registered by kernel module. It uses libMirage, an image access library that is part of userspace-cdemu suite, for the image access (e.g. sector reading). Daemon is controlled through methods that are exposed via D-BUS. It is written in C and based on GLib (and thus GObjects), but being controlled over D-BUS, it allows for different clients written in different languages. 2.3. Clients ~~~~~~~~~~~~ Clients are used to control the daemon; examples of the tasks that can be achieved by using daemon's D-BUS interface are: loading and unloading a device, checking device(s) status, setting the debug mask, etc. A client can be written in any language, as long as it has D-BUS bindings; it can be either a CLI or a GUI application. For illustration, two clients are included as part of userspace-cdemu: - cdemu-client: a simple CLI client - gcdemu: a GNOME applet For more information about these particular clients, consult their documentation. Should you be interested in writing your own client, there is a section in this document that describes the daemon's interface, methods and signals. 3. Requirements ~~~~~~~~~~~~~~~ CDEmu daemon has the following software requirements: - GLib 2.6 or newer - D-BUS 0.60 or newer - libdaemon 0.10 or newer - libao 0.8.0 or newer - libsysfs - libMirage 1.2.0 or newer (part of the suite) - VHBA module (part of the suite) 4. Installation and set up ~~~~~~~~~~~~~~~~~~~~~~~~~~ The build and installation process is classical ./configure, make, make install. However, there are some quirks one should be aware of. Make sure you have installed all the required libraries; GLib, D-BUS, libao and libdaemon should be provided by most of the modern distributions and should as such be detected properly by configure script. libMirage, which is also part of userspace-cdemu suite, is also required. If you are building and installing it yourself, make sure that its .pc file is visible to pkg-config utility; if you are using /usr prefix, you should be fine, but in case /usr/local or something else is used and you haven't set up pkg-config to look there, you might need to force it to do so. For example, if libMirage was installed to /usr/local, configure would have to be run as "PKG_CONFIG_PATH=/usr/local/lib/pkg-config ./configure". Vhba module is not a build-time dependency, but it might be a good idea to have it installed at this point. The daemon can register its interface on either system or session D-BUS' bus. By default, system bus is used. To use session bus, use --bus=session when running daemon. If daemon is ran in daemon mode, usage of system bus is automatically implied. If you wish to run CDEmu daemon on system bus, CDEmu daemon's configuration files for D-BUS must be installed in appropriate directory. On most systems, this is /etc/dbus-1/system.d. However, due to the way autotools are used, /etc gets prefixed and therefore config file ends up installed into ${prefix}/etc/. To avoid this, you should pass --sysconfdir=/etc to configure, regardless of the prefix you are passing to configure. Alternatively, you can specify appropriate directory using --with-dbus-system-dir switch. We use a single libao backend to support CD-audio playback. This allows you to select from a number of available audio drivers. Valid choices are the driver names used by libao as well as "default" and "null". CDEmu is usually configured to use the "default" libao audio driver, which means that the audio driver specified in libao's config file ("/etc/libao.conf" or "~/.libao") is used. If "null" is specified, audio is sent to the null driver, essentially turning off audio playback. For a full list of valid driver names have a look at the libao documentation, in particular the "libao.conf" manpage. Also note that most media players on Linux are capable of digital audio extraction, meaning they can play CD-audio directly without relying on the "analog" playback capabilities of the virtual optical device. Because of this it's possible to use the libao "null" driver and still play CDs normally. Unlike previous (experimental snapshot) releases, this release of CDEmu daemon does not provide initscripts. After some thought it was decided it was too much hassle to write initscripts for different distributions, especially with alternatives to SysV init system becoming more and more popular. Packagers are welcome to add initscripts specific to distribution they are packaging for, of course. Bear in mind, though, that daemon started by initscripts should be ran in daemon mode (and therefore use system bus). 5. Troubleshooting (When bad things happen to good people) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Q: I built and installed the module, but I can't insert it ('modprobe vhba' results in something along the lines of 'FATAL: Module vhba not found.'). A: Try running 'depmod -a' after you have installed the module. Q: Daemon fails to start with the following message: 'cdemud: cdemud_daemon_initialize: failed to open control device /dev/vhba_ctl! Daemon initialization failed: Failed to open control device.' A: The message indicates that either vhba module is not inserted or you don't have read/write permissions for /dev/vhba_ctl. Please make sure that module is inserted, that /dev/vhba_ctl exists and that you have proper read/write permissions. Q: Daemon fails to start with the following message: 'cdemud: cdemud_daemon_initialize: failed to get name on system bus! Daemon initialization failed: Name request on D-BUS failed.' A: The message indicates that name registration on the system bus has failed. The most likely cause of this is improper permissions. Make sure that CDEmu daemon's D-BUS configuration file is in proper place and that you are running the daemon as root. Q: Daemon fails to start with the following message: cdemu0: cdemud_audio_initialize: failed to open audio device (driver: 'default')! A: Most likely you will need to specify a working audio driver in libao's config file (/etc/libao.conf or ~/.libao), or, if you are using initscripts that came with the package for your distribution, in the config file it provided. Also, please note that running system-wide (daemonized) instance of the daemon and pulseaudio output doesn't work if pulseaudio is run per-session. 6. CDEmu daemon D-BUS interface (a.k.a. writing your own client) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Communication between CDEmu daemon and a client is done via D-BUS. CDEmu daemon registers itself on either sytem or session bus, where it exposes the interface which can be used by client to control the daemon. 6.1. D-BUS name and object path ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The name CDEmu daemon requests on the system bus is "net.sf.cdemu.CDEMUD_Daemon", whereas the object path is "/CDEMUD_Daemon". The name of the interface is "net.sf.cdemu.CDEMUD_Daemon". To illustrate, a simple python program connecting to daemon registered on system bus would therefore look like this: import dbus if getattr(dbus, 'version', (0,0,0)) >= (0,41,0): import dbus.glib system_bus = dbus.SystemBus() dbus_proxy = system_bus.get_object('net.sf.cdemu.CDEMUD_Daemon', '/CDEMUD_Daemon') dbus_iface = dbus.Interface(dbus_proxy, 'net.sf.cdemu.CDEMUD_Daemon') 6.2. Methods ~~~~~~~~~~~~ For more information on D-BUS methods, argument direction and signatures or language-specific data type mappings, please consult the D-BUS documentation. CDEmu daemon's interface consists of the following methods that can be used to control the daemon: * GetDaemonVersion (version) + version: out; "s" Daemon version string. - Returns daemon version string. * GetLibraryVersion (version) + version: out; "s" Library version string - Returns library version string of libMirage library used by the daemon. * GetDaemonInterfaceVersion (version) + version: out; "i" Daemon interface version number - Returns daemon interface version number, which should be used to detect if client can use the interface or not. * EnumDaemonDebugMasks (type, masks) + masks: out; "a(si)" Array of structures containing supported debug masks. Each structure has two fields; debug mask name (string) and debug mask value (int). - Returns debug masks supported by the daemon. * EnumLibraryDebugMasks (type, masks) + masks: out; "a(si)" Array of structures containing supported debug masks. Each structure has two fields; debug mask name (string) and debug mask value (int). - Returns debug masks supported by the libMirage library that is used by the daemon. * EnumSupportedParsers (parsers) + parsers: out; "a(ssss)" Array of structures containing information about supported parsers. Each structure has multiple fields; parser ID (string), parser name (string), image type description (string) and image file MIME type (string). - Returns supported image parsers. * EnumSupportedFragments (fragments) + framgents: out; "a(ss)" Array of structures containing information about supported fragments. Each structure has two fields; fragment ID (string) and fragment name (string). - Returns supported fragments. * GetNumberOfDevices (number_of_devices) + number_of_devices: out; "i" Number of devices (int). - Returns number of virtual devices. * DeviceGetStatus (device_number, loaded, file_names) + device_number: in; "i" Device you are requesting status for (int). + loaded: out; "b" Boolean denoting whether device is loaded or not. + file_names: out; "as" Image's file name(s) (string). - Returns the status of specified device. * DeviceLoad (device_number, file_names, parameters) + device_number: in; "i" Device that is to be loaded (int). + file_names: in; "as" File name(s) of the image to be loaded (array of strings). + parameters: in; "a{sv}" Additional (optional) parameters, stored in a D-BUS dictionary type. If no parameters are needed, empty dictionary should be sent. Currently supported parameters: - "password":"password_string"; password for encrypted images - Attempts to load the image into specified device. - The client might wish to detect MIRAGE_E_NEEDPASSWORD error, which indicates that the image is encrypted and needs a password provided via parameters. * DeviceUnload (device_number) + device_number: in; "i" Device that is to be unloaded (int). - Attempts to unload the device. * DeviceGetOption (device_number, option_name, option_values) + device_number: in; "i" Device for which the specified option's value is to be retrieved (int). + option_name: in; "s" Name of the option (string). + option_values: out; "av" Option value(s) (array of variants). The actual content depends on the option. - This method retrieves the value(s) of specified option for specified device. For more information on supported options, see Section 7. * DeviceSetOption (device_number, option_name, option_values) + device_number: in; "i" Device for which the specified option's value is to be set (int). + option_name: in; "s" Name of the option (string). + option_values: in; "av" Option value(s) (array of variants). The actual content depends on the option. - This method sets the value(s) of specified option for specified device. For more information on supported options, see Section 7. 6.3. Signals ~~~~~~~~~~~~ In addition to the methods, CDEmu daemon's interface emits the following signals in response to the change of status of either the daemon or one of the devices: * DaemonStarted - emitted when daemon is started * DaemonStopped - emitted when daemon is stopped * DeviceStatusChange + device_number: "i" Device that emitted the signal (int). - emitted when device is loaded/unloaded * DeviceOptionChange + device_number: "i" Device that emitted the signal (int). + option: "s" Option that has been changed (string). - emitted when device's option is changed 7. Device options ~~~~~~~~~~~~~~~~~ CDEmu virtual devices have the following options that can be get/set via the DeviceGetOption/DeviceSetOption API. Please note that number of arguments and argument types for DeviceSetOption function are strictly checked; i.e. tbe method call will fail, for example, if argument for the 'dpm-emulation option' is of type G_TYPE_INT. * dpm-emulation + arguments: enabled (G_TYPE_BOOLEAN) - DPM emulation flag. Determines whether DPM emulation is performed. * tr-emulation + arguments: enabled (G_TYPE_BOOLEAN) - Transfer rate emulation flag. Determines whether transfer rate emulation is performed * device-id + arguments: vendor_id (G_TYPE_STRING), product_id (G_TYPE_STRING), revision (G_TYPE_STRING), vendor_specific (G_TYPE_STRING) - Device ID. Determines the device identifier (vendor identifier, product identifier, product revision and vendor-specific string) as returned by INQUIRY command. Changing the ID might be useful in cases when an application doesn't like the default ID for some reason. - Note that the length of argument strings should be as following: vendor_id 8 characters, product_id 16 characters, revision 4 characters and vendor_specific 20 characters. The actual arguments can surpass these lengths, but only specified amount of characters will actually be used by the device. * daemon-debug-mask + arguments: mask (G_TYPE_INT) - Daemon debug mask. Determines the amount of verbosity of daemon's code. * library-debug-mask + arguments: mask (G_TYPE_INT) - Library debug mask. Determines the amount of verbosity of libMirage library used by the daemon. 8. Debugging ~~~~~~~~~~~~ Both CDEmu daemon and the underlying libMirage contain debugging code that supports changing the verbosity of debug traces while the daemon is running and processing requests. The details of changing the debug mask vary from client to client, but in general it should be possible to change the debug mask of every device for either the daemon or the library. Supported masks can be obtained from the daemon for both components. The actual mask is combination of these masks and determines which traces get printed and which not. When daemon is run in non-daemon mode, it prints the traces into console. When run in daemon mode, system logger (i.e. syslogd) is used. Using appropriate debug mask and monitoring the output, the source of problem can be quickly found, be it either a failure in loading an image or incorrect response to the given command. If you are debugging the daemon using the GNU Debugger (gdb) and get an error reading "failed to open control device" then you need to check your permissions. GDB doesn't honor any set-UID or set-GID flags on the daemon executable so you will have to make sure that your user has read and write permissions on the control device. 9. Encrypted images and password supplying ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ As of version 1.2.0, libMirage offers basic support for encrypted images and as of version 1.2.0, CDEmu daemon supports that functionality as well. Encrypted images require password to decrypt the data. When image loading is performed in libMirage, the parser detects whether password is required, and if it is, it issues a callback to obtain it from the user. The problem is that CDEmu daemon and its clients use synchronous communication, which means that there is no way to propagate the password request from the callback back to the client, i.e. by the means of emitting signal from daemon (because technically, the image loading function is still in progress and the client is waiting for its return status). Therefore, if no password is provided via 'parameters' argument of DeviceLoad method and the image loading requires password, the method will fail and return error MIRAGE_E_NEEDPASSWORD. In this case, client might want to prompt the user for password and then call DeviceLoad again, this time with password set in 'parameters' argument. If password is incorrect, the method will fail, returning error MIRAGE_E_WRONGPASSWORD. Otherwise, the image should be loaded successfully (provided no other errors occured). Of course, nothing prevents the client to allow the user to enter password as an optional argument the first time image is loaded. DISCLAIMER: ~~~~~~~~~~~ the encrypted images support in CDEmu is not -meant- to be secure. In author's opinion the formats that provide encryption support offer no real benefit over other formats and should not be considered for making backups in the first place. However, every now and then one might come across such an image and in those cases the ability to simply load them might be useful. Therefore, the password is sent from clients to daemon in plain string form, with no real protection. Live with it, or don't use it. 10. Contact information ~~~~~~~~~~~~~~~~~~~~~~ CDEmu project's web page: http://cdemu.sourceforge.net CDEmu project's mailing list: cdemu-devel@lists.sourceforge.net Author can be directly contacted via e-mail address listed in AUTHORS file.