1 | /* |
2 | * QEMU monitor |
3 | * |
4 | * Copyright (c) 2003-2004 Fabrice Bellard |
5 | * |
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
7 | * of this software and associated documentation files (the "Software"), to deal |
8 | * in the Software without restriction, including without limitation the rights |
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
10 | * copies of the Software, and to permit persons to whom the Software is |
11 | * furnished to do so, subject to the following conditions: |
12 | * |
13 | * The above copyright notice and this permission notice shall be included in |
14 | * all copies or substantial portions of the Software. |
15 | * |
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
22 | * THE SOFTWARE. |
23 | */ |
24 | |
25 | #include "qemu/osdep.h" |
26 | #include <dirent.h> |
27 | #include "monitor-internal.h" |
28 | #include "qapi/error.h" |
29 | #include "qapi/qmp/qdict.h" |
30 | #include "qapi/qmp/qnum.h" |
31 | #include "qemu/config-file.h" |
32 | #include "qemu/ctype.h" |
33 | #include "qemu/cutils.h" |
34 | #include "qemu/log.h" |
35 | #include "qemu/option.h" |
36 | #include "qemu/units.h" |
37 | #include "sysemu/block-backend.h" |
38 | #include "sysemu/runstate.h" |
39 | #include "trace.h" |
40 | |
41 | static void monitor_command_cb(void *opaque, const char *cmdline, |
42 | void *readline_opaque) |
43 | { |
44 | MonitorHMP *mon = opaque; |
45 | |
46 | monitor_suspend(&mon->common); |
47 | handle_hmp_command(mon, cmdline); |
48 | monitor_resume(&mon->common); |
49 | } |
50 | |
51 | void monitor_read_command(MonitorHMP *mon, int show_prompt) |
52 | { |
53 | if (!mon->rs) { |
54 | return; |
55 | } |
56 | |
57 | readline_start(mon->rs, "(qemu) " , 0, monitor_command_cb, NULL); |
58 | if (show_prompt) { |
59 | readline_show_prompt(mon->rs); |
60 | } |
61 | } |
62 | |
63 | int monitor_read_password(MonitorHMP *mon, ReadLineFunc *readline_func, |
64 | void *opaque) |
65 | { |
66 | if (mon->rs) { |
67 | readline_start(mon->rs, "Password: " , 1, readline_func, opaque); |
68 | /* prompt is printed on return from the command handler */ |
69 | return 0; |
70 | } else { |
71 | monitor_printf(&mon->common, |
72 | "terminal does not support password prompting\n" ); |
73 | return -ENOTTY; |
74 | } |
75 | } |
76 | |
77 | static int get_str(char *buf, int buf_size, const char **pp) |
78 | { |
79 | const char *p; |
80 | char *q; |
81 | int c; |
82 | |
83 | q = buf; |
84 | p = *pp; |
85 | while (qemu_isspace(*p)) { |
86 | p++; |
87 | } |
88 | if (*p == '\0') { |
89 | fail: |
90 | *q = '\0'; |
91 | *pp = p; |
92 | return -1; |
93 | } |
94 | if (*p == '\"') { |
95 | p++; |
96 | while (*p != '\0' && *p != '\"') { |
97 | if (*p == '\\') { |
98 | p++; |
99 | c = *p++; |
100 | switch (c) { |
101 | case 'n': |
102 | c = '\n'; |
103 | break; |
104 | case 'r': |
105 | c = '\r'; |
106 | break; |
107 | case '\\': |
108 | case '\'': |
109 | case '\"': |
110 | break; |
111 | default: |
112 | printf("unsupported escape code: '\\%c'\n" , c); |
113 | goto fail; |
114 | } |
115 | if ((q - buf) < buf_size - 1) { |
116 | *q++ = c; |
117 | } |
118 | } else { |
119 | if ((q - buf) < buf_size - 1) { |
120 | *q++ = *p; |
121 | } |
122 | p++; |
123 | } |
124 | } |
125 | if (*p != '\"') { |
126 | printf("unterminated string\n" ); |
127 | goto fail; |
128 | } |
129 | p++; |
130 | } else { |
131 | while (*p != '\0' && !qemu_isspace(*p)) { |
132 | if ((q - buf) < buf_size - 1) { |
133 | *q++ = *p; |
134 | } |
135 | p++; |
136 | } |
137 | } |
138 | *q = '\0'; |
139 | *pp = p; |
140 | return 0; |
141 | } |
142 | |
143 | #define MAX_ARGS 16 |
144 | |
145 | static void free_cmdline_args(char **args, int nb_args) |
146 | { |
147 | int i; |
148 | |
149 | assert(nb_args <= MAX_ARGS); |
150 | |
151 | for (i = 0; i < nb_args; i++) { |
152 | g_free(args[i]); |
153 | } |
154 | |
155 | } |
156 | |
157 | /* |
158 | * Parse the command line to get valid args. |
159 | * @cmdline: command line to be parsed. |
160 | * @pnb_args: location to store the number of args, must NOT be NULL. |
161 | * @args: location to store the args, which should be freed by caller, must |
162 | * NOT be NULL. |
163 | * |
164 | * Returns 0 on success, negative on failure. |
165 | * |
166 | * NOTE: this parser is an approximate form of the real command parser. Number |
167 | * of args have a limit of MAX_ARGS. If cmdline contains more, it will |
168 | * return with failure. |
169 | */ |
170 | static int parse_cmdline(const char *cmdline, |
171 | int *pnb_args, char **args) |
172 | { |
173 | const char *p; |
174 | int nb_args, ret; |
175 | char buf[1024]; |
176 | |
177 | p = cmdline; |
178 | nb_args = 0; |
179 | for (;;) { |
180 | while (qemu_isspace(*p)) { |
181 | p++; |
182 | } |
183 | if (*p == '\0') { |
184 | break; |
185 | } |
186 | if (nb_args >= MAX_ARGS) { |
187 | goto fail; |
188 | } |
189 | ret = get_str(buf, sizeof(buf), &p); |
190 | if (ret < 0) { |
191 | goto fail; |
192 | } |
193 | args[nb_args] = g_strdup(buf); |
194 | nb_args++; |
195 | } |
196 | *pnb_args = nb_args; |
197 | return 0; |
198 | |
199 | fail: |
200 | free_cmdline_args(args, nb_args); |
201 | return -1; |
202 | } |
203 | |
204 | /* |
205 | * Can command @cmd be executed in preconfig state? |
206 | */ |
207 | static bool cmd_can_preconfig(const HMPCommand *cmd) |
208 | { |
209 | if (!cmd->flags) { |
210 | return false; |
211 | } |
212 | |
213 | return strchr(cmd->flags, 'p'); |
214 | } |
215 | |
216 | static void help_cmd_dump_one(Monitor *mon, |
217 | const HMPCommand *cmd, |
218 | char **prefix_args, |
219 | int prefix_args_nb) |
220 | { |
221 | int i; |
222 | |
223 | if (runstate_check(RUN_STATE_PRECONFIG) && !cmd_can_preconfig(cmd)) { |
224 | return; |
225 | } |
226 | |
227 | for (i = 0; i < prefix_args_nb; i++) { |
228 | monitor_printf(mon, "%s " , prefix_args[i]); |
229 | } |
230 | monitor_printf(mon, "%s %s -- %s\n" , cmd->name, cmd->params, cmd->help); |
231 | } |
232 | |
233 | /* @args[@arg_index] is the valid command need to find in @cmds */ |
234 | static void help_cmd_dump(Monitor *mon, const HMPCommand *cmds, |
235 | char **args, int nb_args, int arg_index) |
236 | { |
237 | const HMPCommand *cmd; |
238 | size_t i; |
239 | |
240 | /* No valid arg need to compare with, dump all in *cmds */ |
241 | if (arg_index >= nb_args) { |
242 | for (cmd = cmds; cmd->name != NULL; cmd++) { |
243 | help_cmd_dump_one(mon, cmd, args, arg_index); |
244 | } |
245 | return; |
246 | } |
247 | |
248 | /* Find one entry to dump */ |
249 | for (cmd = cmds; cmd->name != NULL; cmd++) { |
250 | if (hmp_compare_cmd(args[arg_index], cmd->name) && |
251 | ((!runstate_check(RUN_STATE_PRECONFIG) || |
252 | cmd_can_preconfig(cmd)))) { |
253 | if (cmd->sub_table) { |
254 | /* continue with next arg */ |
255 | help_cmd_dump(mon, cmd->sub_table, |
256 | args, nb_args, arg_index + 1); |
257 | } else { |
258 | help_cmd_dump_one(mon, cmd, args, arg_index); |
259 | } |
260 | return; |
261 | } |
262 | } |
263 | |
264 | /* Command not found */ |
265 | monitor_printf(mon, "unknown command: '" ); |
266 | for (i = 0; i <= arg_index; i++) { |
267 | monitor_printf(mon, "%s%s" , args[i], i == arg_index ? "'\n" : " " ); |
268 | } |
269 | } |
270 | |
271 | void help_cmd(Monitor *mon, const char *name) |
272 | { |
273 | char *args[MAX_ARGS]; |
274 | int nb_args = 0; |
275 | |
276 | /* 1. parse user input */ |
277 | if (name) { |
278 | /* special case for log, directly dump and return */ |
279 | if (!strcmp(name, "log" )) { |
280 | const QEMULogItem *item; |
281 | monitor_printf(mon, "Log items (comma separated):\n" ); |
282 | monitor_printf(mon, "%-10s %s\n" , "none" , "remove all logs" ); |
283 | for (item = qemu_log_items; item->mask != 0; item++) { |
284 | monitor_printf(mon, "%-10s %s\n" , item->name, item->help); |
285 | } |
286 | return; |
287 | } |
288 | |
289 | if (parse_cmdline(name, &nb_args, args) < 0) { |
290 | return; |
291 | } |
292 | } |
293 | |
294 | /* 2. dump the contents according to parsed args */ |
295 | help_cmd_dump(mon, hmp_cmds, args, nb_args, 0); |
296 | |
297 | free_cmdline_args(args, nb_args); |
298 | } |
299 | |
300 | /*******************************************************************/ |
301 | |
302 | static const char *pch; |
303 | static sigjmp_buf expr_env; |
304 | |
305 | static void GCC_FMT_ATTR(2, 3) QEMU_NORETURN |
306 | expr_error(Monitor *mon, const char *fmt, ...) |
307 | { |
308 | va_list ap; |
309 | va_start(ap, fmt); |
310 | monitor_vprintf(mon, fmt, ap); |
311 | monitor_printf(mon, "\n" ); |
312 | va_end(ap); |
313 | siglongjmp(expr_env, 1); |
314 | } |
315 | |
316 | static void next(void) |
317 | { |
318 | if (*pch != '\0') { |
319 | pch++; |
320 | while (qemu_isspace(*pch)) { |
321 | pch++; |
322 | } |
323 | } |
324 | } |
325 | |
326 | static int64_t expr_sum(Monitor *mon); |
327 | |
328 | static int64_t expr_unary(Monitor *mon) |
329 | { |
330 | int64_t n; |
331 | char *p; |
332 | int ret; |
333 | |
334 | switch (*pch) { |
335 | case '+': |
336 | next(); |
337 | n = expr_unary(mon); |
338 | break; |
339 | case '-': |
340 | next(); |
341 | n = -expr_unary(mon); |
342 | break; |
343 | case '~': |
344 | next(); |
345 | n = ~expr_unary(mon); |
346 | break; |
347 | case '(': |
348 | next(); |
349 | n = expr_sum(mon); |
350 | if (*pch != ')') { |
351 | expr_error(mon, "')' expected" ); |
352 | } |
353 | next(); |
354 | break; |
355 | case '\'': |
356 | pch++; |
357 | if (*pch == '\0') { |
358 | expr_error(mon, "character constant expected" ); |
359 | } |
360 | n = *pch; |
361 | pch++; |
362 | if (*pch != '\'') { |
363 | expr_error(mon, "missing terminating \' character" ); |
364 | } |
365 | next(); |
366 | break; |
367 | case '$': |
368 | { |
369 | char buf[128], *q; |
370 | int64_t reg = 0; |
371 | |
372 | pch++; |
373 | q = buf; |
374 | while ((*pch >= 'a' && *pch <= 'z') || |
375 | (*pch >= 'A' && *pch <= 'Z') || |
376 | (*pch >= '0' && *pch <= '9') || |
377 | *pch == '_' || *pch == '.') { |
378 | if ((q - buf) < sizeof(buf) - 1) { |
379 | *q++ = *pch; |
380 | } |
381 | pch++; |
382 | } |
383 | while (qemu_isspace(*pch)) { |
384 | pch++; |
385 | } |
386 | *q = 0; |
387 | ret = get_monitor_def(®, buf); |
388 | if (ret < 0) { |
389 | expr_error(mon, "unknown register" ); |
390 | } |
391 | n = reg; |
392 | } |
393 | break; |
394 | case '\0': |
395 | expr_error(mon, "unexpected end of expression" ); |
396 | n = 0; |
397 | break; |
398 | default: |
399 | errno = 0; |
400 | n = strtoull(pch, &p, 0); |
401 | if (errno == ERANGE) { |
402 | expr_error(mon, "number too large" ); |
403 | } |
404 | if (pch == p) { |
405 | expr_error(mon, "invalid char '%c' in expression" , *p); |
406 | } |
407 | pch = p; |
408 | while (qemu_isspace(*pch)) { |
409 | pch++; |
410 | } |
411 | break; |
412 | } |
413 | return n; |
414 | } |
415 | |
416 | static int64_t expr_prod(Monitor *mon) |
417 | { |
418 | int64_t val, val2; |
419 | int op; |
420 | |
421 | val = expr_unary(mon); |
422 | for (;;) { |
423 | op = *pch; |
424 | if (op != '*' && op != '/' && op != '%') { |
425 | break; |
426 | } |
427 | next(); |
428 | val2 = expr_unary(mon); |
429 | switch (op) { |
430 | default: |
431 | case '*': |
432 | val *= val2; |
433 | break; |
434 | case '/': |
435 | case '%': |
436 | if (val2 == 0) { |
437 | expr_error(mon, "division by zero" ); |
438 | } |
439 | if (op == '/') { |
440 | val /= val2; |
441 | } else { |
442 | val %= val2; |
443 | } |
444 | break; |
445 | } |
446 | } |
447 | return val; |
448 | } |
449 | |
450 | static int64_t expr_logic(Monitor *mon) |
451 | { |
452 | int64_t val, val2; |
453 | int op; |
454 | |
455 | val = expr_prod(mon); |
456 | for (;;) { |
457 | op = *pch; |
458 | if (op != '&' && op != '|' && op != '^') { |
459 | break; |
460 | } |
461 | next(); |
462 | val2 = expr_prod(mon); |
463 | switch (op) { |
464 | default: |
465 | case '&': |
466 | val &= val2; |
467 | break; |
468 | case '|': |
469 | val |= val2; |
470 | break; |
471 | case '^': |
472 | val ^= val2; |
473 | break; |
474 | } |
475 | } |
476 | return val; |
477 | } |
478 | |
479 | static int64_t expr_sum(Monitor *mon) |
480 | { |
481 | int64_t val, val2; |
482 | int op; |
483 | |
484 | val = expr_logic(mon); |
485 | for (;;) { |
486 | op = *pch; |
487 | if (op != '+' && op != '-') { |
488 | break; |
489 | } |
490 | next(); |
491 | val2 = expr_logic(mon); |
492 | if (op == '+') { |
493 | val += val2; |
494 | } else { |
495 | val -= val2; |
496 | } |
497 | } |
498 | return val; |
499 | } |
500 | |
501 | static int get_expr(Monitor *mon, int64_t *pval, const char **pp) |
502 | { |
503 | pch = *pp; |
504 | if (sigsetjmp(expr_env, 0)) { |
505 | *pp = pch; |
506 | return -1; |
507 | } |
508 | while (qemu_isspace(*pch)) { |
509 | pch++; |
510 | } |
511 | *pval = expr_sum(mon); |
512 | *pp = pch; |
513 | return 0; |
514 | } |
515 | |
516 | static int get_double(Monitor *mon, double *pval, const char **pp) |
517 | { |
518 | const char *p = *pp; |
519 | char *tailp; |
520 | double d; |
521 | |
522 | d = strtod(p, &tailp); |
523 | if (tailp == p) { |
524 | monitor_printf(mon, "Number expected\n" ); |
525 | return -1; |
526 | } |
527 | if (d != d || d - d != 0) { |
528 | /* NaN or infinity */ |
529 | monitor_printf(mon, "Bad number\n" ); |
530 | return -1; |
531 | } |
532 | *pval = d; |
533 | *pp = tailp; |
534 | return 0; |
535 | } |
536 | |
537 | /* |
538 | * Store the command-name in cmdname, and return a pointer to |
539 | * the remaining of the command string. |
540 | */ |
541 | static const char *get_command_name(const char *cmdline, |
542 | char *cmdname, size_t nlen) |
543 | { |
544 | size_t len; |
545 | const char *p, *pstart; |
546 | |
547 | p = cmdline; |
548 | while (qemu_isspace(*p)) { |
549 | p++; |
550 | } |
551 | if (*p == '\0') { |
552 | return NULL; |
553 | } |
554 | pstart = p; |
555 | while (*p != '\0' && *p != '/' && !qemu_isspace(*p)) { |
556 | p++; |
557 | } |
558 | len = p - pstart; |
559 | if (len > nlen - 1) { |
560 | len = nlen - 1; |
561 | } |
562 | memcpy(cmdname, pstart, len); |
563 | cmdname[len] = '\0'; |
564 | return p; |
565 | } |
566 | |
567 | /** |
568 | * Read key of 'type' into 'key' and return the current |
569 | * 'type' pointer. |
570 | */ |
571 | static char *key_get_info(const char *type, char **key) |
572 | { |
573 | size_t len; |
574 | char *p, *str; |
575 | |
576 | if (*type == ',') { |
577 | type++; |
578 | } |
579 | |
580 | p = strchr(type, ':'); |
581 | if (!p) { |
582 | *key = NULL; |
583 | return NULL; |
584 | } |
585 | len = p - type; |
586 | |
587 | str = g_malloc(len + 1); |
588 | memcpy(str, type, len); |
589 | str[len] = '\0'; |
590 | |
591 | *key = str; |
592 | return ++p; |
593 | } |
594 | |
595 | static int default_fmt_format = 'x'; |
596 | static int default_fmt_size = 4; |
597 | |
598 | static int is_valid_option(const char *c, const char *typestr) |
599 | { |
600 | char option[3]; |
601 | |
602 | option[0] = '-'; |
603 | option[1] = *c; |
604 | option[2] = '\0'; |
605 | |
606 | typestr = strstr(typestr, option); |
607 | return (typestr != NULL); |
608 | } |
609 | |
610 | static const HMPCommand *search_dispatch_table(const HMPCommand *disp_table, |
611 | const char *cmdname) |
612 | { |
613 | const HMPCommand *cmd; |
614 | |
615 | for (cmd = disp_table; cmd->name != NULL; cmd++) { |
616 | if (hmp_compare_cmd(cmdname, cmd->name)) { |
617 | return cmd; |
618 | } |
619 | } |
620 | |
621 | return NULL; |
622 | } |
623 | |
624 | /* |
625 | * Parse command name from @cmdp according to command table @table. |
626 | * If blank, return NULL. |
627 | * Else, if no valid command can be found, report to @mon, and return |
628 | * NULL. |
629 | * Else, change @cmdp to point right behind the name, and return its |
630 | * command table entry. |
631 | * Do not assume the return value points into @table! It doesn't when |
632 | * the command is found in a sub-command table. |
633 | */ |
634 | static const HMPCommand *monitor_parse_command(MonitorHMP *hmp_mon, |
635 | const char *cmdp_start, |
636 | const char **cmdp, |
637 | HMPCommand *table) |
638 | { |
639 | Monitor *mon = &hmp_mon->common; |
640 | const char *p; |
641 | const HMPCommand *cmd; |
642 | char cmdname[256]; |
643 | |
644 | /* extract the command name */ |
645 | p = get_command_name(*cmdp, cmdname, sizeof(cmdname)); |
646 | if (!p) { |
647 | return NULL; |
648 | } |
649 | |
650 | cmd = search_dispatch_table(table, cmdname); |
651 | if (!cmd) { |
652 | monitor_printf(mon, "unknown command: '%.*s'\n" , |
653 | (int)(p - cmdp_start), cmdp_start); |
654 | return NULL; |
655 | } |
656 | if (runstate_check(RUN_STATE_PRECONFIG) && !cmd_can_preconfig(cmd)) { |
657 | monitor_printf(mon, "Command '%.*s' not available with -preconfig " |
658 | "until after exit_preconfig.\n" , |
659 | (int)(p - cmdp_start), cmdp_start); |
660 | return NULL; |
661 | } |
662 | |
663 | /* filter out following useless space */ |
664 | while (qemu_isspace(*p)) { |
665 | p++; |
666 | } |
667 | |
668 | *cmdp = p; |
669 | /* search sub command */ |
670 | if (cmd->sub_table != NULL && *p != '\0') { |
671 | return monitor_parse_command(hmp_mon, cmdp_start, cmdp, cmd->sub_table); |
672 | } |
673 | |
674 | return cmd; |
675 | } |
676 | |
677 | /* |
678 | * Parse arguments for @cmd. |
679 | * If it can't be parsed, report to @mon, and return NULL. |
680 | * Else, insert command arguments into a QDict, and return it. |
681 | * Note: On success, caller has to free the QDict structure. |
682 | */ |
683 | static QDict *monitor_parse_arguments(Monitor *mon, |
684 | const char **endp, |
685 | const HMPCommand *cmd) |
686 | { |
687 | const char *typestr; |
688 | char *key; |
689 | int c; |
690 | const char *p = *endp; |
691 | char buf[1024]; |
692 | QDict *qdict = qdict_new(); |
693 | |
694 | /* parse the parameters */ |
695 | typestr = cmd->args_type; |
696 | for (;;) { |
697 | typestr = key_get_info(typestr, &key); |
698 | if (!typestr) { |
699 | break; |
700 | } |
701 | c = *typestr; |
702 | typestr++; |
703 | switch (c) { |
704 | case 'F': |
705 | case 'B': |
706 | case 's': |
707 | { |
708 | int ret; |
709 | |
710 | while (qemu_isspace(*p)) { |
711 | p++; |
712 | } |
713 | if (*typestr == '?') { |
714 | typestr++; |
715 | if (*p == '\0') { |
716 | /* no optional string: NULL argument */ |
717 | break; |
718 | } |
719 | } |
720 | ret = get_str(buf, sizeof(buf), &p); |
721 | if (ret < 0) { |
722 | switch (c) { |
723 | case 'F': |
724 | monitor_printf(mon, "%s: filename expected\n" , |
725 | cmd->name); |
726 | break; |
727 | case 'B': |
728 | monitor_printf(mon, "%s: block device name expected\n" , |
729 | cmd->name); |
730 | break; |
731 | default: |
732 | monitor_printf(mon, "%s: string expected\n" , cmd->name); |
733 | break; |
734 | } |
735 | goto fail; |
736 | } |
737 | qdict_put_str(qdict, key, buf); |
738 | } |
739 | break; |
740 | case 'O': |
741 | { |
742 | QemuOptsList *opts_list; |
743 | QemuOpts *opts; |
744 | |
745 | opts_list = qemu_find_opts(key); |
746 | if (!opts_list || opts_list->desc->name) { |
747 | goto bad_type; |
748 | } |
749 | while (qemu_isspace(*p)) { |
750 | p++; |
751 | } |
752 | if (!*p) { |
753 | break; |
754 | } |
755 | if (get_str(buf, sizeof(buf), &p) < 0) { |
756 | goto fail; |
757 | } |
758 | opts = qemu_opts_parse_noisily(opts_list, buf, true); |
759 | if (!opts) { |
760 | goto fail; |
761 | } |
762 | qemu_opts_to_qdict(opts, qdict); |
763 | qemu_opts_del(opts); |
764 | } |
765 | break; |
766 | case '/': |
767 | { |
768 | int count, format, size; |
769 | |
770 | while (qemu_isspace(*p)) { |
771 | p++; |
772 | } |
773 | if (*p == '/') { |
774 | /* format found */ |
775 | p++; |
776 | count = 1; |
777 | if (qemu_isdigit(*p)) { |
778 | count = 0; |
779 | while (qemu_isdigit(*p)) { |
780 | count = count * 10 + (*p - '0'); |
781 | p++; |
782 | } |
783 | } |
784 | size = -1; |
785 | format = -1; |
786 | for (;;) { |
787 | switch (*p) { |
788 | case 'o': |
789 | case 'd': |
790 | case 'u': |
791 | case 'x': |
792 | case 'i': |
793 | case 'c': |
794 | format = *p++; |
795 | break; |
796 | case 'b': |
797 | size = 1; |
798 | p++; |
799 | break; |
800 | case 'h': |
801 | size = 2; |
802 | p++; |
803 | break; |
804 | case 'w': |
805 | size = 4; |
806 | p++; |
807 | break; |
808 | case 'g': |
809 | case 'L': |
810 | size = 8; |
811 | p++; |
812 | break; |
813 | default: |
814 | goto next; |
815 | } |
816 | } |
817 | next: |
818 | if (*p != '\0' && !qemu_isspace(*p)) { |
819 | monitor_printf(mon, "invalid char in format: '%c'\n" , |
820 | *p); |
821 | goto fail; |
822 | } |
823 | if (format < 0) { |
824 | format = default_fmt_format; |
825 | } |
826 | if (format != 'i') { |
827 | /* for 'i', not specifying a size gives -1 as size */ |
828 | if (size < 0) { |
829 | size = default_fmt_size; |
830 | } |
831 | default_fmt_size = size; |
832 | } |
833 | default_fmt_format = format; |
834 | } else { |
835 | count = 1; |
836 | format = default_fmt_format; |
837 | if (format != 'i') { |
838 | size = default_fmt_size; |
839 | } else { |
840 | size = -1; |
841 | } |
842 | } |
843 | qdict_put_int(qdict, "count" , count); |
844 | qdict_put_int(qdict, "format" , format); |
845 | qdict_put_int(qdict, "size" , size); |
846 | } |
847 | break; |
848 | case 'i': |
849 | case 'l': |
850 | case 'M': |
851 | { |
852 | int64_t val; |
853 | |
854 | while (qemu_isspace(*p)) { |
855 | p++; |
856 | } |
857 | if (*typestr == '?' || *typestr == '.') { |
858 | if (*typestr == '?') { |
859 | if (*p == '\0') { |
860 | typestr++; |
861 | break; |
862 | } |
863 | } else { |
864 | if (*p == '.') { |
865 | p++; |
866 | while (qemu_isspace(*p)) { |
867 | p++; |
868 | } |
869 | } else { |
870 | typestr++; |
871 | break; |
872 | } |
873 | } |
874 | typestr++; |
875 | } |
876 | if (get_expr(mon, &val, &p)) { |
877 | goto fail; |
878 | } |
879 | /* Check if 'i' is greater than 32-bit */ |
880 | if ((c == 'i') && ((val >> 32) & 0xffffffff)) { |
881 | monitor_printf(mon, "\'%s\' has failed: " , cmd->name); |
882 | monitor_printf(mon, "integer is for 32-bit values\n" ); |
883 | goto fail; |
884 | } else if (c == 'M') { |
885 | if (val < 0) { |
886 | monitor_printf(mon, "enter a positive value\n" ); |
887 | goto fail; |
888 | } |
889 | val *= MiB; |
890 | } |
891 | qdict_put_int(qdict, key, val); |
892 | } |
893 | break; |
894 | case 'o': |
895 | { |
896 | int ret; |
897 | uint64_t val; |
898 | const char *end; |
899 | |
900 | while (qemu_isspace(*p)) { |
901 | p++; |
902 | } |
903 | if (*typestr == '?') { |
904 | typestr++; |
905 | if (*p == '\0') { |
906 | break; |
907 | } |
908 | } |
909 | ret = qemu_strtosz_MiB(p, &end, &val); |
910 | if (ret < 0 || val > INT64_MAX) { |
911 | monitor_printf(mon, "invalid size\n" ); |
912 | goto fail; |
913 | } |
914 | qdict_put_int(qdict, key, val); |
915 | p = end; |
916 | } |
917 | break; |
918 | case 'T': |
919 | { |
920 | double val; |
921 | |
922 | while (qemu_isspace(*p)) { |
923 | p++; |
924 | } |
925 | if (*typestr == '?') { |
926 | typestr++; |
927 | if (*p == '\0') { |
928 | break; |
929 | } |
930 | } |
931 | if (get_double(mon, &val, &p) < 0) { |
932 | goto fail; |
933 | } |
934 | if (p[0] && p[1] == 's') { |
935 | switch (*p) { |
936 | case 'm': |
937 | val /= 1e3; p += 2; break; |
938 | case 'u': |
939 | val /= 1e6; p += 2; break; |
940 | case 'n': |
941 | val /= 1e9; p += 2; break; |
942 | } |
943 | } |
944 | if (*p && !qemu_isspace(*p)) { |
945 | monitor_printf(mon, "Unknown unit suffix\n" ); |
946 | goto fail; |
947 | } |
948 | qdict_put(qdict, key, qnum_from_double(val)); |
949 | } |
950 | break; |
951 | case 'b': |
952 | { |
953 | const char *beg; |
954 | bool val; |
955 | |
956 | while (qemu_isspace(*p)) { |
957 | p++; |
958 | } |
959 | beg = p; |
960 | while (qemu_isgraph(*p)) { |
961 | p++; |
962 | } |
963 | if (p - beg == 2 && !memcmp(beg, "on" , p - beg)) { |
964 | val = true; |
965 | } else if (p - beg == 3 && !memcmp(beg, "off" , p - beg)) { |
966 | val = false; |
967 | } else { |
968 | monitor_printf(mon, "Expected 'on' or 'off'\n" ); |
969 | goto fail; |
970 | } |
971 | qdict_put_bool(qdict, key, val); |
972 | } |
973 | break; |
974 | case '-': |
975 | { |
976 | const char *tmp = p; |
977 | int skip_key = 0; |
978 | /* option */ |
979 | |
980 | c = *typestr++; |
981 | if (c == '\0') { |
982 | goto bad_type; |
983 | } |
984 | while (qemu_isspace(*p)) { |
985 | p++; |
986 | } |
987 | if (*p == '-') { |
988 | p++; |
989 | if (c != *p) { |
990 | if (!is_valid_option(p, typestr)) { |
991 | monitor_printf(mon, "%s: unsupported option -%c\n" , |
992 | cmd->name, *p); |
993 | goto fail; |
994 | } else { |
995 | skip_key = 1; |
996 | } |
997 | } |
998 | if (skip_key) { |
999 | p = tmp; |
1000 | } else { |
1001 | /* has option */ |
1002 | p++; |
1003 | qdict_put_bool(qdict, key, true); |
1004 | } |
1005 | } |
1006 | } |
1007 | break; |
1008 | case 'S': |
1009 | { |
1010 | /* package all remaining string */ |
1011 | int len; |
1012 | |
1013 | while (qemu_isspace(*p)) { |
1014 | p++; |
1015 | } |
1016 | if (*typestr == '?') { |
1017 | typestr++; |
1018 | if (*p == '\0') { |
1019 | /* no remaining string: NULL argument */ |
1020 | break; |
1021 | } |
1022 | } |
1023 | len = strlen(p); |
1024 | if (len <= 0) { |
1025 | monitor_printf(mon, "%s: string expected\n" , |
1026 | cmd->name); |
1027 | goto fail; |
1028 | } |
1029 | qdict_put_str(qdict, key, p); |
1030 | p += len; |
1031 | } |
1032 | break; |
1033 | default: |
1034 | bad_type: |
1035 | monitor_printf(mon, "%s: unknown type '%c'\n" , cmd->name, c); |
1036 | goto fail; |
1037 | } |
1038 | g_free(key); |
1039 | key = NULL; |
1040 | } |
1041 | /* check that all arguments were parsed */ |
1042 | while (qemu_isspace(*p)) { |
1043 | p++; |
1044 | } |
1045 | if (*p != '\0') { |
1046 | monitor_printf(mon, "%s: extraneous characters at the end of line\n" , |
1047 | cmd->name); |
1048 | goto fail; |
1049 | } |
1050 | |
1051 | return qdict; |
1052 | |
1053 | fail: |
1054 | qobject_unref(qdict); |
1055 | g_free(key); |
1056 | return NULL; |
1057 | } |
1058 | |
1059 | void handle_hmp_command(MonitorHMP *mon, const char *cmdline) |
1060 | { |
1061 | QDict *qdict; |
1062 | const HMPCommand *cmd; |
1063 | const char *cmd_start = cmdline; |
1064 | |
1065 | trace_handle_hmp_command(mon, cmdline); |
1066 | |
1067 | cmd = monitor_parse_command(mon, cmdline, &cmdline, hmp_cmds); |
1068 | if (!cmd) { |
1069 | return; |
1070 | } |
1071 | |
1072 | qdict = monitor_parse_arguments(&mon->common, &cmdline, cmd); |
1073 | if (!qdict) { |
1074 | while (cmdline > cmd_start && qemu_isspace(cmdline[-1])) { |
1075 | cmdline--; |
1076 | } |
1077 | monitor_printf(&mon->common, "Try \"help %.*s\" for more information\n" , |
1078 | (int)(cmdline - cmd_start), cmd_start); |
1079 | return; |
1080 | } |
1081 | |
1082 | cmd->cmd(&mon->common, qdict); |
1083 | qobject_unref(qdict); |
1084 | } |
1085 | |
1086 | static void cmd_completion(MonitorHMP *mon, const char *name, const char *list) |
1087 | { |
1088 | const char *p, *pstart; |
1089 | char cmd[128]; |
1090 | int len; |
1091 | |
1092 | p = list; |
1093 | for (;;) { |
1094 | pstart = p; |
1095 | p = qemu_strchrnul(p, '|'); |
1096 | len = p - pstart; |
1097 | if (len > sizeof(cmd) - 2) { |
1098 | len = sizeof(cmd) - 2; |
1099 | } |
1100 | memcpy(cmd, pstart, len); |
1101 | cmd[len] = '\0'; |
1102 | if (name[0] == '\0' || !strncmp(name, cmd, strlen(name))) { |
1103 | readline_add_completion(mon->rs, cmd); |
1104 | } |
1105 | if (*p == '\0') { |
1106 | break; |
1107 | } |
1108 | p++; |
1109 | } |
1110 | } |
1111 | |
1112 | static void file_completion(MonitorHMP *mon, const char *input) |
1113 | { |
1114 | DIR *ffs; |
1115 | struct dirent *d; |
1116 | char path[1024]; |
1117 | char file[1024], file_prefix[1024]; |
1118 | int input_path_len; |
1119 | const char *p; |
1120 | |
1121 | p = strrchr(input, '/'); |
1122 | if (!p) { |
1123 | input_path_len = 0; |
1124 | pstrcpy(file_prefix, sizeof(file_prefix), input); |
1125 | pstrcpy(path, sizeof(path), "." ); |
1126 | } else { |
1127 | input_path_len = p - input + 1; |
1128 | memcpy(path, input, input_path_len); |
1129 | if (input_path_len > sizeof(path) - 1) { |
1130 | input_path_len = sizeof(path) - 1; |
1131 | } |
1132 | path[input_path_len] = '\0'; |
1133 | pstrcpy(file_prefix, sizeof(file_prefix), p + 1); |
1134 | } |
1135 | |
1136 | ffs = opendir(path); |
1137 | if (!ffs) { |
1138 | return; |
1139 | } |
1140 | for (;;) { |
1141 | struct stat sb; |
1142 | d = readdir(ffs); |
1143 | if (!d) { |
1144 | break; |
1145 | } |
1146 | |
1147 | if (strcmp(d->d_name, "." ) == 0 || strcmp(d->d_name, ".." ) == 0) { |
1148 | continue; |
1149 | } |
1150 | |
1151 | if (strstart(d->d_name, file_prefix, NULL)) { |
1152 | memcpy(file, input, input_path_len); |
1153 | if (input_path_len < sizeof(file)) { |
1154 | pstrcpy(file + input_path_len, sizeof(file) - input_path_len, |
1155 | d->d_name); |
1156 | } |
1157 | /* |
1158 | * stat the file to find out if it's a directory. |
1159 | * In that case add a slash to speed up typing long paths |
1160 | */ |
1161 | if (stat(file, &sb) == 0 && S_ISDIR(sb.st_mode)) { |
1162 | pstrcat(file, sizeof(file), "/" ); |
1163 | } |
1164 | readline_add_completion(mon->rs, file); |
1165 | } |
1166 | } |
1167 | closedir(ffs); |
1168 | } |
1169 | |
1170 | static const char *next_arg_type(const char *typestr) |
1171 | { |
1172 | const char *p = strchr(typestr, ':'); |
1173 | return (p != NULL ? ++p : typestr); |
1174 | } |
1175 | |
1176 | static void monitor_find_completion_by_table(MonitorHMP *mon, |
1177 | const HMPCommand *cmd_table, |
1178 | char **args, |
1179 | int nb_args) |
1180 | { |
1181 | const char *cmdname; |
1182 | int i; |
1183 | const char *ptype, *old_ptype, *str, *name; |
1184 | const HMPCommand *cmd; |
1185 | BlockBackend *blk = NULL; |
1186 | |
1187 | if (nb_args <= 1) { |
1188 | /* command completion */ |
1189 | if (nb_args == 0) { |
1190 | cmdname = "" ; |
1191 | } else { |
1192 | cmdname = args[0]; |
1193 | } |
1194 | readline_set_completion_index(mon->rs, strlen(cmdname)); |
1195 | for (cmd = cmd_table; cmd->name != NULL; cmd++) { |
1196 | if (!runstate_check(RUN_STATE_PRECONFIG) || |
1197 | cmd_can_preconfig(cmd)) { |
1198 | cmd_completion(mon, cmdname, cmd->name); |
1199 | } |
1200 | } |
1201 | } else { |
1202 | /* find the command */ |
1203 | for (cmd = cmd_table; cmd->name != NULL; cmd++) { |
1204 | if (hmp_compare_cmd(args[0], cmd->name) && |
1205 | (!runstate_check(RUN_STATE_PRECONFIG) || |
1206 | cmd_can_preconfig(cmd))) { |
1207 | break; |
1208 | } |
1209 | } |
1210 | if (!cmd->name) { |
1211 | return; |
1212 | } |
1213 | |
1214 | if (cmd->sub_table) { |
1215 | /* do the job again */ |
1216 | monitor_find_completion_by_table(mon, cmd->sub_table, |
1217 | &args[1], nb_args - 1); |
1218 | return; |
1219 | } |
1220 | if (cmd->command_completion) { |
1221 | cmd->command_completion(mon->rs, nb_args, args[nb_args - 1]); |
1222 | return; |
1223 | } |
1224 | |
1225 | ptype = next_arg_type(cmd->args_type); |
1226 | for (i = 0; i < nb_args - 2; i++) { |
1227 | if (*ptype != '\0') { |
1228 | ptype = next_arg_type(ptype); |
1229 | while (*ptype == '?') { |
1230 | ptype = next_arg_type(ptype); |
1231 | } |
1232 | } |
1233 | } |
1234 | str = args[nb_args - 1]; |
1235 | old_ptype = NULL; |
1236 | while (*ptype == '-' && old_ptype != ptype) { |
1237 | old_ptype = ptype; |
1238 | ptype = next_arg_type(ptype); |
1239 | } |
1240 | switch (*ptype) { |
1241 | case 'F': |
1242 | /* file completion */ |
1243 | readline_set_completion_index(mon->rs, strlen(str)); |
1244 | file_completion(mon, str); |
1245 | break; |
1246 | case 'B': |
1247 | /* block device name completion */ |
1248 | readline_set_completion_index(mon->rs, strlen(str)); |
1249 | while ((blk = blk_next(blk)) != NULL) { |
1250 | name = blk_name(blk); |
1251 | if (str[0] == '\0' || |
1252 | !strncmp(name, str, strlen(str))) { |
1253 | readline_add_completion(mon->rs, name); |
1254 | } |
1255 | } |
1256 | break; |
1257 | case 's': |
1258 | case 'S': |
1259 | if (!strcmp(cmd->name, "help|?" )) { |
1260 | monitor_find_completion_by_table(mon, cmd_table, |
1261 | &args[1], nb_args - 1); |
1262 | } |
1263 | break; |
1264 | default: |
1265 | break; |
1266 | } |
1267 | } |
1268 | } |
1269 | |
1270 | static void monitor_find_completion(void *opaque, |
1271 | const char *cmdline) |
1272 | { |
1273 | MonitorHMP *mon = opaque; |
1274 | char *args[MAX_ARGS]; |
1275 | int nb_args, len; |
1276 | |
1277 | /* 1. parse the cmdline */ |
1278 | if (parse_cmdline(cmdline, &nb_args, args) < 0) { |
1279 | return; |
1280 | } |
1281 | |
1282 | /* |
1283 | * if the line ends with a space, it means we want to complete the |
1284 | * next arg |
1285 | */ |
1286 | len = strlen(cmdline); |
1287 | if (len > 0 && qemu_isspace(cmdline[len - 1])) { |
1288 | if (nb_args >= MAX_ARGS) { |
1289 | goto cleanup; |
1290 | } |
1291 | args[nb_args++] = g_strdup("" ); |
1292 | } |
1293 | |
1294 | /* 2. auto complete according to args */ |
1295 | monitor_find_completion_by_table(mon, hmp_cmds, args, nb_args); |
1296 | |
1297 | cleanup: |
1298 | free_cmdline_args(args, nb_args); |
1299 | } |
1300 | |
1301 | static void monitor_read(void *opaque, const uint8_t *buf, int size) |
1302 | { |
1303 | MonitorHMP *mon; |
1304 | Monitor *old_mon = cur_mon; |
1305 | int i; |
1306 | |
1307 | cur_mon = opaque; |
1308 | mon = container_of(cur_mon, MonitorHMP, common); |
1309 | |
1310 | if (mon->rs) { |
1311 | for (i = 0; i < size; i++) { |
1312 | readline_handle_byte(mon->rs, buf[i]); |
1313 | } |
1314 | } else { |
1315 | if (size == 0 || buf[size - 1] != 0) { |
1316 | monitor_printf(cur_mon, "corrupted command\n" ); |
1317 | } else { |
1318 | handle_hmp_command(mon, (char *)buf); |
1319 | } |
1320 | } |
1321 | |
1322 | cur_mon = old_mon; |
1323 | } |
1324 | |
1325 | static void monitor_event(void *opaque, int event) |
1326 | { |
1327 | Monitor *mon = opaque; |
1328 | MonitorHMP *hmp_mon = container_of(mon, MonitorHMP, common); |
1329 | |
1330 | switch (event) { |
1331 | case CHR_EVENT_MUX_IN: |
1332 | qemu_mutex_lock(&mon->mon_lock); |
1333 | mon->mux_out = 0; |
1334 | qemu_mutex_unlock(&mon->mon_lock); |
1335 | if (mon->reset_seen) { |
1336 | readline_restart(hmp_mon->rs); |
1337 | monitor_resume(mon); |
1338 | monitor_flush(mon); |
1339 | } else { |
1340 | atomic_mb_set(&mon->suspend_cnt, 0); |
1341 | } |
1342 | break; |
1343 | |
1344 | case CHR_EVENT_MUX_OUT: |
1345 | if (mon->reset_seen) { |
1346 | if (atomic_mb_read(&mon->suspend_cnt) == 0) { |
1347 | monitor_printf(mon, "\n" ); |
1348 | } |
1349 | monitor_flush(mon); |
1350 | monitor_suspend(mon); |
1351 | } else { |
1352 | atomic_inc(&mon->suspend_cnt); |
1353 | } |
1354 | qemu_mutex_lock(&mon->mon_lock); |
1355 | mon->mux_out = 1; |
1356 | qemu_mutex_unlock(&mon->mon_lock); |
1357 | break; |
1358 | |
1359 | case CHR_EVENT_OPENED: |
1360 | monitor_printf(mon, "QEMU %s monitor - type 'help' for more " |
1361 | "information\n" , QEMU_VERSION); |
1362 | if (!mon->mux_out) { |
1363 | readline_restart(hmp_mon->rs); |
1364 | readline_show_prompt(hmp_mon->rs); |
1365 | } |
1366 | mon->reset_seen = 1; |
1367 | mon_refcount++; |
1368 | break; |
1369 | |
1370 | case CHR_EVENT_CLOSED: |
1371 | mon_refcount--; |
1372 | monitor_fdsets_cleanup(); |
1373 | break; |
1374 | } |
1375 | } |
1376 | |
1377 | |
1378 | /* |
1379 | * These functions just adapt the readline interface in a typesafe way. We |
1380 | * could cast function pointers but that discards compiler checks. |
1381 | */ |
1382 | static void GCC_FMT_ATTR(2, 3) monitor_readline_printf(void *opaque, |
1383 | const char *fmt, ...) |
1384 | { |
1385 | MonitorHMP *mon = opaque; |
1386 | va_list ap; |
1387 | va_start(ap, fmt); |
1388 | monitor_vprintf(&mon->common, fmt, ap); |
1389 | va_end(ap); |
1390 | } |
1391 | |
1392 | static void monitor_readline_flush(void *opaque) |
1393 | { |
1394 | MonitorHMP *mon = opaque; |
1395 | monitor_flush(&mon->common); |
1396 | } |
1397 | |
1398 | void monitor_init_hmp(Chardev *chr, bool use_readline) |
1399 | { |
1400 | MonitorHMP *mon = g_new0(MonitorHMP, 1); |
1401 | |
1402 | monitor_data_init(&mon->common, false, false, false); |
1403 | qemu_chr_fe_init(&mon->common.chr, chr, &error_abort); |
1404 | |
1405 | mon->use_readline = use_readline; |
1406 | if (mon->use_readline) { |
1407 | mon->rs = readline_init(monitor_readline_printf, |
1408 | monitor_readline_flush, |
1409 | mon, |
1410 | monitor_find_completion); |
1411 | monitor_read_command(mon, 0); |
1412 | } |
1413 | |
1414 | qemu_chr_fe_set_handlers(&mon->common.chr, monitor_can_read, monitor_read, |
1415 | monitor_event, NULL, &mon->common, NULL, true); |
1416 | monitor_list_append(&mon->common); |
1417 | } |
1418 | |