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