]> git.proxmox.com Git - qemu.git/blame - monitor.c
win32 port (Kazu)
[qemu.git] / monitor.c
CommitLineData
9dc39cba
FB
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 */
9dc39cba
FB
24#include "vl.h"
25
26//#define DEBUG
27
28#define TERM_CMD_BUF_SIZE 4095
29#define MAX_ARGS 64
30
31#define IS_NORM 0
32#define IS_ESC 1
33#define IS_CSI 2
34
35#define printf do_not_use_printf
36
37static char term_cmd_buf[TERM_CMD_BUF_SIZE + 1];
38static int term_cmd_buf_index;
39static int term_cmd_buf_size;
40static int term_esc_state;
41static int term_esc_param;
42
43typedef struct term_cmd_t {
44 const char *name;
45 void (*handler)(int argc, const char **argv);
46 const char *params;
47 const char *help;
48} term_cmd_t;
49
50static term_cmd_t term_cmds[];
51static term_cmd_t info_cmds[];
52
53void term_printf(const char *fmt, ...)
54{
55 va_list ap;
56 va_start(ap, fmt);
57 vprintf(fmt, ap);
58 va_end(ap);
59}
60
61void term_flush(void)
62{
63 fflush(stdout);
64}
65
66static int compare_cmd(const char *name, const char *list)
67{
68 const char *p, *pstart;
69 int len;
70 len = strlen(name);
71 p = list;
72 for(;;) {
73 pstart = p;
74 p = strchr(p, '|');
75 if (!p)
76 p = pstart + strlen(pstart);
77 if ((p - pstart) == len && !memcmp(pstart, name, len))
78 return 1;
79 if (*p == '\0')
80 break;
81 p++;
82 }
83 return 0;
84}
85
86static void help_cmd1(term_cmd_t *cmds, const char *prefix, const char *name)
87{
88 term_cmd_t *cmd;
89
90 for(cmd = cmds; cmd->name != NULL; cmd++) {
91 if (!name || !strcmp(name, cmd->name))
92 term_printf("%s%s %s -- %s\n", prefix, cmd->name, cmd->params, cmd->help);
93 }
94}
95
96static void help_cmd(const char *name)
97{
98 if (name && !strcmp(name, "info")) {
99 help_cmd1(info_cmds, "info ", NULL);
100 } else {
101 help_cmd1(term_cmds, "", name);
f193c797
FB
102 if (name && !strcmp(name, "log")) {
103 CPULogItem *item;
104 term_printf("Log items (comma separated):\n");
105 term_printf("%-10s %s\n", "none", "remove all logs");
106 for(item = cpu_log_items; item->mask != 0; item++) {
107 term_printf("%-10s %s\n", item->name, item->help);
108 }
109 }
9dc39cba
FB
110 }
111}
112
113static void do_help(int argc, const char **argv)
114{
115 help_cmd(argv[1]);
116}
117
118static void do_commit(int argc, const char **argv)
119{
120 int i;
121
122 for (i = 0; i < MAX_DISKS; i++) {
123 if (bs_table[i])
124 bdrv_commit(bs_table[i]);
125 }
126}
127
128static void do_info(int argc, const char **argv)
129{
130 term_cmd_t *cmd;
131 const char *item;
132
133 if (argc < 2)
134 goto help;
135 item = argv[1];
136 for(cmd = info_cmds; cmd->name != NULL; cmd++) {
137 if (compare_cmd(argv[1], cmd->name))
138 goto found;
139 }
140 help:
141 help_cmd(argv[0]);
142 return;
143 found:
144 cmd->handler(argc, argv);
145}
146
147static void do_info_network(int argc, const char **argv)
148{
149 int i, j;
150 NetDriverState *nd;
151
152 for(i = 0; i < nb_nics; i++) {
153 nd = &nd_table[i];
154 term_printf("%d: ifname=%s macaddr=", i, nd->ifname);
155 for(j = 0; j < 6; j++) {
156 if (j > 0)
157 term_printf(":");
158 term_printf("%02x", nd->macaddr[j]);
159 }
160 term_printf("\n");
161 }
162}
163
164static void do_info_block(int argc, const char **argv)
165{
166 bdrv_info();
167}
168
169static void do_quit(int argc, const char **argv)
170{
171 exit(0);
172}
173
174static int eject_device(BlockDriverState *bs, int force)
175{
176 if (bdrv_is_inserted(bs)) {
177 if (!force) {
178 if (!bdrv_is_removable(bs)) {
179 term_printf("device is not removable\n");
180 return -1;
181 }
182 if (bdrv_is_locked(bs)) {
183 term_printf("device is locked\n");
184 return -1;
185 }
186 }
187 bdrv_close(bs);
188 }
189 return 0;
190}
191
192static void do_eject(int argc, const char **argv)
193{
194 BlockDriverState *bs;
195 const char **parg;
196 int force;
197
198 parg = argv + 1;
199 if (!*parg) {
200 fail:
201 help_cmd(argv[0]);
202 return;
203 }
204 force = 0;
205 if (!strcmp(*parg, "-f")) {
206 force = 1;
207 parg++;
208 }
209 if (!*parg)
210 goto fail;
211 bs = bdrv_find(*parg);
212 if (!bs) {
213 term_printf("device not found\n");
214 return;
215 }
216 eject_device(bs, force);
217}
218
219static void do_change(int argc, const char **argv)
220{
221 BlockDriverState *bs;
222
223 if (argc != 3) {
224 help_cmd(argv[0]);
225 return;
226 }
227 bs = bdrv_find(argv[1]);
228 if (!bs) {
229 term_printf("device not found\n");
230 return;
231 }
232 if (eject_device(bs, 0) < 0)
233 return;
234 bdrv_open(bs, argv[2], 0);
235}
236
59a983b9
FB
237static void do_screen_dump(int argc, const char **argv)
238{
239 if (argc != 2) {
240 help_cmd(argv[0]);
241 return;
242 }
243 vga_screen_dump(argv[1]);
244}
245
f193c797
FB
246static void do_log(int argc, const char **argv)
247{
248 int mask;
249
250 if (argc != 2)
251 goto help;
252 if (!strcmp(argv[1], "none")) {
253 mask = 0;
254 } else {
255 mask = cpu_str_to_log_mask(argv[1]);
256 if (!mask) {
257 help:
258 help_cmd(argv[0]);
259 return;
260 }
261 }
262 cpu_set_log(mask);
263}
264
8a7ddc38
FB
265static void do_savevm(int argc, const char **argv)
266{
267 if (argc != 2) {
268 help_cmd(argv[0]);
269 return;
270 }
271 if (qemu_savevm(argv[1]) < 0)
272 term_printf("I/O error when saving VM to '%s'\n", argv[1]);
273}
274
275static void do_loadvm(int argc, const char **argv)
276{
277 if (argc != 2) {
278 help_cmd(argv[0]);
279 return;
280 }
281 if (qemu_loadvm(argv[1]) < 0)
282 term_printf("I/O error when loading VM from '%s'\n", argv[1]);
283}
284
285static void do_stop(int argc, const char **argv)
286{
287 vm_stop(EXCP_INTERRUPT);
288}
289
290static void do_cont(int argc, const char **argv)
291{
292 vm_start();
293}
294
67b915a5 295#ifdef CONFIG_GDBSTUB
8a7ddc38
FB
296static void do_gdbserver(int argc, const char **argv)
297{
298 int port;
299
300 port = DEFAULT_GDBSTUB_PORT;
301 if (argc >= 2)
302 port = atoi(argv[1]);
303 if (gdbserver_start(port) < 0) {
304 qemu_printf("Could not open gdbserver socket on port %d\n", port);
305 } else {
306 qemu_printf("Waiting gdb connection on port %d\n", port);
307 }
308}
67b915a5 309#endif
8a7ddc38 310
9dc39cba
FB
311static term_cmd_t term_cmds[] = {
312 { "help|?", do_help,
313 "[cmd]", "show the help" },
314 { "commit", do_commit,
315 "", "commit changes to the disk images (if -snapshot is used)" },
316 { "info", do_info,
317 "subcommand", "show various information about the system state" },
318 { "q|quit", do_quit,
319 "", "quit the emulator" },
320 { "eject", do_eject,
321 "[-f] device", "eject a removable media (use -f to force it)" },
322 { "change", do_change,
323 "device filename", "change a removable media" },
59a983b9
FB
324 { "screendump", do_screen_dump,
325 "filename", "save screen into PPM image 'filename'" },
f193c797
FB
326 { "log", do_log,
327 "item1[,...]", "activate logging of the specified items to '/tmp/qemu.log'" },
8a7ddc38
FB
328 { "savevm", do_savevm,
329 "filename", "save the whole virtual machine state to 'filename'" },
330 { "loadvm", do_loadvm,
331 "filename", "restore the whole virtual machine state from 'filename'" },
332 { "stop", do_stop, "", "stop emulation", },
333 { "c|cont", do_cont, "", "resume emulation", },
67b915a5 334#ifdef CONFIG_GDBSTUB
8a7ddc38 335 { "gdbserver", do_gdbserver, "[port]", "start gdbserver session (default port=1234)", },
67b915a5 336#endif
f193c797 337 { NULL, NULL, },
9dc39cba
FB
338};
339
340static term_cmd_t info_cmds[] = {
341 { "network", do_info_network,
342 "", "show the network state" },
343 { "block", do_info_block,
344 "", "show the block devices" },
345 { NULL, NULL, },
346};
347
348static void term_handle_command(char *cmdline)
349{
350 char *p, *pstart;
351 int argc;
352 const char *args[MAX_ARGS + 1];
353 term_cmd_t *cmd;
354
355#ifdef DEBUG
356 term_printf("command='%s'\n", cmdline);
357#endif
358
359 /* split command in words */
360 argc = 0;
361 p = cmdline;
362 for(;;) {
363 while (isspace(*p))
364 p++;
365 if (*p == '\0')
366 break;
367 pstart = p;
368 while (*p != '\0' && !isspace(*p))
369 p++;
370 args[argc] = pstart;
371 argc++;
372 if (argc >= MAX_ARGS)
373 break;
374 if (*p == '\0')
375 break;
376 *p++ = '\0';
377 }
378 args[argc] = NULL;
379#ifdef DEBUG
380 for(i=0;i<argc;i++) {
381 term_printf(" '%s'", args[i]);
382 }
383 term_printf("\n");
384#endif
385 if (argc <= 0)
386 return;
387 for(cmd = term_cmds; cmd->name != NULL; cmd++) {
388 if (compare_cmd(args[0], cmd->name))
389 goto found;
390 }
391 term_printf("unknown command: '%s'\n", args[0]);
392 return;
393 found:
394 cmd->handler(argc, args);
395}
396
397static void term_show_prompt(void)
398{
399 term_printf("(qemu) ");
400 fflush(stdout);
401 term_cmd_buf_index = 0;
402 term_cmd_buf_size = 0;
403 term_esc_state = IS_NORM;
404}
405
406static void term_insert_char(int ch)
407{
408 if (term_cmd_buf_index < TERM_CMD_BUF_SIZE) {
409 memmove(term_cmd_buf + term_cmd_buf_index + 1,
410 term_cmd_buf + term_cmd_buf_index,
411 term_cmd_buf_size - term_cmd_buf_index);
412 term_cmd_buf[term_cmd_buf_index] = ch;
413 term_cmd_buf_size++;
414 term_printf("\033[@%c", ch);
415 term_cmd_buf_index++;
416 term_flush();
417 }
418}
419
420static void term_backward_char(void)
421{
422 if (term_cmd_buf_index > 0) {
423 term_cmd_buf_index--;
424 term_printf("\033[D");
425 term_flush();
426 }
427}
428
429static void term_forward_char(void)
430{
431 if (term_cmd_buf_index < term_cmd_buf_size) {
432 term_cmd_buf_index++;
433 term_printf("\033[C");
434 term_flush();
435 }
436}
437
438static void term_delete_char(void)
439{
440 if (term_cmd_buf_index < term_cmd_buf_size) {
441 memmove(term_cmd_buf + term_cmd_buf_index,
442 term_cmd_buf + term_cmd_buf_index + 1,
443 term_cmd_buf_size - term_cmd_buf_index - 1);
444 term_printf("\033[P");
445 term_cmd_buf_size--;
446 term_flush();
447 }
448}
449
450static void term_backspace(void)
451{
452 if (term_cmd_buf_index > 0) {
453 term_backward_char();
454 term_delete_char();
455 }
456}
457
458static void term_bol(void)
459{
460 while (term_cmd_buf_index > 0)
461 term_backward_char();
462}
463
464static void term_eol(void)
465{
466 while (term_cmd_buf_index < term_cmd_buf_size)
467 term_forward_char();
468}
469
470/* return true if command handled */
471static void term_handle_byte(int ch)
472{
473 switch(term_esc_state) {
474 case IS_NORM:
475 switch(ch) {
476 case 1:
477 term_bol();
478 break;
479 case 5:
480 term_eol();
481 break;
482 case 10:
483 case 13:
484 term_cmd_buf[term_cmd_buf_size] = '\0';
485 term_printf("\n");
486 term_handle_command(term_cmd_buf);
487 term_show_prompt();
488 break;
489 case 27:
490 term_esc_state = IS_ESC;
491 break;
492 case 127:
493 case 8:
494 term_backspace();
495 break;
496 default:
497 if (ch >= 32) {
498 term_insert_char(ch);
499 }
500 break;
501 }
502 break;
503 case IS_ESC:
504 if (ch == '[') {
505 term_esc_state = IS_CSI;
506 term_esc_param = 0;
507 } else {
508 term_esc_state = IS_NORM;
509 }
510 break;
511 case IS_CSI:
512 switch(ch) {
513 case 'D':
514 term_backward_char();
515 break;
516 case 'C':
517 term_forward_char();
518 break;
519 case '0' ... '9':
520 term_esc_param = term_esc_param * 10 + (ch - '0');
521 goto the_end;
522 case '~':
523 switch(term_esc_param) {
524 case 1:
525 term_bol();
526 break;
527 case 3:
528 term_delete_char();
529 break;
530 case 4:
531 term_eol();
532 break;
533 }
534 break;
535 default:
536 break;
537 }
538 term_esc_state = IS_NORM;
539 the_end:
540 break;
541 }
542}
543
544/*************************************************************/
545/* serial console support */
546
547#define TERM_ESCAPE 0x01 /* ctrl-a is used for escape */
548
549static int term_got_escape, term_command;
550
551void term_print_help(void)
552{
553 term_printf("\n"
554 "C-a h print this help\n"
555 "C-a x exit emulatior\n"
9dc39cba
FB
556 "C-a s save disk data back to file (if -snapshot)\n"
557 "C-a b send break (magic sysrq)\n"
558 "C-a c switch between console and monitor\n"
559 "C-a C-a send C-a\n"
560 );
561}
562
563/* called when a char is received */
564static void term_received_byte(int ch)
565{
566 if (!serial_console) {
567 /* if no serial console, handle every command */
568 term_handle_byte(ch);
569 } else {
570 if (term_got_escape) {
571 term_got_escape = 0;
572 switch(ch) {
573 case 'h':
574 term_print_help();
575 break;
576 case 'x':
577 exit(0);
578 break;
579 case 's':
580 {
581 int i;
582 for (i = 0; i < MAX_DISKS; i++) {
583 if (bs_table[i])
584 bdrv_commit(bs_table[i]);
585 }
586 }
587 break;
588 case 'b':
589 if (serial_console)
590 serial_receive_break(serial_console);
591 break;
592 case 'c':
593 if (!term_command) {
594 term_show_prompt();
595 term_command = 1;
596 } else {
597 term_command = 0;
598 }
599 break;
9dc39cba
FB
600 case TERM_ESCAPE:
601 goto send_char;
602 }
603 } else if (ch == TERM_ESCAPE) {
604 term_got_escape = 1;
605 } else {
606 send_char:
607 if (term_command) {
608 term_handle_byte(ch);
609 } else {
610 if (serial_console)
611 serial_receive_byte(serial_console, ch);
612 }
613 }
614 }
615}
616
617static int term_can_read(void *opaque)
618{
619 if (serial_console) {
620 return serial_can_receive(serial_console);
621 } else {
f193c797 622 return 128;
9dc39cba
FB
623 }
624}
625
626static void term_read(void *opaque, const uint8_t *buf, int size)
627{
628 int i;
629 for(i = 0; i < size; i++)
630 term_received_byte(buf[i]);
631}
632
633void monitor_init(void)
634{
635 if (!serial_console) {
636 term_printf("QEMU %s monitor - type 'help' for more information\n",
637 QEMU_VERSION);
638 term_show_prompt();
639 }
8a7ddc38 640 qemu_add_fd_read_handler(0, term_can_read, term_read, NULL);
9dc39cba 641}