Statistics
| Branch: | Revision:

root / monitor.c @ 9dc39cba

History | View | Annotate | Download (13.2 kB)

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
    }
122
}
123

    
124
static void do_help(int argc, const char **argv)
125
{
126
    help_cmd(argv[1]);
127
}
128

    
129
static 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

    
139
static 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

    
158
static 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
 
175
static void do_info_block(int argc, const char **argv)
176
{
177
    bdrv_info();
178
}
179

    
180
static void do_quit(int argc, const char **argv)
181
{
182
    exit(0);
183
}
184

    
185
static 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

    
203
static 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

    
230
static 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

    
248
static term_cmd_t term_cmds[] = {
249
    { "help|?", do_help, 
250
      "[cmd]", "show the help" },
251
    { "commit", do_commit, 
252
      "", "commit changes to the disk images (if -snapshot is used)" },
253
    { "info", do_info,
254
      "subcommand", "show various information about the system state" },
255
    { "q|quit", do_quit,
256
      "", "quit the emulator" },
257
    { "eject", do_eject,
258
      "[-f] device", "eject a removable media (use -f to force it)" },
259
    { "change", do_change,
260
      "device filename", "change a removable media" },
261
    { NULL, NULL, },
262
};
263

    
264
static term_cmd_t info_cmds[] = {
265
    { "network", do_info_network,
266
      "", "show the network state" },
267
    { "block", do_info_block,
268
      "", "show the block devices" },
269
    { NULL, NULL, },
270
};
271

    
272
static void term_handle_command(char *cmdline)
273
{
274
    char *p, *pstart;
275
    int argc;
276
    const char *args[MAX_ARGS + 1];
277
    term_cmd_t *cmd;
278

    
279
#ifdef DEBUG
280
    term_printf("command='%s'\n", cmdline);
281
#endif
282
    
283
    /* split command in words */
284
    argc = 0;
285
    p = cmdline;
286
    for(;;) {
287
        while (isspace(*p))
288
            p++;
289
        if (*p == '\0')
290
            break;
291
        pstart = p;
292
        while (*p != '\0' && !isspace(*p))
293
            p++;
294
        args[argc] = pstart;
295
        argc++;
296
        if (argc >= MAX_ARGS)
297
            break;
298
        if (*p == '\0')
299
            break;
300
        *p++ = '\0';
301
    }
302
    args[argc] = NULL;
303
#ifdef DEBUG
304
    for(i=0;i<argc;i++) {
305
        term_printf(" '%s'", args[i]);
306
    }
307
    term_printf("\n");
308
#endif
309
    if (argc <= 0)
310
        return;
311
    for(cmd = term_cmds; cmd->name != NULL; cmd++) {
312
        if (compare_cmd(args[0], cmd->name)) 
313
            goto found;
314
    }
315
    term_printf("unknown command: '%s'\n", args[0]);
316
    return;
317
 found:
318
    cmd->handler(argc, args);
319
}
320

    
321
static void term_show_prompt(void)
322
{
323
    term_printf("(qemu) ");
324
    fflush(stdout);
325
    term_cmd_buf_index = 0;
326
    term_cmd_buf_size = 0;
327
    term_esc_state = IS_NORM;
328
}
329

    
330
static void term_insert_char(int ch)
331
{
332
    if (term_cmd_buf_index < TERM_CMD_BUF_SIZE) {
333
        memmove(term_cmd_buf + term_cmd_buf_index + 1,
334
                term_cmd_buf + term_cmd_buf_index,
335
                term_cmd_buf_size - term_cmd_buf_index);
336
        term_cmd_buf[term_cmd_buf_index] = ch;
337
        term_cmd_buf_size++;
338
        term_printf("\033[@%c", ch);
339
        term_cmd_buf_index++;
340
        term_flush();
341
    }
342
}
343

    
344
static void term_backward_char(void)
345
{
346
    if (term_cmd_buf_index > 0) {
347
        term_cmd_buf_index--;
348
        term_printf("\033[D");
349
        term_flush();
350
    }
351
}
352

    
353
static void term_forward_char(void)
354
{
355
    if (term_cmd_buf_index < term_cmd_buf_size) {
356
        term_cmd_buf_index++;
357
        term_printf("\033[C");
358
        term_flush();
359
    }
360
}
361

    
362
static void term_delete_char(void)
363
{
364
    if (term_cmd_buf_index < term_cmd_buf_size) {
365
        memmove(term_cmd_buf + term_cmd_buf_index,
366
                term_cmd_buf + term_cmd_buf_index + 1,
367
                term_cmd_buf_size - term_cmd_buf_index - 1);
368
        term_printf("\033[P");
369
        term_cmd_buf_size--;
370
        term_flush();
371
    }
372
}
373

    
374
static void term_backspace(void)
375
{
376
    if (term_cmd_buf_index > 0) {
377
        term_backward_char();
378
        term_delete_char();
379
    }
380
}
381

    
382
static void term_bol(void)
383
{
384
    while (term_cmd_buf_index > 0)
385
        term_backward_char();
386
}
387

    
388
static void term_eol(void)
389
{
390
    while (term_cmd_buf_index < term_cmd_buf_size)
391
        term_forward_char();
392
}
393

    
394
/* return true if command handled */
395
static void term_handle_byte(int ch)
396
{
397
    switch(term_esc_state) {
398
    case IS_NORM:
399
        switch(ch) {
400
        case 1:
401
            term_bol();
402
            break;
403
        case 5:
404
            term_eol();
405
            break;
406
        case 10:
407
        case 13:
408
            term_cmd_buf[term_cmd_buf_size] = '\0';
409
            term_printf("\n");
410
            term_handle_command(term_cmd_buf);
411
            term_show_prompt();
412
            break;
413
        case 27:
414
            term_esc_state = IS_ESC;
415
            break;
416
        case 127:
417
        case 8:
418
            term_backspace();
419
            break;
420
        default:
421
            if (ch >= 32) {
422
                term_insert_char(ch);
423
            }
424
            break;
425
        }
426
        break;
427
    case IS_ESC:
428
        if (ch == '[') {
429
            term_esc_state = IS_CSI;
430
            term_esc_param = 0;
431
        } else {
432
            term_esc_state = IS_NORM;
433
        }
434
        break;
435
    case IS_CSI:
436
        switch(ch) {
437
        case 'D':
438
            term_backward_char();
439
            break;
440
        case 'C':
441
            term_forward_char();
442
            break;
443
        case '0' ... '9':
444
            term_esc_param = term_esc_param * 10 + (ch - '0');
445
            goto the_end;
446
        case '~':
447
            switch(term_esc_param) {
448
            case 1:
449
                term_bol();
450
                break;
451
            case 3:
452
                term_delete_char();
453
                break;
454
            case 4:
455
                term_eol();
456
                break;
457
            }
458
            break;
459
        default:
460
            break;
461
        }
462
        term_esc_state = IS_NORM;
463
    the_end:
464
        break;
465
    }
466
}
467

    
468
/*************************************************************/
469
/* serial console support */
470

    
471
#define TERM_ESCAPE 0x01 /* ctrl-a is used for escape */
472

    
473
static int term_got_escape, term_command;
474

    
475
void term_print_help(void)
476
{
477
    term_printf("\n"
478
                "C-a h    print this help\n"
479
                "C-a x    exit emulatior\n"
480
                "C-a d    switch on/off debug log\n"
481
                "C-a s    save disk data back to file (if -snapshot)\n"
482
                "C-a b    send break (magic sysrq)\n"
483
                "C-a c    switch between console and monitor\n"
484
                "C-a C-a  send C-a\n"
485
                );
486
}
487

    
488
/* called when a char is received */
489
static void term_received_byte(int ch)
490
{
491
    if (!serial_console) {
492
        /* if no serial console, handle every command */
493
        term_handle_byte(ch);
494
    } else {
495
        if (term_got_escape) {
496
            term_got_escape = 0;
497
            switch(ch) {
498
            case 'h':
499
                term_print_help();
500
                break;
501
            case 'x':
502
                exit(0);
503
                break;
504
            case 's': 
505
                {
506
                    int i;
507
                    for (i = 0; i < MAX_DISKS; i++) {
508
                        if (bs_table[i])
509
                            bdrv_commit(bs_table[i]);
510
                    }
511
                }
512
                break;
513
            case 'b':
514
                if (serial_console)
515
                    serial_receive_break(serial_console);
516
                break;
517
            case 'c':
518
                if (!term_command) {
519
                    term_show_prompt();
520
                    term_command = 1;
521
                } else {
522
                    term_command = 0;
523
                }
524
                break;
525
            case 'd':
526
                cpu_set_log(CPU_LOG_ALL);
527
                break;
528
            case TERM_ESCAPE:
529
                goto send_char;
530
            }
531
        } else if (ch == TERM_ESCAPE) {
532
            term_got_escape = 1;
533
        } else {
534
        send_char:
535
            if (term_command) {
536
                term_handle_byte(ch);
537
            } else {
538
                if (serial_console)
539
                    serial_receive_byte(serial_console, ch);
540
            }
541
        }
542
    }
543
}
544

    
545
static int term_can_read(void *opaque)
546
{
547
    if (serial_console) {
548
        return serial_can_receive(serial_console);
549
    } else {
550
        return 1;
551
    }
552
}
553

    
554
static void term_read(void *opaque, const uint8_t *buf, int size)
555
{
556
    int i;
557
    for(i = 0; i < size; i++)
558
        term_received_byte(buf[i]);
559
}
560

    
561
void monitor_init(void)
562
{
563
    if (!serial_console) {
564
        term_printf("QEMU %s monitor - type 'help' for more information\n",
565
                    QEMU_VERSION);
566
        term_show_prompt();
567
    }
568
    add_fd_read_handler(0, term_can_read, term_read, NULL);
569
}