ia64/xen-unstable

changeset 1541:4206a81e8dca

bitkeeper revision 1.999 (40d83983YNm1foUR4ODZt9AAVdci-Q)

Switch to new method of shutting down domains.
author mjw@wray-m-3.hpl.hp.com
date Tue Jun 22 13:52:03 2004 +0000 (2004-06-22)
parents 2e43f83e8d44
children 7d2b7e6dad4c 894c33426ae1
files .rootkeys tools/xenmgr/lib/XendDomain.py tools/xenmgr/lib/XendDomainInfo.py tools/xenmgr/lib/server/SrvConsoleServer.py tools/xenmgr/lib/server/SrvDomain.py tools/xenmgr/lib/server/channel.py tools/xenmgr/lib/server/controller.py tools/xenmgr/lib/server/domain.py tools/xenmgr/lib/server/messages.py tools/xenmgr/lib/xm/create.py tools/xenmgr/lib/xm/shutdown.py
line diff
     1.1 --- a/.rootkeys	Tue Jun 22 11:42:20 2004 +0000
     1.2 +++ b/.rootkeys	Tue Jun 22 13:52:03 2004 +0000
     1.3 @@ -262,6 +262,7 @@ 40c9c469N2-b3GqpLHHHPZykJPLVvA tools/xen
     1.4  40c9c469hJ_IlatRne-9QEa0-wlquw tools/xenmgr/lib/server/console.py
     1.5  40c9c469UcNJh_NuLU0ytorM0Lk5Ow tools/xenmgr/lib/server/controller.py
     1.6  40c9c469vHh-qLiiubdbKEQbJf18Zw tools/xenmgr/lib/server/cstruct.py
     1.7 +40d83983OXjt-y3HjSCcuoPp9rzvmw tools/xenmgr/lib/server/domain.py
     1.8  40c9c469yrm31i60pGKslTi2Zgpotg tools/xenmgr/lib/server/messages.py
     1.9  40c9c46925x-Rjb0Cv2f1-l2jZrPYg tools/xenmgr/lib/server/netif.py
    1.10  40c9c469ZqILEQ8x6yWy0_51jopiCg tools/xenmgr/lib/server/params.py
     2.1 --- a/tools/xenmgr/lib/XendDomain.py	Tue Jun 22 11:42:20 2004 +0000
     2.2 +++ b/tools/xenmgr/lib/XendDomain.py	Tue Jun 22 13:52:03 2004 +0000
     2.3 @@ -203,21 +203,22 @@ class XendDomain:
     2.4          """Pause domain execution.
     2.5          """
     2.6          dom = int(id)
     2.7 +        eserver.inject('xend.domain.pause', id)
     2.8          return xc.domain_pause(dom=dom)
     2.9      
    2.10 -    def domain_shutdown(self, id):
    2.11 +    def domain_shutdown(self, id, reason='poweroff'):
    2.12          """Shutdown domain (nicely).
    2.13          """
    2.14          dom = int(id)
    2.15          if dom <= 0:
    2.16              return 0
    2.17 -        eserver.inject('xend.domain.shutdown', id)
    2.18 -        val = xc.domain_destroy(dom=dom) # FIXME -- send CMSG_SHUTDOWN
    2.19 +        eserver.inject('xend.domain.shutdown', [id, reason])
    2.20 +        val = xend.domain_shutdown(dom, reason)
    2.21          self.refresh()
    2.22          return val
    2.23      
    2.24      def domain_halt(self, id):
    2.25 -        """Shutdown domain immediately.
    2.26 +        """Terminate domain immediately.
    2.27          """
    2.28          dom = int(id)
    2.29          if dom <= 0:
     3.1 --- a/tools/xenmgr/lib/XendDomainInfo.py	Tue Jun 22 11:42:20 2004 +0000
     3.2 +++ b/tools/xenmgr/lib/XendDomainInfo.py	Tue Jun 22 13:52:03 2004 +0000
     3.3 @@ -122,8 +122,12 @@ class XendDomainInfo:
     3.4              susp  = (self.info['shutdown'] and 's') or '-'
     3.5              crash = (self.info['crashed'] and 'c') or '-'
     3.6              state = run + block + stop + susp + crash
     3.7 +            sxpr.append(['state', state])
     3.8 +            if self.info['shutdown']:
     3.9 +                reasons = ["poweroff", "reboot", "suspend"]
    3.10 +                reason = reasons[info['shutdown_reason']]
    3.11 +                sxpr.append(['shutdown_reason', reason])
    3.12              sxpr.append(['cpu', self.info['cpu']])
    3.13 -            sxpr.append(['state', state])
    3.14              sxpr.append(['cpu_time', self.info['cpu_time']/1e9])
    3.15          if self.console:
    3.16              sxpr.append(self.console.sxpr())
     4.1 --- a/tools/xenmgr/lib/server/SrvConsoleServer.py	Tue Jun 22 11:42:20 2004 +0000
     4.2 +++ b/tools/xenmgr/lib/server/SrvConsoleServer.py	Tue Jun 22 13:52:03 2004 +0000
     4.3 @@ -36,6 +36,7 @@ import channel
     4.4  import blkif
     4.5  import netif
     4.6  import console
     4.7 +import domain
     4.8  from params import *
     4.9  
    4.10  DEBUG = 1
    4.11 @@ -408,6 +409,16 @@ class EventFactory(protocol.Factory):
    4.12          proto.factory = self
    4.13          return proto
    4.14  
    4.15 +class VirqClient:
    4.16 +    def __init__(self, daemon):
    4.17 +        self.daemon = daemon
    4.18 +
    4.19 +    def virqReceived(self, virq):
    4.20 +        print 'VirqClient.virqReceived>', virq
    4.21 +
    4.22 +    def lostChannel(self, channel):
    4.23 +        print 'VirqClient.lostChannel>', channel
    4.24 +        
    4.25  class Daemon:
    4.26      """The xend daemon.
    4.27      """
    4.28 @@ -537,11 +548,13 @@ class Daemon:
    4.29          self.listenMgmt()
    4.30          self.listenEvent()
    4.31          self.listenNotifier()
    4.32 +        self.listenVirq()
    4.33          SrvServer.create()
    4.34          reactor.run()
    4.35  
    4.36      def createFactories(self):
    4.37          self.channelF = channel.channelFactory()
    4.38 +        self.domainCF = domain.DomainControllerFactory()
    4.39          self.blkifCF = blkif.BlkifControllerFactory()
    4.40          self.netifCF = netif.NetifControllerFactory()
    4.41          self.consoleCF = console.ConsoleControllerFactory()
    4.42 @@ -563,6 +576,10 @@ class Daemon:
    4.43          p.startListening()
    4.44          return p
    4.45  
    4.46 +    def listenVirq(self):
    4.47 +        virqChan = self.channelF.virqChannel(channel.VIRQ_DOM_EXC)
    4.48 +        virqChan.registerClient(VirqClient(self))
    4.49 +
    4.50      def exit(self):
    4.51          reactor.diconnectAll()
    4.52          sys.exit(0)
    4.53 @@ -650,28 +667,15 @@ class Daemon:
    4.54          if console.conn:
    4.55              console.conn.loseConnection()
    4.56  
    4.57 -    def domain_start(self, id):
    4.58 -        """Start domain running.
    4.59 -        """
    4.60 -        dom = int(id)
    4.61 -        if dom <= 0: return 0
    4.62 -        return xc.domain_start(dom=dom)
    4.63 -        
    4.64 -    def domain_stop(self, id):
    4.65 -        """Stop domain running.
    4.66 +    def domain_shutdown(self, dom, reason):
    4.67 +        """Shutdown a domain.
    4.68          """
    4.69 -        dom = int(id)
    4.70 -        if dom <= 0: return 0 
    4.71 -        xc.domain_stop(dom=dom)
    4.72 -
    4.73 -    def domain_destroy(self, id, force=0):
    4.74 -        """Destroy a domain. Shutdown if force=0, terminate immediately if force=1.
    4.75 -        """
    4.76 -        dom = int(id)
    4.77 -        if dom <= 0: return 0 
    4.78 -        return xc.domain_destroy(dom=dom, force=force)
    4.79 -    
    4.80 -
    4.81 +        ctrl = self.domainCF.getInstanceByDom(dom)
    4.82 +        if not ctrl:
    4.83 +            raise ValueError('No domain controller: %d' % dom)
    4.84 +        ctrl.shutdown(reason)
    4.85 +        return 0
    4.86 +        
    4.87  def instance():
    4.88      global inst
    4.89      try:
     5.1 --- a/tools/xenmgr/lib/server/SrvDomain.py	Tue Jun 22 11:42:20 2004 +0000
     5.2 +++ b/tools/xenmgr/lib/server/SrvDomain.py	Tue Jun 22 13:52:03 2004 +0000
     5.3 @@ -193,8 +193,8 @@ class SrvDomain(SrvDir):
     5.4  
     5.5      def form(self, req):
     5.6          req.write('<form method="post" action="%s">' % req.prePathURL())
     5.7 -        req.write('<input type="submit" name="op" value="start">')
     5.8 -        req.write('<input type="submit" name="op" value="stop">')
     5.9 +        req.write('<input type="submit" name="op" value="unpause">')
    5.10 +        req.write('<input type="submit" name="op" value="pause">')
    5.11          req.write('<input type="submit" name="op" value="shutdown">')
    5.12          req.write('<input type="submit" name="op" value="halt">')
    5.13          req.write('<br><input type="submit" name="op" value="migrate">')
     6.1 --- a/tools/xenmgr/lib/server/channel.py	Tue Jun 22 11:42:20 2004 +0000
     6.2 +++ b/tools/xenmgr/lib/server/channel.py	Tue Jun 22 13:52:03 2004 +0000
     6.3 @@ -2,6 +2,12 @@ import Xc; xc = Xc.new()
     6.4  import xend.utils
     6.5  from messages import msgTypeName
     6.6  
     6.7 +VIRQ_MISDIRECT  = 0  # Catch-all interrupt for unbound VIRQs.
     6.8 +VIRQ_TIMER      = 1  # Timebase update, and/or requested timeout.
     6.9 +VIRQ_DEBUG      = 2  # Request guest to dump debug info.
    6.10 +VIRQ_CONSOLE    = 3  # (DOM0) bytes received on emergency console.
    6.11 +VIRQ_DOM_EXC    = 4  # (DOM0) Exceptional event for some domain.
    6.12 +
    6.13  def eventChannel(dom1, dom2):
    6.14      return xc.evtchn_bind_interdomain(dom1=dom1, dom2=dom2)
    6.15  
    6.16 @@ -143,7 +149,7 @@ class VirqChannel(BaseChannel):
    6.17          self.virq = virq
    6.18          # Notification port (int).
    6.19          self.port = xc.evtchn_bind_virq(virq)
    6.20 -        self.idx = port
    6.21 +        self.idx = self.port
    6.22          # Clients to call when a virq arrives.
    6.23          self.clients = []
    6.24  
     7.1 --- a/tools/xenmgr/lib/server/controller.py	Tue Jun 22 11:42:20 2004 +0000
     7.2 +++ b/tools/xenmgr/lib/server/controller.py	Tue Jun 22 13:52:03 2004 +0000
     7.3 @@ -36,12 +36,14 @@ class CtrlMsgRcvr:
     7.4          pass
     7.5      
     7.6      def registerChannel(self):
     7.7 +        print 'CtrlMsgRcvr>registerChannel>', self
     7.8          self.channel = self.channelFactory.domChannel(self.dom)
     7.9          self.idx = self.channel.getIndex()
    7.10          if self.majorTypes:
    7.11              self.channel.registerDevice(self.majorTypes, self)
    7.12          
    7.13      def deregisterChannel(self):
    7.14 +        print 'CtrlMsgRcvr>deregisterChannel>', self
    7.15          if self.channel:
    7.16              self.channel.deregisterDevice(self)
    7.17              del self.channel
    7.18 @@ -71,6 +73,8 @@ class ControllerFactory(CtrlMsgRcvr):
    7.19          self.instances = {}
    7.20          self.dlist = []
    7.21          self.dom = 0
    7.22 +        # Timeout (in seconds) for deferreds.
    7.23 +        self.timeout = 10
    7.24          
    7.25      def addInstance(self, instance):
    7.26          self.instances[instance.idx] = instance
    7.27 @@ -99,6 +103,9 @@ class ControllerFactory(CtrlMsgRcvr):
    7.28  
    7.29      def addDeferred(self):
    7.30          d = defer.Deferred()
    7.31 +        if self.timeout > 0:
    7.32 +            # The deferred will error if not called before timeout.
    7.33 +            d.setTimeout(self.timeout)
    7.34          self.dlist.append(d)
    7.35          return d
    7.36  
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/tools/xenmgr/lib/server/domain.py	Tue Jun 22 13:52:03 2004 +0000
     8.3 @@ -0,0 +1,41 @@
     8.4 +import channel
     8.5 +import controller
     8.6 +from messages import *
     8.7 +
     8.8 +class DomainControllerFactory(controller.ControllerFactory):
     8.9 +    """Factory for creating domain controllers.
    8.10 +    """
    8.11 +
    8.12 +    def createInstance(self, dom):
    8.13 +        d = DomainController(self, dom)
    8.14 +        self.addInstance(d)
    8.15 +        return d
    8.16 +    
    8.17 +    def getInstanceByDom(self, dom):
    8.18 +        for inst in self.instances.values():
    8.19 +            if inst.dom == dom:
    8.20 +                return inst
    8.21 +        inst = self.createInstance(dom)
    8.22 +        return inst
    8.23 +
    8.24 +
    8.25 +class DomainController(controller.Controller):
    8.26 +    """Generic controller for a domain.
    8.27 +    """
    8.28 +
    8.29 +    reasons = {'poweroff' : 'shutdown_poweroff_t',
    8.30 +               'reboot'   : 'shutdown_reboot_t',
    8.31 +               'suspend'  : 'shutdown_suspend_t' }
    8.32 +
    8.33 +    def __init__(self, factory, dom):
    8.34 +        controller.Controller.__init__(self, factory, dom)
    8.35 +        self.majorTypes = [ CMSG_SHUTDOWN ]
    8.36 +        self.registerChannel()
    8.37 +        print 'DomainController>', self, self.channel, self.idx
    8.38 +
    8.39 +    def shutdown(self, reason):
    8.40 +        msgtype = self.reasons.get(reason)
    8.41 +        if not msgtype:
    8.42 +            raise ValueError('invalid reason:' + reason)
    8.43 +        msg = packMsg(msgtype, {})
    8.44 +        self.writeRequest(msg)
     9.1 --- a/tools/xenmgr/lib/server/messages.py	Tue Jun 22 11:42:20 2004 +0000
     9.2 +++ b/tools/xenmgr/lib/server/messages.py	Tue Jun 22 13:52:03 2004 +0000
     9.3 @@ -16,7 +16,7 @@ msg_formats = {}
     9.4  
     9.5  CMSG_CONSOLE  = 0
     9.6  
     9.7 -console_formats = { 'console_data': (CMSG_CONSOLE, 0, "?") }
     9.8 +console_formats = { 'console_data': (CMSG_CONSOLE, 0) }
     9.9  
    9.10  msg_formats.update(console_formats)
    9.11  
    9.12 @@ -62,28 +62,28 @@ BLKIF_BE_STATUS_MAPPING_ERROR       = 9
    9.13  
    9.14  blkif_formats = {
    9.15      'blkif_be_connect_t':
    9.16 -    (CMSG_BLKIF_BE, CMSG_BLKIF_BE_CONNECT, "QIILI"),
    9.17 +    (CMSG_BLKIF_BE, CMSG_BLKIF_BE_CONNECT),
    9.18  
    9.19      'blkif_be_create_t':
    9.20 -    (CMSG_BLKIF_BE, CMSG_BLKIF_BE_CREATE, "QII"),
    9.21 +    (CMSG_BLKIF_BE, CMSG_BLKIF_BE_CREATE),
    9.22  
    9.23      'blkif_be_destroy_t':
    9.24 -    (CMSG_BLKIF_BE, CMSG_BLKIF_BE_DESTROY, "QII"),
    9.25 +    (CMSG_BLKIF_BE, CMSG_BLKIF_BE_DESTROY),
    9.26  
    9.27      'blkif_be_vbd_create_t':
    9.28 -    (CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_CREATE, "QIHII"),
    9.29 +    (CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_CREATE),
    9.30  
    9.31      'blkif_be_vbd_grow_t':
    9.32 -    (CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_GROW , "QIHHHQQI"),
    9.33 +    (CMSG_BLKIF_BE, CMSG_BLKIF_BE_VBD_GROW),
    9.34  
    9.35      'blkif_fe_interface_status_changed_t':
    9.36 -    (CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED, "III"),
    9.37 +    (CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_STATUS_CHANGED),
    9.38  
    9.39      'blkif_fe_driver_status_changed_t':
    9.40 -    (CMSG_BLKIF_FE, CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED, "?"),
    9.41 +    (CMSG_BLKIF_FE, CMSG_BLKIF_FE_DRIVER_STATUS_CHANGED),
    9.42  
    9.43      'blkif_fe_interface_connect_t':
    9.44 -    (CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_CONNECT, "IL"),
    9.45 +    (CMSG_BLKIF_FE, CMSG_BLKIF_FE_INTERFACE_CONNECT),
    9.46  }
    9.47  
    9.48  msg_formats.update(blkif_formats)
    9.49 @@ -115,59 +115,55 @@ NETIF_DRIVER_STATUS_UP     = 1
    9.50  
    9.51  netif_formats = {
    9.52      'netif_be_connect_t':
    9.53 -    (CMSG_NETIF_BE, CMSG_NETIF_BE_CONNECT, "QIILLI"),
    9.54 +    (CMSG_NETIF_BE, CMSG_NETIF_BE_CONNECT),
    9.55  
    9.56      'netif_be_create_t':
    9.57 -    (CMSG_NETIF_BE, CMSG_NETIF_BE_CREATE, "QIBBBBBBBBI"),
    9.58 +    (CMSG_NETIF_BE, CMSG_NETIF_BE_CREATE),
    9.59  
    9.60      'netif_be_destroy_t':
    9.61 -    (CMSG_NETIF_BE, CMSG_NETIF_BE_DESTROY, "QII"),
    9.62 +    (CMSG_NETIF_BE, CMSG_NETIF_BE_DESTROY),
    9.63  
    9.64      'netif_be_disconnect_t':
    9.65 -    (CMSG_NETIF_BE, CMSG_NETIF_BE_DISCONNECT, "QII"),
    9.66 +    (CMSG_NETIF_BE, CMSG_NETIF_BE_DISCONNECT),
    9.67  
    9.68      'netif_be_driver_status_changed_t':
    9.69 -    (CMSG_NETIF_BE, CMSG_NETIF_BE_DRIVER_STATUS_CHANGED, "QII"),
    9.70 +    (CMSG_NETIF_BE, CMSG_NETIF_BE_DRIVER_STATUS_CHANGED),
    9.71  
    9.72      'netif_fe_driver_status_changed_t':
    9.73 -    (CMSG_NETIF_FE, CMSG_NETIF_FE_DRIVER_STATUS_CHANGED, "II"),
    9.74 +    (CMSG_NETIF_FE, CMSG_NETIF_FE_DRIVER_STATUS_CHANGED),
    9.75  
    9.76      'netif_fe_interface_connect_t':
    9.77 -    (CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_CONNECT, "ILL"),
    9.78 +    (CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_CONNECT),
    9.79  
    9.80      'netif_fe_interface_status_changed_t':
    9.81 -    (CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED, "IIIBBBBBBBB"),
    9.82 +    (CMSG_NETIF_FE, CMSG_NETIF_FE_INTERFACE_STATUS_CHANGED),
    9.83      }
    9.84  
    9.85  msg_formats.update(netif_formats)
    9.86  
    9.87  #============================================================================
    9.88 -CMSG_SUSPEND  = 5
    9.89  CMSG_SHUTDOWN = 6
    9.90  
    9.91 -CMSG_SHUTDOWN_HALT      = 0
    9.92 -CMSG_SHUTDOWN_POWEROFF  = 1
    9.93 -CMSG_SHUTDOWN_REBOOT    = 2
    9.94 +CMSG_SHUTDOWN_POWEROFF  = 0
    9.95 +CMSG_SHUTDOWN_REBOOT    = 1
    9.96 +CMSG_SHUTDOWN_SUSPEND   = 2
    9.97  
    9.98  STOPCODE_shutdown       = 0
    9.99  STOPCODE_reboot         = 1
   9.100  STOPCODE_suspend        = 2
   9.101  
   9.102 -ctrlif_formats = {
   9.103 -    'ctrlif_suspend_t':
   9.104 -    (CMSG_SUSPEND, 0, "??"),
   9.105 +shutdown_formats = {
   9.106 +    'shutdown_poweroff_t':
   9.107 +    (CMSG_SHUTDOWN, CMSG_SHUTDOWN_POWEROFF),
   9.108 +    
   9.109 +    'shutdown_reboot_t':
   9.110 +    (CMSG_SHUTDOWN, CMSG_SHUTDOWN_REBOOT),
   9.111  
   9.112 -    'ctrlif_shutdown_halt_t':
   9.113 -    (CMSG_SHUTDOWN, CMSG_SHUTDOWN_HALT, "??"),
   9.114 -    
   9.115 -    'ctrlif_shutdown_poweroff_t':
   9.116 -    (CMSG_SHUTDOWN, CMSG_SHUTDOWN_POWEROFF, "??"),
   9.117 -    
   9.118 -    'ctrlif_shutdown_reboot_t':
   9.119 -    (CMSG_SHUTDOWN, CMSG_SHUTDOWN_REBOOT, "??"),
   9.120 +    'shutdown_suspend_t':
   9.121 +    (CMSG_SHUTDOWN, CMSG_SHUTDOWN_SUSPEND),
   9.122      }
   9.123  
   9.124 -msg_formats.update(ctrlif_formats)
   9.125 +msg_formats.update(shutdown_formats)
   9.126  
   9.127  #============================================================================
   9.128  
   9.129 @@ -176,7 +172,7 @@ class Msg:
   9.130  
   9.131  def packMsg(ty, params):
   9.132      if DEBUG: print '>packMsg', ty, params
   9.133 -    (major, minor, packing) = msg_formats[ty]
   9.134 +    (major, minor) = msg_formats[ty]
   9.135      args = {}
   9.136      for (k, v) in params.items():
   9.137          if k == 'mac':
    10.1 --- a/tools/xenmgr/lib/xm/create.py	Tue Jun 22 11:42:20 2004 +0000
    10.2 +++ b/tools/xenmgr/lib/xm/create.py	Tue Jun 22 13:52:03 2004 +0000
    10.3 @@ -235,7 +235,7 @@ def preprocess_ip(opts):
    10.4      setip = (opts.hostname or opts.netmask
    10.5               or opts.gateway or opts.dhcp or opts.interface)
    10.6      if not setip: return
    10.7 -    if not opts
    10.8 +    #if not opts
    10.9      ip = (opts.ip
   10.10            + ':'
   10.11            + ':' + opts.gateway
    11.1 --- a/tools/xenmgr/lib/xm/shutdown.py	Tue Jun 22 11:42:20 2004 +0000
    11.2 +++ b/tools/xenmgr/lib/xm/shutdown.py	Tue Jun 22 13:52:03 2004 +0000
    11.3 @@ -10,7 +10,7 @@ gopts = Opts(use="""[options] [DOM]
    11.4  Shutdown one or more domains gracefully.""")
    11.5  
    11.6  gopts.opt('help', short='h',
    11.7 -         fn=set_value, default=0,
    11.8 +         fn=set_true, default=0,
    11.9           use="Print this help.")
   11.10  
   11.11  gopts.opt('all', short='a',
   11.12 @@ -46,8 +46,8 @@ def main_all(opts, args):
   11.13      shutdown(opts, None, opts.wait)
   11.14  
   11.15  def main_dom(opts, args):
   11.16 -    if len(args) < 2: opts.err('Missing domain')
   11.17 -    dom = argv[1]
   11.18 +    if len(args) < 1: opts.err('Missing domain')
   11.19 +    dom = args[0]
   11.20      try:
   11.21          domid = int(dom)
   11.22      except:
   11.23 @@ -59,6 +59,8 @@ def main(argv):
   11.24      args = opts.parse(argv)
   11.25      if opts.help:
   11.26          opts.usage()
   11.27 +        return
   11.28 +    print 'shutdown.main>', len(args), args
   11.29      if opts.all:
   11.30          main_all(opts, args)
   11.31      else: