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