]> git.proxmox.com Git - qemu.git/blame - monitor.c
use new directory layout
[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);
121 }
122}
123
124static void do_help(int argc, const char **argv)
125{
126 help_cmd(argv[1]);
127}
128
129static void do_commit(int argc, const char **argv)
130{
131 int i;
132
133 for (i = 0; i < MAX_DISKS; i++) {
134 if (bs_table[i])
135 bdrv_commit(bs_table[i]);
136 }
137}
138
139static void do_info(int argc, const char **argv)
140{
141 term_cmd_t *cmd;
142 const char *item;
143
144 if (argc < 2)
145 goto help;
146 item = argv[1];
147 for(cmd = info_cmds; cmd->name != NULL; cmd++) {
148 if (compare_cmd(argv[1], cmd->name))
149 goto found;
150 }
151 help:
152 help_cmd(argv[0]);
153 return;
154 found:
155 cmd->handler(argc, argv);
156}
157
158static void do_info_network(int argc, const char **argv)
159{
160 int i, j;
161 NetDriverState *nd;
162
163 for(i = 0; i < nb_nics; i++) {
164 nd = &nd_table[i];
165 term_printf("%d: ifname=%s macaddr=", i, nd->ifname);
166 for(j = 0; j < 6; j++) {
167 if (j > 0)
168 term_printf(":");
169 term_printf("%02x", nd->macaddr[j]);
170 }
171 term_printf("\n");
172 }
173}
174
175static void do_info_block(int argc, const char **argv)
176{
177 bdrv_info();
178}
179
180static void do_quit(int argc, const char **argv)
181{
182 exit(0);
183}
184
185static int eject_device(BlockDriverState *bs, int force)
186{
187 if (bdrv_is_inserted(bs)) {
188 if (!force) {
189 if (!bdrv_is_removable(bs)) {
190 term_printf("device is not removable\n");
191 return -1;
192 }
193 if (bdrv_is_locked(bs)) {
194 term_printf("device is locked\n");
195 return -1;
196 }
197 }
198 bdrv_close(bs);
199 }
200 return 0;
201}
202
203static void do_eject(int argc, const char **argv)
204{
205 BlockDriverState *bs;
206 const char **parg;
207 int force;
208
209 parg = argv + 1;
210 if (!*parg) {
211 fail:
212 help_cmd(argv[0]);
213 return;
214 }
215 force = 0;
216 if (!strcmp(*parg, "-f")) {
217 force = 1;
218 parg++;
219 }
220 if (!*parg)
221 goto fail;
222 bs = bdrv_find(*parg);
223 if (!bs) {
224 term_printf("device not found\n");
225 return;
226 }
227 eject_device(bs, force);
228}
229
230static void do_change(int argc, const char **argv)
231{
232 BlockDriverState *bs;
233
234 if (argc != 3) {
235 help_cmd(argv[0]);
236 return;
237 }
238 bs = bdrv_find(argv[1]);
239 if (!bs) {
240 term_printf("device not found\n");
241 return;
242 }
243 if (eject_device(bs, 0) < 0)
244 return;
245 bdrv_open(bs, argv[2], 0);
246}
247
59a983b9
FB
248static void do_screen_dump(int argc, const char **argv)
249{
250 if (argc != 2) {
251 help_cmd(argv[0]);
252 return;
253 }
254 vga_screen_dump(argv[1]);
255}
256
9dc39cba
FB
257static term_cmd_t term_cmds[] = {
258 { "help|?", do_help,
259 "[cmd]", "show the help" },
260 { "commit", do_commit,
261 "", "commit changes to the disk images (if -snapshot is used)" },
262 { "info", do_info,
263 "subcommand", "show various information about the system state" },
264 { "q|quit", do_quit,
265 "", "quit the emulator" },
266 { "eject", do_eject,
267 "[-f] device", "eject a removable media (use -f to force it)" },
268 { "change", do_change,
269 "device filename", "change a removable media" },
59a983b9
FB
270 { "screendump", do_screen_dump,
271 "filename", "save screen into PPM image 'filename'" },
9dc39cba
FB
272 { NULL, NULL, },
273};
274
275static term_cmd_t info_cmds[] = {
276 { "network", do_info_network,
277 "", "show the network state" },
278 { "block", do_info_block,
279 "", "show the block devices" },
280 { NULL, NULL, },
281};
282
283static void term_handle_command(char *cmdline)
284{
285 char *p, *pstart;
286 int argc;
287 const char *args[MAX_ARGS + 1];
288 term_cmd_t *cmd;
289
290#ifdef DEBUG
291 term_printf("command='%s'\n", cmdline);
292#endif
293
294 /* split command in words */
295 argc = 0;
296 p = cmdline;
297 for(;;) {
298 while (isspace(*p))
299 p++;
300 if (*p == '\0')
301 break;
302 pstart = p;
303 while (*p != '\0' && !isspace(*p))
304 p++;
305 args[argc] = pstart;
306 argc++;
307 if (argc >= MAX_ARGS)
308 break;
309 if (*p == '\0')
310 break;
311 *p++ = '\0';
312 }
313 args[argc] = NULL;
314#ifdef DEBUG
315 for(i=0;i<argc;i++) {
316 term_printf(" '%s'", args[i]);
317 }
318 term_printf("\n");
319#endif
320 if (argc <= 0)
321 return;
322 for(cmd = term_cmds; cmd->name != NULL; cmd++) {
323 if (compare_cmd(args[0], cmd->name))
324 goto found;
325 }
326 term_printf("unknown command: '%s'\n", args[0]);
327 return;
328 found:
329 cmd->handler(argc, args);
330}
331
332static void term_show_prompt(void)
333{
334 term_printf("(qemu) ");
335 fflush(stdout);
336 term_cmd_buf_index = 0;
337 term_cmd_buf_size = 0;
338 term_esc_state = IS_NORM;
339}
340
341static void term_insert_char(int ch)
342{
343 if (term_cmd_buf_index < TERM_CMD_BUF_SIZE) {
344 memmove(term_cmd_buf + term_cmd_buf_index + 1,
345 term_cmd_buf + term_cmd_buf_index,
346 term_cmd_buf_size - term_cmd_buf_index);
347 term_cmd_buf[term_cmd_buf_index] = ch;
348 term_cmd_buf_size++;
349 term_printf("\033[@%c", ch);
350 term_cmd_buf_index++;
351 term_flush();
352 }
353}
354
355static void term_backward_char(void)
356{
357 if (term_cmd_buf_index > 0) {
358 term_cmd_buf_index--;
359 term_printf("\033[D");
360 term_flush();
361 }
362}
363
364static void term_forward_char(void)
365{
366 if (term_cmd_buf_index < term_cmd_buf_size) {
367 term_cmd_buf_index++;
368 term_printf("\033[C");
369 term_flush();
370 }
371}
372
373static void term_delete_char(void)
374{
375 if (term_cmd_buf_index < term_cmd_buf_size) {
376 memmove(term_cmd_buf + term_cmd_buf_index,
377 term_cmd_buf + term_cmd_buf_index + 1,
378 term_cmd_buf_size - term_cmd_buf_index - 1);
379 term_printf("\033[P");
380 term_cmd_buf_size--;
381 term_flush();
382 }
383}
384
385static void term_backspace(void)
386{
387 if (term_cmd_buf_index > 0) {
388 term_backward_char();
389 term_delete_char();
390 }
391}
392
393static void term_bol(void)
394{
395 while (term_cmd_buf_index > 0)
396 term_backward_char();
397}
398
399static void term_eol(void)
400{
401 while (term_cmd_buf_index < term_cmd_buf_size)
402 term_forward_char();
403}
404
405/* return true if command handled */
406static void term_handle_byte(int ch)
407{
408 switch(term_esc_state) {
409 case IS_NORM:
410 switch(ch) {
411 case 1:
412 term_bol();
413 break;
414 case 5:
415 term_eol();
416 break;
417 case 10:
418 case 13:
419 term_cmd_buf[term_cmd_buf_size] = '\0';
420 term_printf("\n");
421 term_handle_command(term_cmd_buf);
422 term_show_prompt();
423 break;
424 case 27:
425 term_esc_state = IS_ESC;
426 break;
427 case 127:
428 case 8:
429 term_backspace();
430 break;
431 default:
432 if (ch >= 32) {
433 term_insert_char(ch);
434 }
435 break;
436 }
437 break;
438 case IS_ESC:
439 if (ch == '[') {
440 term_esc_state = IS_CSI;
441 term_esc_param = 0;
442 } else {
443 term_esc_state = IS_NORM;
444 }
445 break;
446 case IS_CSI:
447 switch(ch) {
448 case 'D':
449 term_backward_char();
450 break;
451 case 'C':
452 term_forward_char();
453 break;
454 case '0' ... '9':
455 term_esc_param = term_esc_param * 10 + (ch - '0');
456 goto the_end;
457 case '~':
458 switch(term_esc_param) {
459 case 1:
460 term_bol();
461 break;
462 case 3:
463 term_delete_char();
464 break;
465 case 4:
466 term_eol();
467 break;
468 }
469 break;
470 default:
471 break;
472 }
473 term_esc_state = IS_NORM;
474 the_end:
475 break;
476 }
477}
478
479/*************************************************************/
480/* serial console support */
481
482#define TERM_ESCAPE 0x01 /* ctrl-a is used for escape */
483
484static int term_got_escape, term_command;
485
486void term_print_help(void)
487{
488 term_printf("\n"
489 "C-a h print this help\n"
490 "C-a x exit emulatior\n"
491 "C-a d switch on/off debug log\n"
492 "C-a s save disk data back to file (if -snapshot)\n"
493 "C-a b send break (magic sysrq)\n"
494 "C-a c switch between console and monitor\n"
495 "C-a C-a send C-a\n"
496 );
497}
498
499/* called when a char is received */
500static void term_received_byte(int ch)
501{
502 if (!serial_console) {
503 /* if no serial console, handle every command */
504 term_handle_byte(ch);
505 } else {
506 if (term_got_escape) {
507 term_got_escape = 0;
508 switch(ch) {
509 case 'h':
510 term_print_help();
511 break;
512 case 'x':
513 exit(0);
514 break;
515 case 's':
516 {
517 int i;
518 for (i = 0; i < MAX_DISKS; i++) {
519 if (bs_table[i])
520 bdrv_commit(bs_table[i]);
521 }
522 }
523 break;
524 case 'b':
525 if (serial_console)
526 serial_receive_break(serial_console);
527 break;
528 case 'c':
529 if (!term_command) {
530 term_show_prompt();
531 term_command = 1;
532 } else {
533 term_command = 0;
534 }
535 break;
536 case 'd':
537 cpu_set_log(CPU_LOG_ALL);
538 break;
539 case TERM_ESCAPE:
540 goto send_char;
541 }
542 } else if (ch == TERM_ESCAPE) {
543 term_got_escape = 1;
544 } else {
545 send_char:
546 if (term_command) {
547 term_handle_byte(ch);
548 } else {
549 if (serial_console)
550 serial_receive_byte(serial_console, ch);
551 }
552 }
553 }
554}
555
556static int term_can_read(void *opaque)
557{
558 if (serial_console) {
559 return serial_can_receive(serial_console);
560 } else {
561 return 1;
562 }
563}
564
565static void term_read(void *opaque, const uint8_t *buf, int size)
566{
567 int i;
568 for(i = 0; i < size; i++)
569 term_received_byte(buf[i]);
570}
571
572void monitor_init(void)
573{
574 if (!serial_console) {
575 term_printf("QEMU %s monitor - type 'help' for more information\n",
576 QEMU_VERSION);
577 term_show_prompt();
578 }
579 add_fd_read_handler(0, term_can_read, term_read, NULL);
580}