ia64/xen-unstable

view tools/python/xen/xm/main.py @ 6735:5c49ed1145cc

Fix xm info handling of empty strings (fix bugzilla bug #216)

Signed-off-by: Steven Hand <steven@xensource.com>
author shand@ubuntu.eng.hq.xensource.com
date Fri Sep 09 15:11:18 2005 -0800 (2005-09-09)
parents dd668f7527cb
children b35215021b32 5cbb2ecce16a
line source
1 # (C) Copyright IBM Corp. 2005
2 # Copyright (C) 2004 Mike Wray
3 #
4 # Authors:
5 # Sean Dague <sean at dague dot net>
6 # Mike Wray <mike dot wray at hp dot com>
7 #
8 # This library is free software; you can redistribute it and/or
9 # modify it under the terms of version 2.1 of the GNU Lesser General Public
10 # License as published by the Free Software Foundation.
11 #
12 # This library is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 # Lesser General Public License for more details.
16 #
17 # You should have received a copy of the GNU Lesser General Public
18 # License along with this library; if not, write to the Free Software
19 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 """Grand unified management application for Xen.
22 """
23 import os
24 import os.path
25 import sys
26 import commands
27 import re
28 from getopt import getopt
29 import socket
30 import warnings
31 warnings.filterwarnings('ignore', category=FutureWarning)
32 from xen.xend import PrettyPrint
33 from xen.xend import sxp
34 from xen.xm.opts import *
35 shorthelp = """Usage: xm <subcommand> [args]
36 Control, list, and manipulate Xen guest instances
38 xm common subcommands:
39 console <DomId> attach to console of DomId
40 create <CfgFile> create a domain based on Config File
41 destroy <DomId> terminate a domain immediately
42 help display this message
43 list [DomId, ...] list information about domains
44 mem-max <DomId> <Mem> set the maximum memory reservation for a domain
45 mem-set <DomId> <Mem> adjust the current memory usage for a domain
46 migrate <DomId> <Host> migrate a domain to another machine
47 pause <DomId> pause execution of a domain
48 reboot <DomId> reboot a domain
49 restore <File> create a domain from a saved state file
50 save <DomId> <File> save domain state (and config) to file
51 shutdown <DomId> shutdown a domain
52 top monitor system and domains in real-time
53 unpause <DomId> unpause a paused domain
55 For a complete list of subcommands run 'xm help --long'
56 For more help on xm see the xm(1) man page
57 For more help on xm create, see the xmdomain.cfg(5) man page"""
59 longhelp = """Usage: xm <subcommand> [args]
60 Control, list, and manipulate Xen guest instances
62 xm full list of subcommands:
64 Domain Commands:
65 console <DomId> attach to console of DomId
66 cpus-list <DomId> <VCpu> get the list of cpus for a VCPU
67 cpus-set <DomId> <VCpu> <CPUS> set which cpus a VCPU can use.
68 create <ConfigFile> create a domain
69 destroy <DomId> terminate a domain immediately
70 domid <DomName> convert a domain name to a domain id
71 domname <DomId> convert a domain id to a domain name
72 list list information about domains
73 mem-max <DomId> <Mem> set domain maximum memory limit
74 mem-set <DomId> <Mem> set the domain's memory dynamically
75 migrate <DomId> <Host> migrate a domain to another machine
76 pause <DomId> pause execution of a domain
77 reboot [-w|-a] <DomId> reboot a domain
78 restore <File> create a domain from a saved state file
79 save <DomId> <File> save domain state (and config) to file
80 shutdown [-w|-a] <DomId> shutdown a domain
81 sysrq <DomId> <letter> send a sysrq to a domain
82 unpause <DomId> unpause a paused domain
83 vcpu-enable <DomId> <VCPU> disable VCPU in a domain
84 vcpu-disable <DomId> <VCPU> enable VCPU in a domain
85 vcpu-list <DomId> get the list of VCPUs for a domain
87 Xen Host Commands:
88 dmesg [--clear] read or clear Xen's message buffer
89 info get information about the xen host
90 log print the xend log
91 top monitor system and domains in real-time
93 Scheduler Commands:
94 bvt <options> set BVT scheduler parameters
95 bvt_ctxallow <Allow> set the BVT scheduler context switch allowance
96 sedf <options> set simple EDF parameters
98 Virtual Device Commands:
99 block-create <DomId> <BackDev> <FrontDev> <Mode> [BackDomId]
100 Create a new virtual block device
101 block-destroy <DomId> <DevId> Destroy a domain's virtual block device
102 block-list <DomId> List virtual block devices for a domain
103 block-refresh <DomId> <DevId> Refresh a virtual block device for a domain
104 network-limit <DomId> <Vif> <Credit> <Period>
105 Limit the transmission rate of a virtual network interface
106 network-list <DomId> List virtual network interfaces for a domain
108 Vnet commands:
109 vnet-list [-l|--long] list vnets
110 vnet-create <config> create a vnet from a config file
111 vnet-delete <vnetid> delete a vnet
113 For a short list of subcommands run 'xm help'
114 For more help on xm see the xm(1) man page
115 For more help on xm create, see the xmdomain.cfg(5) man page"""
117 ####################################################################
118 #
119 # Utility functions
120 #
121 ####################################################################
123 def arg_check(args,num,name):
124 if len(args) < num:
125 err("'xm %s' requires %s argument(s)!\n" % (name, num))
126 usage(name)
128 def unit(c):
129 if not c.isalpha():
130 return 0
131 base = 1
132 if c == 'G' or c == 'g': base = 1024 * 1024 * 1024
133 elif c == 'M' or c == 'm': base = 1024 * 1024
134 elif c == 'K' or c == 'k': base = 1024
135 else:
136 print 'ignoring unknown unit'
137 return base
139 def int_unit(str, dest):
140 base = unit(str[-1])
141 if not base:
142 return int(str)
144 value = int(str[:-1])
145 dst_base = unit(dest)
146 if dst_base == 0:
147 dst_base = 1
148 if dst_base > base:
149 return value / (dst_base / base)
150 else:
151 return value * (base / dst_base)
153 def err(msg):
154 print >>sys.stderr, "Error:", msg
156 def handle_xend_error(cmd, dom, ex):
157 error = str(ex)
158 if error == "Not found" and dom != None:
159 err("Domain '%s' not found when running 'xm %s'" % (dom, cmd))
160 sys.exit(1)
161 else:
162 raise ex
165 #########################################################################
166 #
167 # Main xm functions
168 #
169 #########################################################################
171 def xm_create(args):
172 from xen.xm import create
173 # ugly hack because the opt parser apparently wants
174 # the subcommand name just to throw it away!
175 args.insert(0,"bogus")
176 create.main(args)
178 def xm_save(args):
179 arg_check(args,2,"save")
181 dom = args[0] # TODO: should check if this exists
182 savefile = os.path.abspath(args[1])
184 from xen.xend.XendClient import server
185 server.xend_domain_save(dom, savefile)
187 def xm_restore(args):
188 arg_check(args,1,"restore")
190 savefile = os.path.abspath(args[0])
192 from xen.xend.XendClient import server
193 info = server.xend_domain_restore(savefile)
194 PrettyPrint.prettyprint(info)
195 id = sxp.child_value(info, 'id')
196 if id is not None:
197 server.xend_domain_unpause(id)
199 def xm_migrate(args):
200 # TODO: arg_check
201 from xen.xm import migrate
202 # ugly hack because the opt parser apparently wants
203 # the subcommand name just to throw it away!
204 args.insert(0,"bogus")
205 migrate.main(args)
207 def xm_list(args):
208 use_long = 0
209 show_vcpus = 0
210 try:
211 (options, params) = getopt(args, 'lv', ['long','vcpus'])
212 except GetoptError, opterr:
213 err(opterr)
214 sys.exit(1)
216 n = len(params)
217 for (k, v) in options:
218 if k in ['-l', '--long']:
219 use_long = 1
220 if k in ['-v', '--vcpus']:
221 show_vcpus = 1
223 domsinfo = []
224 from xen.xend.XendClient import server
225 if n == 0:
226 doms = server.xend_domains()
227 doms.sort()
228 else:
229 doms = params
230 for dom in doms:
231 info = server.xend_domain(dom)
232 domsinfo.append(parse_doms_info(info))
234 if use_long:
235 for dom in doms:
236 info = server.xend_domain(dom)
237 PrettyPrint.prettyprint(info)
238 elif show_vcpus:
239 xm_show_vcpus(domsinfo)
240 else:
241 xm_brief_list(domsinfo)
243 def parse_doms_info(info):
244 dominfo = {}
245 dominfo['dom'] = int(sxp.child_value(info, 'id', '-1'))
246 dominfo['name'] = sxp.child_value(info, 'name', '??')
247 dominfo['mem'] = int(sxp.child_value(info, 'memory', '0'))
248 dominfo['cpu'] = str(sxp.child_value(info, 'cpu', '0'))
249 dominfo['vcpus'] = int(sxp.child_value(info, 'vcpus', '0'))
250 # if there is more than 1 cpu, the value doesn't mean much
251 if dominfo['vcpus'] > 1:
252 dominfo['cpu'] = '-'
253 dominfo['state'] = sxp.child_value(info, 'state', '??')
254 dominfo['cpu_time'] = float(sxp.child_value(info, 'cpu_time', '0'))
255 # security identifiers
256 if ((int(sxp.child_value(info, 'ssidref', '0'))) != 0):
257 dominfo['ssidref1'] = int(sxp.child_value(info, 'ssidref', '0')) & 0xffff
258 dominfo['ssidref2'] = (int(sxp.child_value(info, 'ssidref', '0')) >> 16) & 0xffff
259 # get out the vcpu information
260 dominfo['vcpulist'] = []
261 vcpu_to_cpu = sxp.child_value(info, 'vcpu_to_cpu', '-1').split('|')
262 cpumap = sxp.child_value(info, 'cpumap', [])
263 mask = ((int(sxp.child_value(info, 'vcpus', '0')))**2) - 1
264 count = 0
265 for cpu in vcpu_to_cpu:
266 vcpuinfo = {}
267 vcpuinfo['name'] = sxp.child_value(info, 'name', '??')
268 vcpuinfo['dom'] = int(sxp.child_value(info, 'id', '-1'))
269 vcpuinfo['vcpu'] = int(count)
270 vcpuinfo['cpu'] = int(cpu)
271 vcpuinfo['cpumap'] = int(cpumap[count])&mask
272 count = count + 1
273 dominfo['vcpulist'].append(vcpuinfo)
274 return dominfo
276 def xm_brief_list(domsinfo):
277 print 'Name Id Mem(MB) CPU VCPU(s) State Time(s)'
278 for dominfo in domsinfo:
279 if dominfo.has_key("ssidref1"):
280 print ("%(name)-16s %(dom)3d %(mem)7d %(cpu)3s %(vcpus)5d %(state)5s %(cpu_time)7.1f s:%(ssidref2)02x/p:%(ssidref1)02x" % dominfo)
281 else:
282 print ("%(name)-16s %(dom)3d %(mem)7d %(cpu)3s %(vcpus)5d %(state)5s %(cpu_time)7.1f" % dominfo)
284 def xm_show_vcpus(domsinfo):
285 print 'Name Id VCPU CPU CPUMAP'
286 for dominfo in domsinfo:
287 for vcpuinfo in dominfo['vcpulist']:
288 print ("%(name)-16s %(dom)3d %(vcpu)4d %(cpu)3d 0x%(cpumap)x" %
289 vcpuinfo)
291 def xm_vcpu_list(args):
292 args.insert(0,"-v")
293 xm_list(args)
295 def xm_destroy(args):
296 arg_check(args,1,"destroy")
298 from xen.xm import destroy
299 # ugly hack because the opt parser apparently wants
300 # the subcommand name just to throw it away!
301 args.insert(0,"bogus")
302 destroy.main(args)
304 def xm_reboot(args):
305 arg_check(args,1,"reboot")
306 # ugly hack because the opt parser apparently wants
307 # the subcommand name just to throw it away!
308 args.insert(0,"bogus")
309 args.insert(2,"-R")
310 from xen.xm import shutdown
311 shutdown.main(args)
313 def xm_shutdown(args):
314 arg_check(args,1,"shutdown")
316 # ugly hack because the opt parser apparently wants
317 # the subcommand name just to throw it away!
318 args.insert(0,"bogus")
319 from xen.xm import shutdown
320 shutdown.main(args)
322 def xm_sysrq(args):
323 from xen.xm import sysrq
324 # ugly hack because the opt parser apparently wants
325 # the subcommand name just to throw it away!
326 args.insert(0,"bogus")
327 sysrq.main(args)
329 def xm_pause(args):
330 arg_check(args, 1, "pause")
331 dom = args[0]
333 from xen.xend.XendClient import server
334 server.xend_domain_pause(dom)
336 def xm_unpause(args):
337 arg_check(args, 1, "unpause")
338 dom = args[0]
340 from xen.xend.XendClient import server
341 server.xend_domain_unpause(dom)
343 #############################################################
345 def cpu_make_map(cpulist):
346 cpus = []
347 cpumap = 0
348 for c in cpulist.split(','):
349 if c.find('-') != -1:
350 (x,y) = c.split('-')
351 for i in range(int(x),int(y)+1):
352 cpus.append(int(i))
353 else:
354 cpus.append(int(c))
355 cpus.sort()
356 for c in cpus:
357 cpumap = cpumap | 1<<c
359 return cpumap
361 def xm_cpus_set(args):
362 arg_check(args, 3, "cpus-set")
364 dom = args[0]
365 vcpu = int(args[1])
366 cpumap = cpu_make_map(args[2])
368 from xen.xend.XendClient import server
369 server.xend_domain_pincpu(dom, vcpu, cpumap)
371 def xm_mem_max(args):
372 arg_check(args, 2, "mem-max")
374 dom = args[0]
375 mem = int_unit(args[1], 'm')
377 from xen.xend.XendClient import server
378 server.xend_domain_maxmem_set(dom, mem)
380 def xm_mem_set(args):
381 arg_check(args, 2, "mem-set")
383 dom = args[0]
384 mem_target = int_unit(args[1], 'm')
386 from xen.xend.XendClient import server
387 server.xend_domain_mem_target_set(dom, mem_target)
389 # TODO: why does this lookup by name? and what if that fails!?
390 def xm_vcpu_enable(args):
391 arg_check(args, 2, "vcpu-enable")
393 name = args[0]
394 vcpu = int(args[1])
396 from xen.xend.XendClient import server
397 dom = server.xend_domain(name)
398 id = sxp.child_value(dom, 'id')
399 server.xend_domain_vcpu_hotplug(id, vcpu, 1)
401 def xm_vcpu_disable(args):
402 arg_check(args, 2, "vcpu-disable")
404 name = args[0]
405 vcpu = int(args[1])
407 from xen.xend.XendClient import server
408 dom = server.xend_domain(name)
409 id = sxp.child_value(dom, 'id')
410 server.xend_domain_vcpu_hotplug(id, vcpu, 0)
412 def xm_domid(args):
413 name = args[0]
415 from xen.xend.XendClient import server
416 dom = server.xend_domain(name)
417 print sxp.child_value(dom, 'id')
419 def xm_domname(args):
420 name = args[0]
422 from xen.xend.XendClient import server
423 dom = server.xend_domain(name)
424 print sxp.child_value(dom, 'name')
426 def xm_bvt(args):
427 arg_check(args, 6, "bvt")
428 dom = args[0]
429 v = map(long, args[1:6])
430 from xen.xend.XendClient import server
431 server.xend_domain_cpu_bvt_set(dom, *v)
433 def xm_bvt_ctxallow(args):
434 arg_check(args, 1, "bvt_ctxallow")
436 slice = int(args[0])
437 from xen.xend.XendClient import server
438 server.xend_node_cpu_bvt_slice_set(slice)
440 def xm_sedf(args):
441 arg_check(args, 6, "sedf")
443 dom = args[0]
444 v = map(int, args[1:6])
445 from xen.xend.XendClient import server
446 server.xend_domain_cpu_sedf_set(dom, *v)
448 def xm_info(args):
449 from xen.xend.XendClient import server
450 info = server.xend_node()
452 for x in info[1:]:
453 if len(x) < 2:
454 print "%-23s: (none)" % x[0]
455 else:
456 print "%-23s:" % x[0], x[1]
458 # TODO: remove as soon as console server shows up
459 def xm_console(args):
460 arg_check(args,1,"console")
462 dom = args[0]
463 from xen.xend.XendClient import server
464 info = server.xend_domain(dom)
465 domid = int(sxp.child_value(info, 'id', '-1'))
466 cmd = "/usr/libexec/xen/xenconsole %d" % domid
467 os.execvp('/usr/libexec/xen/xenconsole', cmd.split())
468 console = sxp.child(info, "console")
470 def xm_top(args):
471 os.execv('/usr/sbin/xentop', ['/usr/sbin/xentop'])
473 def xm_dmesg(args):
475 gopts = Opts(use="""[-c|--clear]
477 Read Xen's message buffer (boot output, warning and error messages) or clear
478 its contents if the [-c|--clear] flag is specified.
479 """)
481 gopts.opt('clear', short='c',
482 fn=set_true, default=0,
483 use="Clear the contents of the Xen message buffer.")
484 # Work around for gopts
485 args.insert(0,"bogus")
486 gopts.parse(args)
487 if not (1 <= len(args) <= 2):
488 err('Invalid arguments: ' + str(args))
490 from xen.xend.XendClient import server
491 if not gopts.vals.clear:
492 print server.xend_node_get_dmesg()
493 else:
494 server.xend_node_clear_dmesg()
496 def xm_log(args):
497 from xen.xend.XendClient import server
498 print server.xend_node_log()
500 def xm_network_limit(args):
501 arg_check(args,4,"network-limit")
502 dom = args[0]
503 v = map(int, args[1:4])
504 from xen.xend.XendClient import server
505 server.xend_domain_vif_limit(dom, *v)
507 def xm_network_list(args):
508 arg_check(args,1,"network-list")
509 dom = args[0]
510 from xen.xend.XendClient import server
511 for x in server.xend_domain_devices(dom, 'vif'):
512 sxp.show(x)
513 print
515 def xm_block_list(args):
516 arg_check(args,1,"block-list")
517 dom = args[0]
518 from xen.xend.XendClient import server
519 for x in server.xend_domain_devices(dom, 'vbd'):
520 sxp.show(x)
521 print
523 def xm_block_create(args):
524 n = len(args)
525 if n < 4 or n > 5:
526 err("%s: Invalid argument(s)" % args[0])
527 usage("block-create")
529 dom = args[0]
530 vbd = ['vbd',
531 ['uname', args[1]],
532 ['dev', args[2]],
533 ['mode', args[3]]]
534 if n == 5:
535 vbd.append(['backend', args[4]])
537 from xen.xend.XendClient import server
538 server.xend_domain_device_create(dom, vbd)
540 def xm_block_refresh(args):
541 arg_check(args,2,"block-refresh")
543 dom = args[0]
544 dev = args[1]
546 from xen.xend.XendClient import server
547 server.xend_domain_device_refresh(dom, 'vbd', dev)
549 def xm_block_destroy(args):
550 arg_check(args,2,"block-destroy")
552 dom = args[0]
553 dev = args[1]
555 from xen.xend.XendClient import server
556 server.xend_domain_device_destroy(dom, 'vbd', dev)
558 def xm_vnet_list(args):
559 from xen.xend.XendClient import server
560 try:
561 (options, params) = getopt(args, 'l', ['long'])
562 except GetoptError, opterr:
563 err(opterr)
564 sys.exit(1)
566 use_long = 0
567 for (k, v) in options:
568 if k in ['-l', '--long']:
569 use_long = 1
571 if params:
572 use_long = 1
573 vnets = params
574 else:
575 vnets = server.xend_vnets()
577 for vnet in vnets:
578 try:
579 if use_long:
580 info = server.xend_vnet(vnet)
581 PrettyPrint.prettyprint(info)
582 else:
583 print vnet
584 except Exception, ex:
585 print vnet, ex
587 def xm_vnet_create(args):
588 arg_check(args, 1, "vnet-create")
589 conf = args[0]
590 from xen.xend.XendClient import server
591 server.xend_vnet_create(conf)
593 def xm_vnet_delete(args):
594 arg_check(args, 1, "vnet-delete")
595 vnet = args[0]
596 from xen.xend.XendClient import server
597 server.xend_vnet_delete(vnet)
599 commands = {
600 # console commands
601 "console": xm_console,
602 # xenstat commands
603 "top": xm_top,
604 # domain commands
605 "domid": xm_domid,
606 "domname": xm_domname,
607 "create": xm_create,
608 "destroy": xm_destroy,
609 "restore": xm_restore,
610 "save": xm_save,
611 "shutdown": xm_shutdown,
612 "reboot": xm_reboot,
613 "list": xm_list,
614 # memory commands
615 "mem-max": xm_mem_max,
616 "mem-set": xm_mem_set,
617 # cpu commands
618 "cpus-set": xm_cpus_set,
619 # "cpus-list": xm_cpus_list,
620 "vcpu-enable": xm_vcpu_enable,
621 "vcpu-disable": xm_vcpu_disable,
622 "vcpu-list": xm_vcpu_list,
623 # migration
624 "migrate": xm_migrate,
625 # special
626 "sysrq": xm_sysrq,
627 "pause": xm_pause,
628 "unpause": xm_unpause,
629 # host commands
630 "dmesg": xm_dmesg,
631 "info": xm_info,
632 "log": xm_log,
633 # scheduler
634 "bvt": xm_bvt,
635 "bvt_ctxallow": xm_bvt_ctxallow,
636 "sedf": xm_sedf,
637 # block
638 "block-create": xm_block_create,
639 "block-destroy": xm_block_destroy,
640 "block-list": xm_block_list,
641 "block-refresh": xm_block_refresh,
642 # network
643 "network-limit": xm_network_limit,
644 "network-list": xm_network_list,
645 # vnet
646 "vnet-list": xm_vnet_list,
647 "vnet-create": xm_vnet_create,
648 "vnet-delete": xm_vnet_delete,
649 }
651 aliases = {
652 "balloon": "mem-set",
653 "vif-list": "network-list",
654 "vif-limit": "network-limit",
655 "vbd-create": "block-create",
656 "vbd-destroy": "block-destroy",
657 "vbd-list": "block-list",
658 "vbd-refresh": "block-refresh",
659 }
661 help = {
662 "--long": longhelp
663 }
665 def xm_lookup_cmd(cmd):
666 if commands.has_key(cmd):
667 return commands[cmd]
668 elif aliases.has_key(cmd):
669 deprecated(cmd,aliases[cmd])
670 return commands[aliases[cmd]]
671 else:
672 if len( cmd ) > 1:
673 matched_commands = filter( lambda (command, func): command[ 0:len(cmd) ] == cmd, commands.iteritems() )
674 if len( matched_commands ) == 1:
675 return matched_commands[0][1]
676 err('Sub Command %s not found!' % cmd)
677 usage()
679 def deprecated(old,new):
680 err('Option %s is deprecated, and will be removed in future!!!' % old)
681 err('Option %s is the new replacement, see "xm help %s" for more info' % (new, new))
683 def usage(cmd=None):
684 if cmd == "full":
685 print fullhelp
686 elif help.has_key(cmd):
687 print help[cmd]
688 else:
689 print shorthelp
690 sys.exit(1)
692 def main(argv=sys.argv):
693 if len(argv) < 2:
694 usage()
696 if re.compile('-*help').match(argv[1]):
697 if len(argv) > 2 and help.has_key(argv[2]):
698 usage(argv[2])
699 else:
700 usage()
701 sys.exit(0)
703 cmd = xm_lookup_cmd(argv[1])
705 # strip off prog name and subcmd
706 args = argv[2:]
707 if cmd:
708 try:
709 from xen.xend.XendClient import XendError
710 rc = cmd(args)
711 if rc:
712 usage()
713 except socket.error, ex:
714 print >>sys.stderr, ex
715 err("Error connecting to xend, is xend running?")
716 sys.exit(1)
717 except IOError:
718 err("Most commands need root access. Please try again as root")
719 sys.exit(1)
720 except XendError, ex:
721 if len(args) > 0:
722 if args[0] == "bogus":
723 args.remove("bogus")
724 handle_xend_error(argv[1], args[0], ex)
725 else:
726 print "Unexpected error:", sys.exc_info()[0]
727 print
728 print "Please report to xen-devel@lists.xensource.com"
729 raise
730 except SystemExit:
731 sys.exit(1)
732 except:
733 print "Unexpected error:", sys.exc_info()[0]
734 print
735 print "Please report to xen-devel@lists.xensource.com"
736 raise
738 else:
739 usage()
741 if __name__ == "__main__":
742 main()