]> git.proxmox.com Git - mirror_qemu.git/blame - monitor.c
do not depend on thunk.h - more log items
[mirror_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
9dc39cba
FB
284static term_cmd_t term_cmds[] = {
285 { "help|?", do_help,
286 "[cmd]", "show the help" },
287 { "commit", do_commit,
288 "", "commit changes to the disk images (if -snapshot is used)" },
289 { "info", do_info,
290 "subcommand", "show various information about the system state" },
291 { "q|quit", do_quit,
292 "", "quit the emulator" },
293 { "eject", do_eject,
294 "[-f] device", "eject a removable media (use -f to force it)" },
295 { "change", do_change,
296 "device filename", "change a removable media" },
59a983b9
FB
297 { "screendump", do_screen_dump,
298 "filename", "save screen into PPM image 'filename'" },
f193c797
FB
299 { "log", do_log,
300 "item1[,...]", "activate logging of the specified items to '/tmp/qemu.log'" },
301 { NULL, NULL, },
9dc39cba
FB
302};
303
304static term_cmd_t info_cmds[] = {
305 { "network", do_info_network,
306 "", "show the network state" },
307 { "block", do_info_block,
308 "", "show the block devices" },
309 { NULL, NULL, },
310};
311
312static void term_handle_command(char *cmdline)
313{
314 char *p, *pstart;
315 int argc;
316 const char *args[MAX_ARGS + 1];
317 term_cmd_t *cmd;
318
319#ifdef DEBUG
320 term_printf("command='%s'\n", cmdline);
321#endif
322
323 /* split command in words */
324 argc = 0;
325 p = cmdline;
326 for(;;) {
327 while (isspace(*p))
328 p++;
329 if (*p == '\0')
330 break;
331 pstart = p;
332 while (*p != '\0' && !isspace(*p))
333 p++;
334 args[argc] = pstart;
335 argc++;
336 if (argc >= MAX_ARGS)
337 break;
338 if (*p == '\0')
339 break;
340 *p++ = '\0';
341 }
342 args[argc] = NULL;
343#ifdef DEBUG
344 for(i=0;i<argc;i++) {
345 term_printf(" '%s'", args[i]);
346 }
347 term_printf("\n");
348#endif
349 if (argc <= 0)
350 return;
351 for(cmd = term_cmds; cmd->name != NULL; cmd++) {
352 if (compare_cmd(args[0], cmd->name))
353 goto found;
354 }
355 term_printf("unknown command: '%s'\n", args[0]);
356 return;
357 found:
358 cmd->handler(argc, args);
359}
360
361static void term_show_prompt(void)
362{
363 term_printf("(qemu) ");
364 fflush(stdout);
365 term_cmd_buf_index = 0;
366 term_cmd_buf_size = 0;
367 term_esc_state = IS_NORM;
368}
369
370static void term_insert_char(int ch)
371{
372 if (term_cmd_buf_index < TERM_CMD_BUF_SIZE) {
373 memmove(term_cmd_buf + term_cmd_buf_index + 1,
374 term_cmd_buf + term_cmd_buf_index,
375 term_cmd_buf_size - term_cmd_buf_index);
376 term_cmd_buf[term_cmd_buf_index] = ch;
377 term_cmd_buf_size++;
378 term_printf("\033[@%c", ch);
379 term_cmd_buf_index++;
380 term_flush();
381 }
382}
383
384static void term_backward_char(void)
385{
386 if (term_cmd_buf_index > 0) {
387 term_cmd_buf_index--;
388 term_printf("\033[D");
389 term_flush();
390 }
391}
392
393static void term_forward_char(void)
394{
395 if (term_cmd_buf_index < term_cmd_buf_size) {
396 term_cmd_buf_index++;
397 term_printf("\033[C");
398 term_flush();
399 }
400}
401
402static void term_delete_char(void)
403{
404 if (term_cmd_buf_index < term_cmd_buf_size) {
405 memmove(term_cmd_buf + term_cmd_buf_index,
406 term_cmd_buf + term_cmd_buf_index + 1,
407 term_cmd_buf_size - term_cmd_buf_index - 1);
408 term_printf("\033[P");
409 term_cmd_buf_size--;
410 term_flush();
411 }
412}
413
414static void term_backspace(void)
415{
416 if (term_cmd_buf_index > 0) {
417 term_backward_char();
418 term_delete_char();
419 }
420}
421
422static void term_bol(void)
423{
424 while (term_cmd_buf_index > 0)
425 term_backward_char();
426}
427
428static void term_eol(void)
429{
430 while (term_cmd_buf_index < term_cmd_buf_size)
431 term_forward_char();
432}
433
434/* return true if command handled */
435static void term_handle_byte(int ch)
436{
437 switch(term_esc_state) {
438 case IS_NORM:
439 switch(ch) {
440 case 1:
441 term_bol();
442 break;
443 case 5:
444 term_eol();
445 break;
446 case 10:
447 case 13:
448 term_cmd_buf[term_cmd_buf_size] = '\0';
449 term_printf("\n");
450 term_handle_command(term_cmd_buf);
451 term_show_prompt();
452 break;
453 case 27:
454 term_esc_state = IS_ESC;
455 break;
456 case 127:
457 case 8:
458 term_backspace();
459 break;
460 default:
461 if (ch >= 32) {
462 term_insert_char(ch);
463 }
464 break;
465 }
466 break;
467 case IS_ESC:
468 if (ch == '[') {
469 term_esc_state = IS_CSI;
470 term_esc_param = 0;
471 } else {
472 term_esc_state = IS_NORM;
473 }
474 break;
475 case IS_CSI:
476 switch(ch) {
477 case 'D':
478 term_backward_char();
479 break;
480 case 'C':
481 term_forward_char();
482 break;
483 case '0' ... '9':
484 term_esc_param = term_esc_param * 10 + (ch - '0');
485 goto the_end;
486 case '~':
487 switch(term_esc_param) {
488 case 1:
489 term_bol();
490 break;
491 case 3:
492 term_delete_char();
493 break;
494 case 4:
495 term_eol();
496 break;
497 }
498 break;
499 default:
500 break;
501 }
502 term_esc_state = IS_NORM;
503 the_end:
504 break;
505 }
506}
507
508/*************************************************************/
509/* serial console support */
510
511#define TERM_ESCAPE 0x01 /* ctrl-a is used for escape */
512
513static int term_got_escape, term_command;
514
515void term_print_help(void)
516{
517 term_printf("\n"
518 "C-a h print this help\n"
519 "C-a x exit emulatior\n"
9dc39cba
FB
520 "C-a s save disk data back to file (if -snapshot)\n"
521 "C-a b send break (magic sysrq)\n"
522 "C-a c switch between console and monitor\n"
523 "C-a C-a send C-a\n"
524 );
525}
526
527/* called when a char is received */
528static void term_received_byte(int ch)
529{
530 if (!serial_console) {
531 /* if no serial console, handle every command */
532 term_handle_byte(ch);
533 } else {
534 if (term_got_escape) {
535 term_got_escape = 0;
536 switch(ch) {
537 case 'h':
538 term_print_help();
539 break;
540 case 'x':
541 exit(0);
542 break;
543 case 's':
544 {
545 int i;
546 for (i = 0; i < MAX_DISKS; i++) {
547 if (bs_table[i])
548 bdrv_commit(bs_table[i]);
549 }
550 }
551 break;
552 case 'b':
553 if (serial_console)
554 serial_receive_break(serial_console);
555 break;
556 case 'c':
557 if (!term_command) {
558 term_show_prompt();
559 term_command = 1;
560 } else {
561 term_command = 0;
562 }
563 break;
9dc39cba
FB
564 case TERM_ESCAPE:
565 goto send_char;
566 }
567 } else if (ch == TERM_ESCAPE) {
568 term_got_escape = 1;
569 } else {
570 send_char:
571 if (term_command) {
572 term_handle_byte(ch);
573 } else {
574 if (serial_console)
575 serial_receive_byte(serial_console, ch);
576 }
577 }
578 }
579}
580
581static int term_can_read(void *opaque)
582{
583 if (serial_console) {
584 return serial_can_receive(serial_console);
585 } else {
f193c797 586 return 128;
9dc39cba
FB
587 }
588}
589
590static void term_read(void *opaque, const uint8_t *buf, int size)
591{
592 int i;
593 for(i = 0; i < size; i++)
594 term_received_byte(buf[i]);
595}
596
597void monitor_init(void)
598{
599 if (!serial_console) {
600 term_printf("QEMU %s monitor - type 'help' for more information\n",
601 QEMU_VERSION);
602 term_show_prompt();
603 }
604 add_fd_read_handler(0, term_can_read, term_read, NULL);
605}