]> git.proxmox.com Git - mirror_qemu.git/blob - monitor.c
do not depend on thunk.h - more log items
[mirror_qemu.git] / monitor.c
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
56 static char term_cmd_buf[TERM_CMD_BUF_SIZE + 1];
57 static int term_cmd_buf_index;
58 static int term_cmd_buf_size;
59 static int term_esc_state;
60 static int term_esc_param;
61
62 typedef 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
69 static term_cmd_t term_cmds[];
70 static term_cmd_t info_cmds[];
71
72 void 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
80 void term_flush(void)
81 {
82 fflush(stdout);
83 }
84
85 static 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
105 static 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
115 static 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);
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 }
129 }
130 }
131
132 static void do_help(int argc, const char **argv)
133 {
134 help_cmd(argv[1]);
135 }
136
137 static 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
147 static 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
166 static 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
183 static void do_info_block(int argc, const char **argv)
184 {
185 bdrv_info();
186 }
187
188 static void do_quit(int argc, const char **argv)
189 {
190 exit(0);
191 }
192
193 static 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
211 static 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
238 static 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
256 static 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
265 static 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
284 static 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" },
297 { "screendump", do_screen_dump,
298 "filename", "save screen into PPM image 'filename'" },
299 { "log", do_log,
300 "item1[,...]", "activate logging of the specified items to '/tmp/qemu.log'" },
301 { NULL, NULL, },
302 };
303
304 static 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
312 static 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
361 static 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
370 static 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
384 static 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
393 static 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
402 static 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
414 static void term_backspace(void)
415 {
416 if (term_cmd_buf_index > 0) {
417 term_backward_char();
418 term_delete_char();
419 }
420 }
421
422 static void term_bol(void)
423 {
424 while (term_cmd_buf_index > 0)
425 term_backward_char();
426 }
427
428 static 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 */
435 static 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
513 static int term_got_escape, term_command;
514
515 void term_print_help(void)
516 {
517 term_printf("\n"
518 "C-a h print this help\n"
519 "C-a x exit emulatior\n"
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 */
528 static 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;
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
581 static int term_can_read(void *opaque)
582 {
583 if (serial_console) {
584 return serial_can_receive(serial_console);
585 } else {
586 return 128;
587 }
588 }
589
590 static 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
597 void 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 }