Index: xen-3.1-testing/tools/ioemu/block.c =================================================================== --- xen-3.1-testing.orig/tools/ioemu/block.c 2007-07-17 08:02:01.000000000 -0600 +++ xen-3.1-testing/tools/ioemu/block.c 2007-07-17 08:05:58.000000000 -0600 @@ -185,6 +185,13 @@ uint8_t *buf; size_t bufsize = 1024; + if ( strcmp(filename, "/dev/cdrom") == 0) { + drv = bdrv_find_format("raw"); + if (drv != NULL) { + return(drv); + } + } + fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); if (fd < 0) { buf = NULL; @@ -536,21 +543,11 @@ return bs->read_only; } -int bdrv_is_inserted(BlockDriverState *bs) -{ - return bs->inserted; -} - int bdrv_is_locked(BlockDriverState *bs) { return bs->locked; } -void bdrv_set_locked(BlockDriverState *bs, int locked) -{ - bs->locked = locked; -} - void bdrv_set_change_cb(BlockDriverState *bs, void (*change_cb)(void *opaque), void *opaque) { @@ -697,8 +694,10 @@ fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE); if (fd < 0) { fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE); - if (fd < 0) - return -1; + if (fd < 0 && strstart(filename, "/dev/cd", NULL)) + fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE | O_NONBLOCK ); + if (fd < 0) + return -1; bs->read_only = 1; } #ifdef _BSD @@ -769,8 +768,97 @@ BDRVRawState *s = bs->opaque; bs->total_sectors = 0; close(s->fd); + s->fd = -1; +} + +#include +#include +static int raw_is_inserted(BlockDriverState *bs) +{ + BDRVRawState *s = bs->opaque; + int ret; + + switch(bs->removable) { + case BDRV_TYPE_CDROM: + ret = ioctl(s->fd, CDROM_DRIVE_STATUS, CDSL_CURRENT); + if (ret == CDS_DISC_OK) { + return 1; + } + if (ret == -1) { // iso case + return 1; + } + else { + return 0; + } + break; + default: + return 1; + } +} + +static int raw_media_changed(BlockDriverState *bs) +{ + int ret = 0; + + switch(bs->removable) { + case BDRV_TYPE_CDROM: + { + if( bs->media_changed == 1 ) + { + ret = 1; + bs->media_changed = 0; + } + return ret; + } + default: + return -ENOTSUP; + } +} + + +static int raw_eject(BlockDriverState *bs, int eject_flag) +{ + char cmd[sizeof(bs->device_name) + 32]; + + switch(bs->removable) { + case BDRV_TYPE_CDROM: + if (eject_flag) { + sprintf(cmd, "eject %s", bs->filename); + if (system(cmd) == -1) { + perror("CDROMEJECT"); + } + } else { + sprintf(cmd, "eject -t %s", bs->filename); + if (system(cmd) == -1) { + perror("CDROMCLOSETRAY"); + } + } + break; + default: + return -ENOTSUP; + } + return 0; +} + +static int raw_set_locked(BlockDriverState *bs, int locked) +{ + BDRVRawState *s = bs->opaque; + + switch(bs->removable) { + case BDRV_TYPE_CDROM: + if (ioctl (s->fd, CDROM_LOCKDOOR, locked) < 0) { + /* Note: an error can happen if the distribution automatically + mounts the CD-ROM */ + // perror("CDROM_LOCKDOOR"); + } + break; + default: + return -ENOTSUP; + } + return 0; } + #ifdef _WIN32 #include #include @@ -850,6 +938,12 @@ raw_close, raw_create, raw_flush, + + /* removable device support */ + .bdrv_is_inserted = raw_is_inserted, + .bdrv_media_changed = raw_media_changed, + .bdrv_eject = raw_eject, + .bdrv_set_locked = raw_set_locked, }; void bdrv_init(void) @@ -866,3 +960,96 @@ bdrv_register(&bdrv_vpc); bdrv_register(&bdrv_vvfat); } + +/**************************************************************/ +/* removable device support */ + +/** + * Return TRUE if the media is present + */ +int bdrv_is_inserted(BlockDriverState *bs) +{ + BlockDriver *drv = bs->drv; + int ret; + if (!drv) + return 0; + if (!drv->bdrv_is_inserted) + return 1; + ret = drv->bdrv_is_inserted(bs); + return ret; +} + +/** + * Return TRUE if the media changed since the last call to this + * function. + */ +int bdrv_media_changed(BlockDriverState *bs) +{ + BlockDriver *drv = bs->drv; + int ret; + + if (!drv || !drv->bdrv_media_changed) + ret = -ENOTSUP; + else + ret = drv->bdrv_media_changed(bs); + if (ret == -ENOTSUP) + ret = bs->media_changed; + bs->media_changed = 0; + return ret; +} + + +/** + * If eject_flag is TRUE, eject the media. Otherwise, close the tray + */ +void bdrv_eject(BlockDriverState *bs, int eject_flag) +{ + + int ret = 0; + char cmd[sizeof(bs->device_name) + 32]; + BlockDriver *drv = bs->drv; + + switch(bs->removable) { + case BDRV_TYPE_CDROM: + if (eject_flag) { + sprintf(cmd, "eject %s", bs->filename); + if (system(cmd) == -1) { + perror("CDROMEJECT"); + ret = -ENOTSUP; + } + } else { + sprintf(cmd, "eject -t %s", bs->filename); + if (system(cmd) == -1) { + perror("CDROMCLOSETRAY"); + ret = -ENOTSUP; + } + } + break; + default: + if (!drv || !drv->bdrv_eject) { + ret = -ENOTSUP; + } else { + ret = drv->bdrv_eject(bs, eject_flag); + } + if (ret == -ENOTSUP) { + if (eject_flag) + bdrv_close(bs); + } + } + //return ret; +} + +/** + * Lock or unlock the media (if it is locked, the user won't be able + * to eject it manually). + */ +void bdrv_set_locked(BlockDriverState *bs, int locked) +{ + BlockDriver *drv = bs->drv; + + bs->locked = locked; + if (drv && drv->bdrv_set_locked) { + drv->bdrv_set_locked(bs, locked); + } +} + Index: xen-3.1-testing/tools/ioemu/block_int.h =================================================================== --- xen-3.1-testing.orig/tools/ioemu/block_int.h 2007-05-17 09:51:09.000000000 -0600 +++ xen-3.1-testing/tools/ioemu/block_int.h 2007-07-17 08:05:58.000000000 -0600 @@ -41,6 +41,13 @@ int nb_sectors, int *pnum); int (*bdrv_set_key)(BlockDriverState *bs, const char *key); int (*bdrv_make_empty)(BlockDriverState *bs); + + /* removable device specific */ + int (*bdrv_is_inserted)(BlockDriverState *bs); + int (*bdrv_media_changed)(BlockDriverState *bs); + int (*bdrv_eject)(BlockDriverState *bs, int eject_flag); + int (*bdrv_set_locked)(BlockDriverState *bs, int locked); + struct BlockDriver *next; }; @@ -65,6 +72,7 @@ char backing_file[1024]; /* if non zero, the image is a diff of this file image */ int is_temporary; + int media_changed; BlockDriverState *backing_hd; Index: xen-3.1-testing/tools/ioemu/hw/ide.c =================================================================== --- xen-3.1-testing.orig/tools/ioemu/hw/ide.c 2007-05-17 09:51:09.000000000 -0600 +++ xen-3.1-testing/tools/ioemu/hw/ide.c 2007-07-17 08:05:58.000000000 -0600 @@ -278,6 +278,7 @@ #define ASC_ILLEGAL_OPCODE 0x20 #define ASC_LOGICAL_BLOCK_OOR 0x21 #define ASC_INV_FIELD_IN_CMD_PACKET 0x24 +#define ASC_MEDIA_CHANGED 0x28 #define ASC_MEDIUM_NOT_PRESENT 0x3a #define ASC_SAVING_PARAMETERS_NOT_SUPPORTED 0x39 @@ -393,6 +394,7 @@ } PCIIDEState; #define DMA_MULTI_THREAD +#undef DMA_MULTI_THREAD #ifdef DMA_MULTI_THREAD @@ -1341,7 +1343,6 @@ } else { ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); - xenstore_check_new_media_present(1000); } break; case GPCMD_MODE_SENSE_10: @@ -1530,7 +1531,10 @@ if (eject && !start) { /* eject the disk */ - bdrv_close(s->bs); + bdrv_eject(s->bs, 1); + } else if (eject && start) { + /* close the tray */ + bdrv_eject(s->bs, 0); } ide_atapi_cmd_ok(s); } Index: xen-3.1-testing/tools/ioemu/xenstore.c =================================================================== --- xen-3.1-testing.orig/tools/ioemu/xenstore.c 2007-05-17 09:51:09.000000000 -0600 +++ xen-3.1-testing/tools/ioemu/xenstore.c 2007-07-17 08:05:58.000000000 -0600 @@ -82,7 +82,7 @@ char **e = NULL; char *buf = NULL, *path; char *fpath = NULL, *bpath = NULL, - *dev = NULL, *params = NULL, *type = NULL; + *dev = NULL, *params = NULL, *type = NULL, *media_present = NULL; int i, is_scsi; unsigned int len, num, hd_index; @@ -170,6 +170,11 @@ bdrv_set_type_hint(bs_table[hd_index], BDRV_TYPE_CDROM); if (pasprintf(&buf, "%s/params", bpath) != -1) xs_watch(xsh, buf, dev); + if (pasprintf(&buf, "%s/media-present", bpath) != -1) { + free(media_present); + media_present = xs_read(xsh, XBT_NULL, buf, &len); + xs_watch(xsh, buf, "media_present"); + } } /* open device now if media present */ if (params[0]) { @@ -313,7 +318,7 @@ void xenstore_process_event(void *opaque) { - char **vec, *image = NULL; + char **vec, *image = NULL, *media_present = NULL; unsigned int len, num, hd_index; vec = xs_read_watch(xsh, &num); @@ -325,6 +330,40 @@ goto out; } + if (!strcmp(vec[XS_WATCH_TOKEN], "media_present")) { + media_present = xs_read(xsh, XBT_NULL, vec[XS_WATCH_PATH], &len); + if (media_present) { + BlockDriverState *bs; + char *buf = NULL, *cp = NULL, *path = NULL, *dev = NULL; + + path = strdup(vec[XS_WATCH_PATH]); + cp = strstr(path, "media-present"); + if (cp){ + *(cp-1) = '\0'; + pasprintf(&buf, "%s/dev", path); + dev = xs_read(xsh, XBT_NULL, buf, &len); + if (dev) { + bs = bdrv_find(dev); + if (!bs) { + term_printf("device not found\n"); + goto out; + } + if (strcmp(media_present, "0") == 0 && bs) { + bdrv_close(bs); + } + else if (strcmp(media_present, "1") == 0 && bs != NULL && bs->drv == NULL) { + if (bdrv_open(bs, bs->filename, 0 /* snapshot */) < 0) { + fprintf(stderr, "qemu: could not open hard disk image '%s'\n", + bs->filename); + } + bs->media_changed = 1; + } + } + } + } + goto out; + } + if (strncmp(vec[XS_WATCH_TOKEN], "hd", 2) || strlen(vec[XS_WATCH_TOKEN]) != 3) goto out; Index: xen-3.1-testing/tools/python/xen/xend/server/HalDaemon.py =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ xen-3.1-testing/tools/python/xen/xend/server/HalDaemon.py 2007-07-17 08:05:58.000000000 -0600 @@ -0,0 +1,228 @@ +#!/usr/bin/env python +# -*- mode: python; -*- +#============================================================================ +# This library is free software; you can redistribute it and/or +# modify it under the terms of version 2.1 of the GNU Lesser General Public +# License as published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#============================================================================ +# Copyright (C) 2007 Pat Campbell +# Copyright (C) 2007 Novell Inc. +#============================================================================ + +"""hald (Hardware Abstraction Layer Daemon) watcher for Xen management + of removable block device media. + +""" + +import gobject +import dbus +import dbus.glib +import os +import types +import sys +import signal +import traceback +from xen.xend.xenstore.xstransact import xstransact, complete +from xen.xend.xenstore.xsutil import xshandle +from xen.xend import PrettyPrint +from xen.xend import XendLogging +from xen.xend.XendLogging import log + +class HalDaemon: + """The Hald block device watcher for XEN + """ + + """Default path to the log file. """ + logfile_default = "/var/log/xen/hald.log" + + """Default level of information to be logged.""" + loglevel_default = 'INFO' + + def __init__(self): + + XendLogging.init(self.logfile_default, self.loglevel_default) + log.debug( "%s", "__init__") + + self.udi_dict = {} + self.debug = 0 + self.dbpath = "/local/domain/0/backend/vbd" + self.bus = dbus.SystemBus() + self.hal_manager_obj = self.bus.get_object('org.freedesktop.Hal', '/org/freedesktop/Hal/Manager') + self.hal_manager = dbus.Interface( self.hal_manager_obj, 'org.freedesktop.Hal.Manager') + self.gatherBlockDevices() + self.registerDeviceCallbacks() + + def run(self): + log.debug( "%s", "In new run" ); + try: + self.mainloop = gobject.MainLoop() + self.mainloop.run() + except KeyboardInterrupt, ex: + log.debug('Keyboard exception handler: %s', ex ) + self.mainloop.quit() + except Exception, ex: + log.debug('Generic exception handler: %s', ex ) + self.mainloop.quit() + + def __del__(self): + log.debug( "%s", "In del " ); + self.unRegisterDeviceCallbacks() + self.mainloop.quit() + + def shutdown(self): + log.debug( "%s", "In shutdown now " ); + self.unRegisterDeviceCallbacks() + self.mainloop.quit() + + def stop(self): + log.debug( "%s", "In stop now " ); + self.unRegisterDeviceCallbacks() + self.mainloop.quit() + + def gatherBlockDevices(self): + + # Get all the current devices from hal and save in a dictionary + try: + device_names = self.hal_manager.GetAllDevices() + i = 0; + for name in device_names: + #log.debug("device name, device=%s",name) + dev_obj = self.bus.get_object ('org.freedesktop.Hal', name) + dev = dbus.Interface (dev_obj, 'org.freedesktop.Hal.Device') + dev_properties = dev_obj.GetAllProperties(dbus_interface="org.freedesktop.Hal.Device") + if dev_properties.has_key('block.device'): + dev_str = dev_properties['block.device'] + dev_major = dev_properties['block.major'] + dev_minor = dev_properties['block.minor'] + udi_info = {} + udi_info['device'] = dev_str + udi_info['major'] = dev_major + udi_info['minor'] = dev_minor + udi_info['udi'] = name + self.udi_dict[i] = udi_info + i = i + 1 + except Exception, ex: + print >>sys.stderr, 'Exception gathering block devices:', ex + log.warn("Exception gathering block devices (%s)",ex) + + # + def registerDeviceCallbacks(self): + # setup the callbacks for when the gdl changes + self.hal_manager.connect_to_signal('DeviceAdded', self.device_added_callback) + self.hal_manager.connect_to_signal('DeviceRemoved', self.device_removed_callback) + + # + def unRegisterDeviceCallbacks(self): + # setup the callbacks for when the gdl changes + self.hal_manager.remove_signal_receiver(self.device_added_callback,'DeviceAdded') + self.hal_manager.remove_signal_receiver(self.device_removed_callback,'DeviceRemoved') + + # + def device_removed_callback(self,udi): + log.debug('UDI %s was removed',udi) + self.show_dict(self.udi_dict) + for key in self.udi_dict: + udi_info = self.udi_dict[key] + if udi_info['udi'] == udi: + device = udi_info['device'] + major = udi_info['major'] + minor = udi_info['minor'] + self.change_xenstore( "remove", device, major, minor) + + # Adds device to dictionary if not already there + def device_added_callback(self,udi): + log.debug('UDI %s was added', udi) + self.show_dict(self.udi_dict) + dev_obj = self.bus.get_object ('org.freedesktop.Hal', udi) + dev = dbus.Interface (dev_obj, 'org.freedesktop.Hal.Device') + device = dev.GetProperty ('block.device') + major = dev.GetProperty ('block.major') + minor = dev.GetProperty ('block.minor') + udi_info = {} + udi_info['device'] = device + udi_info['major'] = major + udi_info['minor'] = minor + udi_info['udi'] = udi + already = 0 + cnt = 0; + for key in self.udi_dict: + info = self.udi_dict[key] + if info['udi'] == udi: + already = 1 + break + cnt = cnt + 1 + if already == 0: + self.udi_dict[cnt] = udi_info; + log.debug('UDI %s was added, device:%s major:%s minor:%s index:%d\n', udi, device, major, minor, cnt) + self.change_xenstore( "add", device, major, minor) + + # Debug helper, shows dictionary contents + def show_dict(self,dict=None): + if self.debug == 0 : + return + if dict == None : + dict = self.udi_dict + for key in dict: + log.debug('udi_info %s udi_info:%s',key,dict[key]) + + # Set or clear xenstore media-present depending on the action argument + # for every vbd that has this block device + def change_xenstore(self,action, device, major, minor): + domains = xstransact.List(self.dbpath) + log.debug('domains: %s', domains) + for domain in domains: # for each domain + devices = xstransact.List( self.dbpath + '/' + domain) + log.debug('devices: %s',devices) + for device in devices: # for each vbd device + str = device.split('/') + vbd_type = None; + vbd_physical_device = None + vbd_media = None + vbd_device_path = self.dbpath + '/' + domain + '/' + device + listing = xstransact.List(vbd_device_path) + for entry in listing: # for each entry + item = self.dbpath + '/' + entry + value = xstransact.Read( vbd_device_path + '/' + entry) + log.debug('%s=%s',item,value) + if item.find('media-present') != -1: + vbd_media = item; + vbd_media_path = item + if item.find('physical-device') != -1: + vbd_physical_device = value; + if item.find('type') != -1: + vbd_type = value; + if vbd_type is not None and vbd_physical_device is not None and vbd_media is not None : + inode = vbd_physical_device.split(':') + imajor = inode[0] + iminor = inode[1] + log.debug("action:%s major:%s- minor:%s- imajor:%s- iminor:%s- inode: %s", + action,major,minor, imajor, iminor, inode) + if int(imajor) == int(major) and int(iminor) == int(minor): + if action == "add": + xs_dict = {'media': "1"} + xstransact.Write(vbd_device_path, 'media-present', "1" ) + log.debug("wrote xenstore media-present 1 path:%s",vbd_media_path) + else: + xstransact.Write(vbd_device_path, 'media-present', "0" ) + log.debug("wrote xenstore media 0 path:%s",vbd_media_path) + +def mylog( fmt, *args): + f = open('/tmp/haldaemon.log', 'a') + print >>f, "HalDaemon ", fmt % args + f.close() + +if __name__ == "__main__": + watcher = HalDaemon() + watcher.run() + print 'Falling off end' + + Index: xen-3.1-testing/tools/python/xen/xend/server/Hald.py =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ xen-3.1-testing/tools/python/xen/xend/server/Hald.py 2007-07-17 08:05:58.000000000 -0600 @@ -0,0 +1,113 @@ +#============================================================================ +# This library is free software; you can redistribute it and/or +# modify it under the terms of version 2.1 of the GNU Lesser General Public +# License as published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +#============================================================================ +# Copyright (C) 2007 Pat Campbell +# Copyright (C) 2007 Novell Inc. +#============================================================================ + +import errno +import types +import os +import sys +import time +import signal +from traceback import print_exc + +from xen.xend.XendLogging import log + +class Hald: + def __init__(self): + self.ready = False + self.running = True + + def run(self): + """Starts the HalDaemon process + """ + self.ready = True + try: + myfile = self.find("xen/xend/server/HalDaemon.py") + args = (["python", myfile ]) + self.pid = self.daemonize("python", args ) + #log.debug( "%s %s pid:%d", "Hald.py starting ", args, self.pid ) + except: + self.pid = -1 + log.debug("Unable to start HalDaemon process") + + def shutdown(self): + """Shutdown the HalDaemon process + """ + log.debug("%s pid:%d", "Hald.shutdown()", self.pid) + self.running = False + self.ready = False + if self.pid != -1: + try: + os.kill(self.pid, signal.SIGINT) + except: + print_exc() + + def daemonize(self,prog, args): + """Runs a program as a daemon with the list of arguments. Returns the PID + of the daemonized program, or returns 0 on error. + Copied from xm/create.py instead of importing to reduce coupling + """ + r, w = os.pipe() + pid = os.fork() + + if pid == 0: + os.close(r) + w = os.fdopen(w, 'w') + os.setsid() + try: + pid2 = os.fork() + except: + pid2 = None + if pid2 == 0: + os.chdir("/") + for fd in range(0, 256): + try: + os.close(fd) + except: + pass + os.open("/dev/null", os.O_RDWR) + os.dup2(0, 1) + os.dup2(0, 2) + os.execvp(prog, args) + os._exit(1) + else: + w.write(str(pid2 or 0)) + w.close() + os._exit(0) + os.close(w) + r = os.fdopen(r) + daemon_pid = int(r.read()) + r.close() + os.waitpid(pid, 0) + #log.debug( "daemon_pid: %d", daemon_pid ) + return daemon_pid + + def find(self,path, matchFunc=os.path.isfile): + """Find a module in the sys.path + From web page: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52224 + """ + for dirname in sys.path: + candidate = os.path.join(dirname, path) + if matchFunc(candidate): + return candidate + raise Error("Can't find file %s" % path) + +if __name__ == "__main__": + watcher = Hald() + watcher.run() + time.sleep(10) + watcher.shutdown() Index: xen-3.1-testing/tools/python/xen/xend/server/SrvServer.py =================================================================== --- xen-3.1-testing.orig/tools/python/xen/xend/server/SrvServer.py 2007-05-17 09:51:10.000000000 -0600 +++ xen-3.1-testing/tools/python/xen/xend/server/SrvServer.py 2007-07-17 08:05:58.000000000 -0600 @@ -57,6 +57,7 @@ from SrvRoot import SrvRoot from XMLRPCServer import XMLRPCServer +from xen.xend.server.Hald import Hald xoptions = XendOptions.instance() @@ -248,6 +249,8 @@ if xoptions.get_xend_unix_xmlrpc_server(): servers.add(XMLRPCServer(XendAPI.AUTH_PAM, False)) + servers.add(Hald()) + def create(): root = SrvDir()