1 /*
2  * Copyright 2009-2017 Citrix Ltd and other contributors
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License as published
6  * by the Free Software Foundation; version 2.1 only. with the special
7  * exception on linking described in file LICENSE.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU Lesser General Public License for more details.
13  */
14 
15 #include <string.h>
16 
17 #include <libxl.h>
18 
19 #include "xl.h"
20 
21 struct cmd_spec cmd_table[] = {
22     { "create",
23       &main_create, 1, 1,
24       "Create a domain from config file <filename>",
25       "<ConfigFile> [options] [vars]",
26       "-h                      Print this help.\n"
27       "-p                      Leave the domain paused after it is created.\n"
28       "-c                      Connect to the console after the domain is created.\n"
29       "-f FILE, --defconfig=FILE\n                     Use the given configuration file.\n"
30       "-q, --quiet             Quiet.\n"
31       "-n, --dryrun            Dry run - prints the resulting configuration\n"
32       "                         (deprecated in favour of global -N option).\n"
33       "-d                      Enable debug messages.\n"
34       "-F                      Run in foreground until death of the domain.\n"
35       "-e                      Do not wait in the background for the death of the domain.\n"
36       "-V, --vncviewer         Connect to the VNC display after the domain is created.\n"
37       "-A, --vncviewer-autopass\n"
38       "                        Pass VNC password to viewer via stdin.\n"
39       "--ignore-global-affinity-masks Ignore global masks in xl.conf."
40     },
41     { "config-update",
42       &main_config_update, 1, 1,
43       "Update a running domain's saved configuration, used when rebuilding "
44       "the domain after reboot.\n"
45       "WARNING: xl now has better capability to manage domain configuration, "
46       "avoid using this command when possible",
47       "<Domain> <ConfigFile> [options] [vars]",
48       "-h                      Print this help.\n"
49       "-f FILE, --defconfig=FILE\n                     Use the given configuration file.\n"
50       "-d                      Enable debug messages.\n"
51     },
52     { "list",
53       &main_list, 0, 0,
54       "List information about all/some domains",
55       "[options] [Domain]\n",
56       "-l, --long              Output all VM details\n"
57       "-v, --verbose           Prints out UUIDs and security context\n"
58       "-Z, --context           Prints out security context\n"
59       "-c, --cpupool           Prints the cpupool the domain is in\n"
60       "-n, --numa              Prints out NUMA node affinity"
61     },
62     { "destroy",
63       &main_destroy, 0, 1,
64       "Terminate a domain immediately",
65       "[options] <Domain>\n",
66       "-f                      Permit destroying domain 0, which will only succeed\n"
67       "                        when run from disaggregated toolstack domain with a\n"
68       "                        hardware domain distinct from domain 0."
69     },
70     { "shutdown",
71       &main_shutdown, 0, 1,
72       "Issue a shutdown signal to a domain",
73       "[options] <-a|Domain>",
74       "-a, --all               Shutdown all guest domains.\n"
75       "-h                      Print this help.\n"
76       "-F                      Fallback to ACPI power event for HVM guests with\n"
77       "                        no PV drivers.\n"
78       "-w, --wait              Wait for guest(s) to shutdown.\n"
79     },
80     { "reboot",
81       &main_reboot, 0, 1,
82       "Issue a reboot signal to a domain",
83       "[options] <-a|Domain>",
84       "-a, --all               Shutdown all guest domains.\n"
85       "-h                      Print this help.\n"
86       "-F                      Fallback to ACPI reset event for HVM guests with\n"
87       "                        no PV drivers.\n"
88       "-w, --wait              Wait for guest(s) to reboot.\n"
89     },
90     { "pci-attach",
91       &main_pciattach, 0, 1,
92       "Insert a new pass-through pci device",
93       "<Domain> <BDF> [Virtual Slot]",
94     },
95     { "pci-detach",
96       &main_pcidetach, 0, 1,
97       "Remove a domain's pass-through pci device",
98       "<Domain> <BDF>",
99     },
100     { "pci-list",
101       &main_pcilist, 0, 0,
102       "List pass-through pci devices for a domain",
103       "<Domain>",
104     },
105     { "pci-assignable-add",
106       &main_pciassignable_add, 0, 1,
107       "Make a device assignable for pci-passthru",
108       "<BDF>",
109       "-h                      Print this help.\n"
110     },
111     { "pci-assignable-remove",
112       &main_pciassignable_remove, 0, 1,
113       "Remove a device from being assignable",
114       "[options] <BDF>",
115       "-h                      Print this help.\n"
116       "-r                      Attempt to re-assign the device to the\n"
117       "                        original driver"
118     },
119     { "pci-assignable-list",
120       &main_pciassignable_list, 0, 0,
121       "List all the assignable pci devices",
122       "",
123     },
124     { "pause",
125       &main_pause, 0, 1,
126       "Pause execution of a domain",
127       "<Domain>",
128     },
129     { "unpause",
130       &main_unpause, 0, 1,
131       "Unpause a paused domain",
132       "<Domain>",
133     },
134     { "console",
135       &main_console, 0, 0,
136       "Attach to domain's console",
137       "[options] <Domain>\n"
138       "-t <type>       console type, pv , serial or vuart\n"
139       "-n <number>     console number"
140     },
141     { "vncviewer",
142       &main_vncviewer, 0, 0,
143       "Attach to domain's VNC server.",
144       "[options] <Domain>\n"
145       "--autopass               Pass VNC password to viewer via stdin and\n"
146       "                         -autopass\n"
147       "--vncviewer-autopass     (consistency alias for --autopass)"
148     },
149 #ifndef LIBXL_HAVE_NO_SUSPEND_RESUME
150     { "save",
151       &main_save, 0, 1,
152       "Save a domain state to restore later",
153       "[options] <Domain> <CheckpointFile> [<ConfigFile>]",
154       "-h  Print this help.\n"
155       "-c  Leave domain running after creating the snapshot.\n"
156       "-p  Leave domain paused after creating the snapshot.\n"
157       "-D  Store the domain id in the configration."
158     },
159     { "migrate",
160       &main_migrate, 0, 1,
161       "Migrate a domain to another host",
162       "[options] <Domain> <host>",
163       "-h              Print this help.\n"
164       "-C <config>     Send <config> instead of config file from creation.\n"
165       "-s <sshcommand> Use <sshcommand> instead of ssh.  String will be passed\n"
166       "                to sh. If empty, run <host> instead of ssh <host> xl\n"
167       "                migrate-receive [-d -e]\n"
168       "-e              Do not wait in the background (on <host>) for the death\n"
169       "                of the domain.\n"
170       "--debug         Print huge (!) amount of debug during the migration process.\n"
171       "-p              Do not unpause domain after migrating it.\n"
172       "-D              Preserve the domain id"
173     },
174     { "restore",
175       &main_restore, 0, 1,
176       "Restore a domain from a saved state",
177       "[options] [<ConfigFile>] <CheckpointFile>",
178       "-h                       Print this help.\n"
179       "-p                       Do not unpause domain after restoring it.\n"
180       "-e                       Do not wait in the background for the death of the domain.\n"
181       "-d                       Enable debug messages.\n"
182       "-V, --vncviewer          Connect to the VNC display after the domain is created.\n"
183       "-A, --vncviewer-autopass Pass VNC password to viewer via stdin."
184     },
185     { "migrate-receive",
186       &main_migrate_receive, 0, 1,
187       "Restore a domain from a saved state",
188       "- for internal use only",
189     },
190 #endif
191     { "dump-core",
192       &main_dump_core, 0, 1,
193       "Core dump a domain",
194       "<Domain> <filename>"
195     },
196     { "cd-insert",
197       &main_cd_insert, 1, 1,
198       "Insert a cdrom into a guest's cd drive",
199       "<Domain> <VirtualDevice> <path>",
200     },
201     { "cd-eject",
202       &main_cd_eject, 1, 1,
203       "Eject a cdrom from a guest's cd drive",
204       "<Domain> <VirtualDevice>",
205     },
206     { "mem-max",
207       &main_memmax, 0, 1,
208       "Set the maximum amount reservation for a domain",
209       "<Domain> <MemMB['b'[bytes]|'k'[KB]|'m'[MB]|'g'[GB]|'t'[TB]]>",
210     },
211     { "mem-set",
212       &main_memset, 0, 1,
213       "Set the current memory usage for a domain",
214       "<Domain> <MemMB['b'[bytes]|'k'[KB]|'m'[MB]|'g'[GB]|'t'[TB]]>",
215     },
216     { "button-press",
217       &main_button_press, 0, 1,
218       "Indicate an ACPI button press to the domain",
219       "<Domain> <Button>",
220       "<Button> may be 'power' or 'sleep'."
221     },
222     { "vcpu-list",
223       &main_vcpulist, 0, 0,
224       "List the VCPUs for all/some domains",
225       "[Domain, ...]",
226     },
227     { "vcpu-pin",
228       &main_vcpupin, 1, 1,
229       "Set which CPUs a VCPU can use",
230       "[option] <Domain> <VCPU|all> <Hard affinity|-|all> <Soft affinity|-|all>",
231       "-f, --force        undo an override pinning done by the kernel\n"
232       "--ignore-global-affinity-masks Ignore global masks in xl.conf",
233     },
234     { "vcpu-set",
235       &main_vcpuset, 0, 1,
236       "Set the number of active VCPUs allowed for the domain",
237       "[option] <Domain> <vCPUs>",
238       "-i, --ignore-host  Don't limit the vCPU based on the host CPU count",
239     },
240     { "vm-list",
241       &main_vm_list, 0, 0,
242       "List guest domains, excluding dom0, stubdoms, etc.",
243       "",
244     },
245     { "info",
246       &main_info, 0, 0,
247       "Get information about Xen host",
248       "-n, --numa         List host NUMA topology information",
249     },
250     { "sharing",
251       &main_sharing, 0, 0,
252       "Get information about page sharing",
253       "[Domain]",
254     },
255     { "sched-credit",
256       &main_sched_credit, 0, 1,
257       "Get/set credit scheduler parameters",
258       "[-d <Domain> [-w[=WEIGHT]|-c[=CAP]]] [-s [-t TSLICE] [-r RATELIMIT]] [-p CPUPOOL]",
259       "-d DOMAIN, --domain=DOMAIN        Domain to modify\n"
260       "-w WEIGHT, --weight=WEIGHT        Weight (int)\n"
261       "-c CAP, --cap=CAP                 Cap (int)\n"
262       "-s         --schedparam           Query / modify scheduler parameters\n"
263       "-t TSLICE, --tslice_ms=TSLICE     Set the timeslice, in milliseconds\n"
264       "-r RLIMIT, --ratelimit_us=RLIMIT  Set the scheduling rate limit, in microseconds\n"
265       "-m DLY, --migration_delay_us=DLY  Set the migration delay, in microseconds\n"
266       "-p CPUPOOL, --cpupool=CPUPOOL     Restrict output to CPUPOOL"
267     },
268     { "sched-credit2",
269       &main_sched_credit2, 0, 1,
270       "Get/set credit2 scheduler parameters",
271       "[-d <Domain> [-w[=WEIGHT]]] [-p CPUPOOL]",
272       "-d DOMAIN, --domain=DOMAIN     Domain to modify\n"
273       "-w WEIGHT, --weight=WEIGHT     Weight (int)\n"
274       "-c CAP,    --cap=CAP           Cap (int)\n"
275       "-s         --schedparam        Query / modify scheduler parameters\n"
276       "-r RLIMIT, --ratelimit_us=RLIMIT Set the scheduling rate limit, in microseconds\n"
277       "-p CPUPOOL, --cpupool=CPUPOOL  Restrict output to CPUPOOL"
278     },
279     { "sched-rtds",
280       &main_sched_rtds, 0, 1,
281       "Get/set rtds scheduler parameters",
282       "[-d <Domain> [-v[=VCPUID/all]] [-p[=PERIOD]] [-b[=BUDGET]] [-e[=Extratime]]]",
283       "-d DOMAIN, --domain=DOMAIN     Domain to modify\n"
284       "-v VCPUID/all, --vcpuid=VCPUID/all    VCPU to modify or output;\n"
285       "               Using '-v all' to modify/output all vcpus\n"
286       "-p PERIOD, --period=PERIOD     Period (us)\n"
287       "-b BUDGET, --budget=BUDGET     Budget (us)\n"
288       "-e Extratime, --extratime=Extratime Extratime (1=yes, 0=no)\n"
289     },
290     { "domid",
291       &main_domid, 0, 0,
292       "Convert a domain name to domain id",
293       "<DomainName>",
294     },
295     { "domname",
296       &main_domname, 0, 0,
297       "Convert a domain id to domain name",
298       "<DomainId>",
299     },
300     { "rename",
301       &main_rename, 0, 1,
302       "Rename a domain",
303       "<Domain> <NewDomainName>",
304     },
305     { "trigger",
306       &main_trigger, 0, 1,
307       "Send a trigger to a domain",
308       "<Domain> <nmi|reset|init|power|sleep|s3resume> [<VCPU>]",
309     },
310     { "sysrq",
311       &main_sysrq, 0, 1,
312       "Send a sysrq to a domain",
313       "<Domain> <letter>",
314     },
315     { "debug-keys",
316       &main_debug_keys, 0, 1,
317       "Send debug keys to Xen",
318       "<Keys>",
319     },
320     { "set-parameters",
321       &main_set_parameters, 0, 1,
322       "Set hypervisor parameters",
323       "<Params>",
324     },
325     { "dmesg",
326       &main_dmesg, 0, 0,
327       "Read and/or clear dmesg buffer",
328       "[-c]",
329       "  -c                        Clear dmesg buffer as well as printing it",
330     },
331     { "top",
332       &main_top, 0, 0,
333       "Monitor a host and the domains in real time",
334       "",
335     },
336     { "network-attach",
337       &main_networkattach, 1, 1,
338       "Create a new virtual network device",
339       "<Domain> [type=<type>] [mac=<mac>] [bridge=<bridge>] "
340       "[ip=<ip>] [script=<script>] [backend=<BackDomain>] [vifname=<name>] "
341       "[rate=<rate>] [model=<model>] [accel=<accel>]",
342     },
343     { "network-list",
344       &main_networklist, 0, 0,
345       "List virtual network interfaces for a domain",
346       "<Domain(s)>",
347     },
348     { "network-detach",
349       &main_networkdetach, 0, 1,
350       "Destroy a domain's virtual network device",
351       "<Domain> <DevId|mac>",
352     },
353     { "channel-list",
354       &main_channellist, 0, 0,
355       "List virtual channel devices for a domain",
356       "<Domain(s)>",
357     },
358     { "block-attach",
359       &main_blockattach, 1, 1,
360       "Create a new virtual block device",
361       "<Domain> <disk-spec-component(s)>...",
362     },
363     { "block-list",
364       &main_blocklist, 0, 0,
365       "List virtual block devices for a domain",
366       "<Domain(s)>",
367     },
368     { "block-detach",
369       &main_blockdetach, 0, 1,
370       "Destroy a domain's virtual block device",
371       "<Domain> <DevId>",
372     },
373     { "vtpm-attach",
374       &main_vtpmattach, 1, 1,
375       "Create a new virtual TPM device",
376       "<Domain> [uuid=<uuid>] [backend=<BackDomain>]",
377     },
378     { "vtpm-list",
379       &main_vtpmlist, 0, 0,
380       "List virtual TPM devices for a domain",
381       "<Domain(s)>",
382     },
383     { "vtpm-detach",
384       &main_vtpmdetach, 0, 1,
385       "Destroy a domain's virtual TPM device",
386       "<Domain> <DevId|uuid>",
387     },
388     { "vkb-attach",
389       &main_vkbattach, 1, 1,
390       "Create a new virtual keyboard device",
391       "<Domain> <vkb-spec-component(s)>...",
392     },
393     { "vkb-list",
394       &main_vkblist, 0, 0,
395       "List virtual keyboard devices for a domain",
396       "<Domain(s)>",
397     },
398     { "vkb-detach",
399       &main_vkbdetach, 0, 1,
400       "Destroy a domain's virtual keyboard device",
401       "<Domain> <DevId>",
402     },
403     { "vdispl-attach",
404       &main_vdisplattach, 1, 1,
405       "Create a new virtual display device",
406       "<Domain> [backend=<BackDomain>] [be-alloc=<BackAlloc>] [connectors='<Connectors>']",
407       "    BackAlloc  - set to 1 to if backend allocates display buffers\n"
408       "    Connectors - list of connector's description in ID:WxH format,\n"
409       "                 where: ID - unique connector ID, W - connector width,\n"
410       "                 H - connector height: connectors='id0:800x600;id1:1024x768'\n"
411     },
412     { "vdispl-list",
413       &main_vdispllist, 0, 0,
414       "List virtual display devices for a domain",
415       "<Domain(s)>",
416     },
417     { "vdispl-detach",
418       &main_vdispldetach, 0, 1,
419       "Destroy a domain's virtual display device",
420       "<Domain> <DevId>",
421     },
422     { "vsnd-attach",
423       &main_vsndattach, 1, 1,
424       "Create a new virtual sound device",
425       "<Domain> <vsnd-spec-component(s)>...",
426     },
427     { "vsnd-list",
428       &main_vsndlist, 0, 0,
429       "List virtual display devices for a domain",
430       "<Domain(s)>",
431     },
432     { "vsnd-detach",
433       &main_vsnddetach, 0, 1,
434       "Destroy a domain's virtual sound device",
435       "<Domain> <DevId>",
436     },
437     { "uptime",
438       &main_uptime, 0, 0,
439       "Print uptime for all/some domains",
440       "[-s] [Domain]",
441     },
442     { "claims",
443       &main_claims, 0, 0,
444       "List outstanding claim information about all domains",
445       "",
446       "",
447     },
448     { "cpupool-create",
449       &main_cpupoolcreate, 1, 1,
450       "Create a new CPU pool",
451       "[options] [<ConfigFile>] [Variable=value ...]",
452       "-h, --help                   Print this help.\n"
453       "-f FILE, --defconfig=FILE    Use the given configuration file.\n"
454       "-n, --dryrun                 Dry run - prints the resulting configuration.\n"
455       "                              (deprecated in favour of global -N option).\n"
456       "\nSee the xlcpupool.cfg(5) manpage for more information.",
457 
458     },
459     { "cpupool-list",
460       &main_cpupoollist, 0, 0,
461       "List CPU pools on host",
462       "[-c|--cpus] [<CPU Pool>]",
463       "-c, --cpus                     Output list of CPUs used by a pool"
464     },
465     { "cpupool-destroy",
466       &main_cpupooldestroy, 0, 1,
467       "Deactivates a CPU pool",
468       "<CPU Pool>",
469     },
470     { "cpupool-rename",
471       &main_cpupoolrename, 0, 1,
472       "Renames a CPU pool",
473       "<CPU Pool> <new name>",
474     },
475     { "cpupool-cpu-add",
476       &main_cpupoolcpuadd, 0, 1,
477       "Adds a CPU to a CPU pool",
478       "<CPU Pool> <CPU nr>|node:<node nr>",
479     },
480     { "cpupool-cpu-remove",
481       &main_cpupoolcpuremove, 0, 1,
482       "Removes a CPU from a CPU pool",
483       "<CPU Pool> <CPU nr>|node:<node nr>",
484     },
485     { "cpupool-migrate",
486       &main_cpupoolmigrate, 0, 1,
487       "Moves a domain into a CPU pool",
488       "<Domain> <CPU Pool>",
489     },
490     { "cpupool-numa-split",
491       &main_cpupoolnumasplit, 0, 1,
492       "Splits up the machine into one CPU pool per NUMA node",
493       "",
494     },
495     { "getenforce",
496       &main_getenforce, 0, 0,
497       "Returns the current enforcing mode of the Flask Xen security module",
498       "",
499     },
500     { "setenforce",
501       &main_setenforce, 0, 1,
502       "Sets the current enforcing mode of the Flask Xen security module",
503       "<1|0|Enforcing|Permissive>",
504     },
505     { "loadpolicy",
506       &main_loadpolicy, 0, 1,
507       "Loads a new policy into the Flask Xen security module",
508       "<policy file>",
509     },
510 #ifndef LIBXL_HAVE_NO_SUSPEND_RESUME
511     { "remus",
512       &main_remus, 0, 1,
513       "Enable Remus HA for domain",
514       "[options] <Domain> [<host>]",
515       "-i MS                   Checkpoint domain memory every MS milliseconds (def. 200ms).\n"
516       "-u                      Disable memory checkpoint compression.\n"
517       "-s <sshcommand>         Use <sshcommand> instead of ssh.  String will be passed\n"
518       "                        to sh. If empty, run <host> instead of \n"
519       "                        ssh <host> xl migrate-receive -r [-e]\n"
520       "-e                      Do not wait in the background (on <host>) for the death\n"
521       "                        of the domain.\n"
522       "-N <netbufscript>       Use netbufscript to setup network buffering instead of the\n"
523       "                        default script (/etc/xen/scripts/remus-netbuf-setup).\n"
524       "-F                      Enable unsafe configurations [-b|-n|-d flags]. Use this option\n"
525       "                        with caution as failover may not work as intended.\n"
526       "-b                      Replicate memory checkpoints to /dev/null (blackhole).\n"
527       "                        Works only in unsafe mode.\n"
528       "-n                      Disable network output buffering. Works only in unsafe mode.\n"
529       "-d                      Disable disk replication. Works only in unsafe mode.\n"
530       "-c                      Enable COLO HA. It is conflict with -i and -b, and memory\n"
531       "                        checkpoint must be disabled.\n"
532       "-p                      Use COLO userspace proxy."
533     },
534 #endif
535     { "devd",
536       &main_devd, 0, 1,
537       "Daemon that listens for devices and launches backends",
538       "[options]",
539       "-F                      Run in the foreground.\n"
540       "-p, --pidfile [FILE]    Write PID to pidfile when daemonizing.",
541     },
542 #if defined(__i386__) || defined(__x86_64__)
543     { "psr-hwinfo",
544       &main_psr_hwinfo, 0, 1,
545       "Show hardware information for Platform Shared Resource",
546       "[options]",
547       "-m, --cmt       Show Cache Monitoring Technology (CMT) hardware info\n"
548       "-a, --cat       Show Cache Allocation Technology (CAT) hardware info\n"
549       "-b, --mba       Show Memory Bandwidth Allocation (MBA) hardware info\n"
550     },
551     { "psr-cmt-attach",
552       &main_psr_cmt_attach, 0, 1,
553       "Attach Cache Monitoring Technology service to a domain",
554       "<Domain>",
555     },
556     { "psr-cmt-detach",
557       &main_psr_cmt_detach, 0, 1,
558       "Detach Cache Monitoring Technology service from a domain",
559       "<Domain>",
560     },
561     { "psr-cmt-show",
562       &main_psr_cmt_show, 0, 1,
563       "Show Cache Monitoring Technology information",
564       "<PSR-CMT-Type> <Domain>",
565       "Available monitor types:\n"
566       "\"cache-occupancy\":         Show L3 cache occupancy(KB)\n"
567       "\"total-mem-bandwidth\":     Show total memory bandwidth(KB/s)\n"
568       "\"local-mem-bandwidth\":     Show local memory bandwidth(KB/s)\n",
569     },
570     { "psr-cat-set",
571       &main_psr_cat_cbm_set, 0, 1,
572       "Set cache capacity bitmasks(CBM) for a domain",
573       "[options] <Domain> <CBM>",
574       "-s <socket>       Specify the socket to process, otherwise all sockets are processed\n"
575       "-l <level>        Specify the cache level to process, otherwise L3 cache is processed\n"
576       "-c                Set code CBM if CDP is supported\n"
577       "-d                Set data CBM if CDP is supported\n"
578     },
579     { "psr-cat-show",
580       &main_psr_cat_show, 0, 1,
581       "Show Cache Allocation Technology information",
582       "[options] <Domain>",
583       "-l <level>        Specify the cache level to process, otherwise L3 cache is processed\n"
584     },
585     { "psr-mba-set",
586       &main_psr_mba_set, 0, 1,
587       "Set throttling value (THRTL) for a domain",
588       "[options] <Domain> <THRTL>",
589       "-s <socket>       Specify the socket to process, otherwise all sockets are processed\n"
590     },
591     { "psr-mba-show",
592       &main_psr_mba_show, 0, 1,
593       "Show Memory Bandwidth Allocation information",
594       "<Domain>",
595     },
596 #endif
597     { "usbctrl-attach",
598       &main_usbctrl_attach, 0, 1,
599       "Create a virtual USB controller for a domain",
600       "<Domain> [type=pv] [version=<version>] [ports=<number>]",
601     },
602     { "usbctrl-detach",
603       &main_usbctrl_detach, 0, 1,
604       "Remove the virtual USB controller specified by <DevId> for a domain",
605       "<Domain> <DevId>",
606     },
607     { "usbdev-attach",
608       &main_usbdev_attach, 0, 1,
609       "Attach a USB device to a domain",
610       "<Domain> hostbus=<busnum> hostaddr=<devnum> [controller=<DevId> [port=<port>]]",
611     },
612     { "usbdev-detach",
613       &main_usbdev_detach, 0, 1,
614       "Detach a USB device from a domain",
615       "<Domain> <controller> <port>",
616     },
617     { "usb-list",
618       &main_usblist, 0, 0,
619       "List information about all USB controllers and devices for a domain",
620       "<Domain>",
621     },
622     { "qemu-monitor-command",
623       &main_qemu_monitor_command, 0, 1,
624       "Issue a qemu monitor command to the device model of a domain",
625       "<Domain> <Command>",
626     },
627 };
628 
629 int cmdtable_len = sizeof(cmd_table)/sizeof(struct cmd_spec);
630 
631 /* Look up a command in the table, allowing unambiguous truncation */
cmdtable_lookup(const char * s)632 struct cmd_spec *cmdtable_lookup(const char *s)
633 {
634     struct cmd_spec *cmd = NULL;
635     size_t len;
636     int i, count = 0;
637 
638     if (!s)
639         return NULL;
640     len = strlen(s);
641     for (i = 0; i < cmdtable_len; i++) {
642         if (!strncmp(s, cmd_table[i].cmd_name, len)) {
643             cmd = &cmd_table[i];
644             /* Take an exact match, even if it also prefixes another command */
645             if (len == strlen(cmd->cmd_name))
646                 return cmd;
647             count++;
648         }
649     }
650     return (count == 1) ? cmd : NULL;
651 }
652 
653 /*
654  * Local variables:
655  * mode: C
656  * c-basic-offset: 4
657  * indent-tabs-mode: nil
658  * End:
659  */
660