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