ia64/xen-unstable

view tools/ioemu/monitor.c @ 7238:971e7c7411b3

Raise an exception if an error appears on the pipes to our children, and make
sure that the child's pipes are closed even under that exception. Move the
handling of POLLHUP to the end of the loop, so that we guarantee to read any
remaining data from the child if POLLHUP and POLLIN appear at the same time.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author emellor@ewan
date Thu Oct 06 10:13:11 2005 +0100 (2005-10-06)
parents 06d84bf87159
children 349d7b4ef7b0
line source
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 #include "vl.h"
25 #include <dirent.h>
27 //#define DEBUG
28 //#define DEBUG_COMPLETION
30 #ifndef offsetof
31 #define offsetof(type, field) ((size_t) &((type *)0)->field)
32 #endif
34 /*
35 * Supported types:
36 *
37 * 'F' filename
38 * 'B' block device name
39 * 's' string (accept optional quote)
40 * 'i' integer
41 * '/' optional gdb-like print format (like "/10x")
42 *
43 * '?' optional type (for 'F', 's' and 'i')
44 *
45 */
47 typedef struct term_cmd_t {
48 const char *name;
49 const char *args_type;
50 void (*handler)();
51 const char *params;
52 const char *help;
53 } term_cmd_t;
55 static CharDriverState *monitor_hd;
57 static term_cmd_t term_cmds[];
58 static term_cmd_t info_cmds[];
60 static char term_outbuf[1024];
61 static int term_outbuf_index;
63 static void monitor_start_input(void);
65 void term_flush(void)
66 {
67 if (term_outbuf_index > 0) {
68 if(monitor_hd)
69 qemu_chr_write(monitor_hd, term_outbuf, term_outbuf_index);
70 else
71 fwrite(term_outbuf, term_outbuf_index, 1, stderr);
72 term_outbuf_index = 0;
73 }
74 }
76 /* flush at every end of line or if the buffer is full */
77 void term_puts(const char *str)
78 {
79 int c;
80 for(;;) {
81 c = *str++;
82 if (c == '\0')
83 break;
84 term_outbuf[term_outbuf_index++] = c;
85 if (term_outbuf_index >= sizeof(term_outbuf) ||
86 c == '\n')
87 term_flush();
88 }
89 }
91 void term_vprintf(const char *fmt, va_list ap)
92 {
93 char buf[4096];
94 vsnprintf(buf, sizeof(buf), fmt, ap);
95 term_puts(buf);
96 }
98 void term_printf(const char *fmt, ...)
99 {
100 va_list ap;
101 va_start(ap, fmt);
102 term_vprintf(fmt, ap);
103 va_end(ap);
104 }
106 static int compare_cmd(const char *name, const char *list)
107 {
108 const char *p, *pstart;
109 int len;
110 len = strlen(name);
111 p = list;
112 for(;;) {
113 pstart = p;
114 p = strchr(p, '|');
115 if (!p)
116 p = pstart + strlen(pstart);
117 if ((p - pstart) == len && !memcmp(pstart, name, len))
118 return 1;
119 if (*p == '\0')
120 break;
121 p++;
122 }
123 return 0;
124 }
126 static void help_cmd1(term_cmd_t *cmds, const char *prefix, const char *name)
127 {
128 term_cmd_t *cmd;
130 for(cmd = cmds; cmd->name != NULL; cmd++) {
131 if (!name || !strcmp(name, cmd->name))
132 term_printf("%s%s %s -- %s\n", prefix, cmd->name, cmd->params, cmd->help);
133 }
134 }
136 static void help_cmd(const char *name)
137 {
138 if (name && !strcmp(name, "info")) {
139 help_cmd1(info_cmds, "info ", NULL);
140 } else {
141 help_cmd1(term_cmds, "", name);
142 if (name && !strcmp(name, "log")) {
143 CPULogItem *item;
144 term_printf("Log items (comma separated):\n");
145 term_printf("%-10s %s\n", "none", "remove all logs");
146 for(item = cpu_log_items; item->mask != 0; item++) {
147 term_printf("%-10s %s\n", item->name, item->help);
148 }
149 }
150 }
151 }
153 static void do_help(const char *name)
154 {
155 help_cmd(name);
156 }
158 static void do_commit(void)
159 {
160 int i;
162 for (i = 0; i < MAX_DISKS; i++) {
163 if (bs_table[i]) {
164 bdrv_commit(bs_table[i]);
165 }
166 }
167 }
169 static void do_info(const char *item)
170 {
171 term_cmd_t *cmd;
173 if (!item)
174 goto help;
175 for(cmd = info_cmds; cmd->name != NULL; cmd++) {
176 if (compare_cmd(item, cmd->name))
177 goto found;
178 }
179 help:
180 help_cmd("info");
181 return;
182 found:
183 cmd->handler();
184 }
186 static void do_info_version(void)
187 {
188 term_printf("%s\n", QEMU_VERSION);
189 }
191 static void do_info_network(void)
192 {
193 int i, j;
194 NetDriverState *nd;
196 for(i = 0; i < nb_nics; i++) {
197 nd = &nd_table[i];
198 term_printf("%d: ifname=%s macaddr=", i, nd->ifname);
199 for(j = 0; j < 6; j++) {
200 if (j > 0)
201 term_printf(":");
202 term_printf("%02x", nd->macaddr[j]);
203 }
204 term_printf("\n");
205 }
206 }
208 static void do_info_block(void)
209 {
210 bdrv_info();
211 }
213 static void do_info_history (void)
214 {
215 int i;
216 const char *str;
218 i = 0;
219 for(;;) {
220 str = readline_get_history(i);
221 if (!str)
222 break;
223 term_printf("%d: '%s'\n", i, str);
224 i++;
225 }
226 }
228 extern void destroy_vmx_domain(void);
229 static void do_quit(void)
230 {
231 destroy_vmx_domain();
232 exit(0);
233 }
235 static int eject_device(BlockDriverState *bs, int force)
236 {
237 if (bdrv_is_inserted(bs)) {
238 if (!force) {
239 if (!bdrv_is_removable(bs)) {
240 term_printf("device is not removable\n");
241 return -1;
242 }
243 if (bdrv_is_locked(bs)) {
244 term_printf("device is locked\n");
245 return -1;
246 }
247 }
248 bdrv_close(bs);
249 }
250 return 0;
251 }
253 static void do_eject(int force, const char *filename)
254 {
255 BlockDriverState *bs;
257 bs = bdrv_find(filename);
258 if (!bs) {
259 term_printf("device not found\n");
260 return;
261 }
262 eject_device(bs, force);
263 }
265 static void do_change(const char *device, const char *filename)
266 {
267 BlockDriverState *bs;
268 #if 0
269 int i;
270 char password[256];
271 #endif
273 bs = bdrv_find(device);
274 if (!bs) {
275 term_printf("device not found\n");
276 return;
277 }
278 if (eject_device(bs, 0) < 0)
279 return;
280 bdrv_open(bs, filename, 0);
281 #if 0
282 if (bdrv_is_encrypted(bs)) {
283 term_printf("%s is encrypted.\n", device);
284 for(i = 0; i < 3; i++) {
285 monitor_readline("Password: ", 1, password, sizeof(password));
286 if (bdrv_set_key(bs, password) == 0)
287 break;
288 term_printf("invalid password\n");
289 }
290 }
291 #endif
292 }
294 static void do_screen_dump(const char *filename)
295 {
296 vga_screen_dump(filename);
297 }
299 static void do_log(const char *items)
300 {
301 int mask;
303 if (!strcmp(items, "none")) {
304 mask = 0;
305 } else {
306 mask = cpu_str_to_log_mask(items);
307 if (!mask) {
308 help_cmd("log");
309 return;
310 }
311 }
312 cpu_set_log(mask);
313 }
315 static term_cmd_t term_cmds[] = {
316 { "help|?", "s?", do_help,
317 "[cmd]", "show the help" },
318 { "commit", "", do_commit,
319 "", "commit changes to the disk images (if -snapshot is used)" },
320 { "info", "s?", do_info,
321 "subcommand", "show various information about the system state" },
322 { "q|quit", "", do_quit,
323 "", "quit the emulator" },
324 { "eject", "-fB", do_eject,
325 "[-f] device", "eject a removable media (use -f to force it)" },
326 { "change", "BF", do_change,
327 "device filename", "change a removable media" },
328 { "screendump", "F", do_screen_dump,
329 "filename", "save screen into PPM image 'filename'" },
330 { "log", "s", do_log,
331 "item1[,...]", "activate logging of the specified items to '/tmp/qemu.log'" },
332 { "q|quit", "", do_quit,
333 "", "quit the emulator" },
334 { NULL, NULL, },
335 };
337 static term_cmd_t info_cmds[] = {
338 { "version", "", do_info_version,
339 "", "show the version of qemu" },
340 { "network", "", do_info_network,
341 "", "show the network state" },
342 { "block", "", do_info_block,
343 "", "show the block devices" },
344 { "history", "", do_info_history,
345 "", "show the command line history", },
346 { "irq", "", irq_info,
347 "", "show the interrupts statistics (if available)", },
348 { "pic", "", pic_info,
349 "", "show i8259 (PIC) state", },
350 { "pci", "", pci_info,
351 "", "show PCI info", },
352 { "vmxiopage", "", sp_info,
353 "", "show VMX device model shared page info", },
354 { NULL, NULL, },
355 };
357 static int get_str(char *buf, int buf_size, const char **pp)
358 {
359 const char *p;
360 char *q;
361 int c;
363 q = buf;
364 p = *pp;
365 while (isspace(*p))
366 p++;
367 if (*p == '\0') {
368 fail:
369 *q = '\0';
370 *pp = p;
371 return -1;
372 }
373 if (*p == '\"') {
374 p++;
375 while (*p != '\0' && *p != '\"') {
376 if (*p == '\\') {
377 p++;
378 c = *p++;
379 switch(c) {
380 case 'n':
381 c = '\n';
382 break;
383 case 'r':
384 c = '\r';
385 break;
386 case '\\':
387 case '\'':
388 case '\"':
389 break;
390 default:
391 qemu_printf("unsupported escape code: '\\%c'\n", c);
392 goto fail;
393 }
394 if ((q - buf) < buf_size - 1) {
395 *q++ = c;
396 }
397 } else {
398 if ((q - buf) < buf_size - 1) {
399 *q++ = *p;
400 }
401 p++;
402 }
403 }
404 if (*p != '\"') {
405 qemu_printf("unterminated string\n");
406 goto fail;
407 }
408 p++;
409 } else {
410 while (*p != '\0' && !isspace(*p)) {
411 if ((q - buf) < buf_size - 1) {
412 *q++ = *p;
413 }
414 p++;
415 }
416 }
417 *q = '\0';
418 *pp = p;
419 return 0;
420 }
422 #define MAX_ARGS 16
424 static void monitor_handle_command(const char *cmdline)
425 {
426 const char *p, *pstart, *typestr;
427 char *q;
428 int c, nb_args, len, i;
429 term_cmd_t *cmd;
430 char cmdname[256];
431 char buf[1024];
432 void *str_allocated[MAX_ARGS];
433 void *args[MAX_ARGS];
435 #ifdef DEBUG
436 term_printf("command='%s'\n", cmdline);
437 #endif
439 /* extract the command name */
440 p = cmdline;
441 q = cmdname;
442 while (isspace(*p))
443 p++;
444 if (*p == '\0')
445 return;
446 pstart = p;
447 while (*p != '\0' && *p != '/' && !isspace(*p))
448 p++;
449 len = p - pstart;
450 if (len > sizeof(cmdname) - 1)
451 len = sizeof(cmdname) - 1;
452 memcpy(cmdname, pstart, len);
453 cmdname[len] = '\0';
455 /* find the command */
456 for(cmd = term_cmds; cmd->name != NULL; cmd++) {
457 if (compare_cmd(cmdname, cmd->name))
458 goto found;
459 }
460 term_printf("unknown command: '%s'\n", cmdname);
461 return;
462 found:
464 for(i = 0; i < MAX_ARGS; i++)
465 str_allocated[i] = NULL;
467 /* parse the parameters */
468 typestr = cmd->args_type;
469 nb_args = 0;
470 for(;;) {
471 c = *typestr;
472 if (c == '\0')
473 break;
474 typestr++;
475 switch(c) {
476 case 'F':
477 case 'B':
478 case 's':
479 {
480 int ret;
481 char *str;
483 while (isspace(*p))
484 p++;
485 if (*typestr == '?') {
486 typestr++;
487 if (*p == '\0') {
488 /* no optional string: NULL argument */
489 str = NULL;
490 goto add_str;
491 }
492 }
493 ret = get_str(buf, sizeof(buf), &p);
494 if (ret < 0) {
495 switch(c) {
496 case 'F':
497 term_printf("%s: filename expected\n", cmdname);
498 break;
499 case 'B':
500 term_printf("%s: block device name expected\n", cmdname);
501 break;
502 default:
503 term_printf("%s: string expected\n", cmdname);
504 break;
505 }
506 goto fail;
507 }
508 str = qemu_malloc(strlen(buf) + 1);
509 strcpy(str, buf);
510 str_allocated[nb_args] = str;
511 add_str:
512 if (nb_args >= MAX_ARGS) {
513 error_args:
514 term_printf("%s: too many arguments\n", cmdname);
515 goto fail;
516 }
517 args[nb_args++] = str;
518 }
519 break;
520 case '-':
521 {
522 int has_option;
523 /* option */
525 c = *typestr++;
526 if (c == '\0')
527 goto bad_type;
528 while (isspace(*p))
529 p++;
530 has_option = 0;
531 if (*p == '-') {
532 p++;
533 if (*p != c) {
534 term_printf("%s: unsupported option -%c\n",
535 cmdname, *p);
536 goto fail;
537 }
538 p++;
539 has_option = 1;
540 }
541 if (nb_args >= MAX_ARGS)
542 goto error_args;
543 args[nb_args++] = (void *)has_option;
544 }
545 break;
546 /* TODO: add more commands we need here to support vmx device model */
547 case '/':
548 case 'i':
549 default:
550 bad_type:
551 term_printf("%s: unknown type '%c',not support now.\n", cmdname, c);
552 goto fail;
553 }
554 }
555 /* check that all arguments were parsed */
556 while (isspace(*p))
557 p++;
558 if (*p != '\0') {
559 term_printf("%s: extraneous characters at the end of line\n",
560 cmdname);
561 goto fail;
562 }
564 switch(nb_args) {
565 case 0:
566 cmd->handler();
567 break;
568 case 1:
569 cmd->handler(args[0]);
570 break;
571 case 2:
572 cmd->handler(args[0], args[1]);
573 break;
574 case 3:
575 cmd->handler(args[0], args[1], args[2]);
576 break;
577 case 4:
578 cmd->handler(args[0], args[1], args[2], args[3]);
579 break;
580 case 5:
581 cmd->handler(args[0], args[1], args[2], args[3], args[4]);
582 break;
583 case 6:
584 cmd->handler(args[0], args[1], args[2], args[3], args[4], args[5]);
585 break;
586 default:
587 term_printf("unsupported number of arguments: %d\n", nb_args);
588 goto fail;
589 }
590 fail:
591 for(i = 0; i < MAX_ARGS; i++)
592 qemu_free(str_allocated[i]);
593 return;
594 }
596 static int term_can_read(void *opaque)
597 {
598 return 128;
599 }
601 static void term_read(void *opaque, const uint8_t *buf, int size)
602 {
603 int i;
604 for(i = 0; i < size; i++)
605 readline_handle_byte(buf[i]);
606 }
608 static void monitor_start_input(void);
610 static void monitor_handle_command1(void *opaque, const char *cmdline)
611 {
612 monitor_handle_command(cmdline);
613 monitor_start_input();
614 }
616 static void monitor_start_input(void)
617 {
618 readline_start("(VTXen) ", 0, monitor_handle_command1, NULL);
619 }
621 void monitor_init(CharDriverState *hd, int show_banner)
622 {
623 monitor_hd = hd;
624 if (show_banner) {
625 term_printf("VMX device model. type 'q' to exit\n");
626 }
627 qemu_chr_add_read_handler(hd, term_can_read, term_read, NULL);
628 monitor_start_input();
629 }