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