more dummy regs & clean-up for twl4030
[qemu] / monitor.c
index b184973..da106d8 100644 (file)
--- a/monitor.c
+++ b/monitor.c
@@ -21,6 +21,7 @@
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  * THE SOFTWARE.
  */
+#include <dirent.h>
 #include "hw/hw.h"
 #include "hw/usb.h"
 #include "hw/pcmcia.h"
 #include "audio/audio.h"
 #include "disas.h"
 #include "balloon.h"
-#include <dirent.h>
 #include "qemu-timer.h"
 #include "migration.h"
 #include "kvm.h"
+#include "acl.h"
 
 //#define DEBUG
 //#define DEBUG_COMPLETION
@@ -67,38 +68,54 @@ typedef struct mon_cmd_t {
     const char *help;
 } mon_cmd_t;
 
-#define MAX_MON 4
-static CharDriverState *monitor_hd[MAX_MON];
-static int hide_banner;
+struct Monitor {
+    CharDriverState *chr;
+    int flags;
+    int suspend_cnt;
+    uint8_t outbuf[1024];
+    int outbuf_index;
+    ReadLineState *rs;
+    CPUState *mon_cpu;
+    BlockDriverCompletionFunc *password_completion_cb;
+    void *password_opaque;
+    LIST_ENTRY(Monitor) entry;
+};
+
+static LIST_HEAD(mon_list, Monitor) mon_list;
 
 static const mon_cmd_t mon_cmds[];
 static const mon_cmd_t info_cmds[];
 
-static uint8_t term_outbuf[1024];
-static int term_outbuf_index;
-static BlockDriverCompletionFunc *password_completion_cb;
-static void *password_opaque;
-
-Monitor *cur_mon;
+Monitor *cur_mon = NULL;
 
-static void monitor_start_input(void);
+static void monitor_command_cb(Monitor *mon, const char *cmdline,
+                               void *opaque);
 
-static CPUState *mon_cpu = NULL;
+static void monitor_read_command(Monitor *mon, int show_prompt)
+{
+    readline_start(mon->rs, "(qemu) ", 0, monitor_command_cb, NULL);
+    if (show_prompt)
+        readline_show_prompt(mon->rs);
+}
 
-static void monitor_read_password(Monitor *mon, ReadLineFunc *readline_func,
-                                  void *opaque)
+static int monitor_read_password(Monitor *mon, ReadLineFunc *readline_func,
+                                 void *opaque)
 {
-    readline_start("Password: ", 1, readline_func, opaque);
+    if (mon->rs) {
+        readline_start(mon->rs, "Password: ", 1, readline_func, opaque);
+        /* prompt is printed on return from the command handler */
+        return 0;
+    } else {
+        monitor_printf(mon, "terminal does not support password prompting\n");
+        return -ENOTTY;
+    }
 }
 
 void monitor_flush(Monitor *mon)
 {
-    int i;
-    if (term_outbuf_index > 0) {
-        for (i = 0; i < MAX_MON; i++)
-            if (monitor_hd[i] && monitor_hd[i]->focus == 0)
-                qemu_chr_write(monitor_hd[i], term_outbuf, term_outbuf_index);
-        term_outbuf_index = 0;
+    if (mon && mon->outbuf_index != 0 && mon->chr->focus == 0) {
+        qemu_chr_write(mon->chr, mon->outbuf, mon->outbuf_index);
+        mon->outbuf_index = 0;
     }
 }
 
@@ -106,15 +123,19 @@ void monitor_flush(Monitor *mon)
 static void monitor_puts(Monitor *mon, const char *str)
 {
     char c;
+
+    if (!mon)
+        return;
+
     for(;;) {
         c = *str++;
         if (c == '\0')
             break;
         if (c == '\n')
-            term_outbuf[term_outbuf_index++] = '\r';
-        term_outbuf[term_outbuf_index++] = c;
-        if (term_outbuf_index >= (sizeof(term_outbuf) - 1) ||
-            c == '\n')
+            mon->outbuf[mon->outbuf_index++] = '\r';
+        mon->outbuf[mon->outbuf_index++] = c;
+        if (mon->outbuf_index >= (sizeof(mon->outbuf) - 1)
+            || c == '\n')
             monitor_flush(mon);
     }
 }
@@ -139,25 +160,25 @@ void monitor_print_filename(Monitor *mon, const char *filename)
     int i;
 
     for (i = 0; filename[i]; i++) {
-       switch (filename[i]) {
-       case ' ':
-       case '"':
-       case '\\':
-           monitor_printf(mon, "\\%c", filename[i]);
-           break;
-       case '\t':
-           monitor_printf(mon, "\\t");
-           break;
-       case '\r':
-           monitor_printf(mon, "\\r");
-           break;
-       case '\n':
-           monitor_printf(mon, "\\n");
-           break;
-       default:
-           monitor_printf(mon, "%c", filename[i]);
-           break;
-       }
+        switch (filename[i]) {
+        case ' ':
+        case '"':
+        case '\\':
+            monitor_printf(mon, "\\%c", filename[i]);
+            break;
+        case '\t':
+            monitor_printf(mon, "\\t");
+            break;
+        case '\r':
+            monitor_printf(mon, "\\r");
+            break;
+        case '\n':
+            monitor_printf(mon, "\\n");
+            break;
+        default:
+            monitor_printf(mon, "%c", filename[i]);
+            break;
+        }
     }
 }
 
@@ -285,7 +306,7 @@ static int mon_set_cpu(int cpu_index)
 
     for(env = first_cpu; env != NULL; env = env->next_cpu) {
         if (env->cpu_index == cpu_index) {
-            mon_cpu = env;
+            cur_mon->mon_cpu = env;
             return 0;
         }
     }
@@ -294,10 +315,11 @@ static int mon_set_cpu(int cpu_index)
 
 static CPUState *mon_get_cpu(void)
 {
-    if (!mon_cpu) {
+    if (!cur_mon->mon_cpu) {
         mon_set_cpu(0);
     }
-    return mon_cpu;
+    cpu_synchronize_state(cur_mon->mon_cpu, 0);
+    return cur_mon->mon_cpu;
 }
 
 static void do_info_registers(Monitor *mon)
@@ -323,8 +345,9 @@ static void do_info_cpus(Monitor *mon)
     mon_get_cpu();
 
     for(env = first_cpu; env != NULL; env = env->next_cpu) {
+        cpu_synchronize_state(env, 0);
         monitor_printf(mon, "%c CPU #%d:",
-                       (env == mon_cpu) ? '*' : ' ',
+                       (env == mon->mon_cpu) ? '*' : ' ',
                        env->cpu_index);
 #if defined(TARGET_I386)
         monitor_printf(mon, " pc=0x" TARGET_FMT_lx,
@@ -359,9 +382,11 @@ static void do_info_history(Monitor *mon)
     int i;
     const char *str;
 
+    if (!mon->rs)
+        return;
     i = 0;
     for(;;) {
-        str = readline_get_history(i);
+        str = readline_get_history(mon->rs, i);
         if (!str)
             break;
         monitor_printf(mon, "%d: '%s'\n", i, str);
@@ -445,23 +470,23 @@ static void change_vnc_password_cb(Monitor *mon, const char *password,
     if (vnc_display_password(NULL, password) < 0)
         monitor_printf(mon, "could not set VNC server password\n");
 
-    monitor_start_input();
+    monitor_read_command(mon, 1);
 }
 
 static void do_change_vnc(Monitor *mon, const char *target, const char *arg)
 {
     if (strcmp(target, "passwd") == 0 ||
-       strcmp(target, "password") == 0) {
-       if (arg) {
+        strcmp(target, "password") == 0) {
+        if (arg) {
             char password[9];
-           strncpy(password, arg, sizeof(password));
-           password[sizeof(password) - 1] = '\0';
+            strncpy(password, arg, sizeof(password));
+            password[sizeof(password) - 1] = '\0';
             change_vnc_password_cb(mon, password, NULL);
         } else {
             monitor_read_password(mon, change_vnc_password_cb, NULL);
         }
     } else {
-       if (vnc_display_open(NULL, target) < 0)
+        if (vnc_display_open(NULL, target) < 0)
             monitor_printf(mon, "could not start VNC server on %s\n", target);
     }
 }
@@ -470,9 +495,9 @@ static void do_change(Monitor *mon, const char *device, const char *target,
                       const char *arg)
 {
     if (strcmp(device, "vnc") == 0) {
-       do_change_vnc(mon, target, arg);
+        do_change_vnc(mon, target, arg);
     } else {
-       do_change_block(mon, device, target, arg);
+        do_change_block(mon, device, target, arg);
     }
 }
 
@@ -1510,6 +1535,86 @@ static void do_info_balloon(Monitor *mon)
         monitor_printf(mon, "balloon: actual=%d\n", (int)(actual >> 20));
 }
 
+static void do_acl(Monitor *mon,
+                   const char *command,
+                   const char *aclname,
+                   const char *match,
+                   int has_index,
+                   int index)
+{
+    qemu_acl *acl;
+
+    acl = qemu_acl_find(aclname);
+    if (!acl) {
+        monitor_printf(mon, "acl: unknown list '%s'\n", aclname);
+        return;
+    }
+
+    if (strcmp(command, "show") == 0) {
+        int i = 0;
+        qemu_acl_entry *entry;
+        monitor_printf(mon, "policy: %s\n",
+                       acl->defaultDeny ? "deny" : "allow");
+        TAILQ_FOREACH(entry, &acl->entries, next) {
+            i++;
+            monitor_printf(mon, "%d: %s %s\n", i,
+                           entry->deny ? "deny" : "allow",
+                           entry->match);
+        }
+    } else if (strcmp(command, "reset") == 0) {
+        qemu_acl_reset(acl);
+        monitor_printf(mon, "acl: removed all rules\n");
+    } else if (strcmp(command, "policy") == 0) {
+        if (!match) {
+            monitor_printf(mon, "acl: missing policy parameter\n");
+            return;
+        }
+
+        if (strcmp(match, "allow") == 0) {
+            acl->defaultDeny = 0;
+            monitor_printf(mon, "acl: policy set to 'allow'\n");
+        } else if (strcmp(match, "deny") == 0) {
+            acl->defaultDeny = 1;
+            monitor_printf(mon, "acl: policy set to 'deny'\n");
+        } else {
+            monitor_printf(mon, "acl: unknown policy '%s', expected 'deny' or 'allow'\n", match);
+        }
+    } else if ((strcmp(command, "allow") == 0) ||
+               (strcmp(command, "deny") == 0)) {
+        int deny = strcmp(command, "deny") == 0 ? 1 : 0;
+        int ret;
+
+        if (!match) {
+            monitor_printf(mon, "acl: missing match parameter\n");
+            return;
+        }
+
+        if (has_index)
+            ret = qemu_acl_insert(acl, deny, match, index);
+        else
+            ret = qemu_acl_append(acl, deny, match);
+        if (ret < 0)
+            monitor_printf(mon, "acl: unable to add acl entry\n");
+        else
+            monitor_printf(mon, "acl: added rule at position %d\n", ret);
+    } else if (strcmp(command, "remove") == 0) {
+        int ret;
+
+        if (!match) {
+            monitor_printf(mon, "acl: missing match parameter\n");
+            return;
+        }
+
+        ret = qemu_acl_remove(acl, match);
+        if (ret < 0)
+            monitor_printf(mon, "acl: no matching acl entry\n");
+        else
+            monitor_printf(mon, "acl: removed rule at position %d\n", ret);
+    } else {
+        monitor_printf(mon, "acl: unknown command '%s'\n", command);
+    }
+}
+
 /* Please update qemu-doc.texi when adding or changing commands */
 static const mon_cmd_t mon_cmds[] = {
     { "help|?", "s?", help_cmd,
@@ -1614,6 +1719,12 @@ static const mon_cmd_t mon_cmds[] = {
       "target", "request VM to change it's memory allocation (in MB)" },
     { "set_link", "ss", do_set_link,
       "name [up|down]", "change the link status of a network adapter" },
+    { "acl", "sss?i?", do_acl, "<command> <aclname> [<match>] [<index>]\n",
+                               "acl show vnc.username\n"
+                               "acl policy vnc.username deny\n"
+                               "acl allow vnc.username fred\n"
+                               "acl deny vnc.username bob\n"
+                               "acl reset vnc.username\n" },
     { NULL, NULL, },
 };
 
@@ -1730,7 +1841,7 @@ static target_long monitor_get_ccr (const struct MonitorDef *md, int val)
 
     u = 0;
     for (i = 0; i < 8; i++)
-       u |= env->crf[i] << (32 - (4 * i));
+        u |= env->crf[i] << (32 - (4 * i));
 
     return u;
 }
@@ -2682,7 +2793,7 @@ static void cmd_completion(const char *name, const char *list)
         memcpy(cmd, pstart, len);
         cmd[len] = '\0';
         if (name[0] == '\0' || !strncmp(name, cmd, strlen(name))) {
-            readline_add_completion(cmd);
+            readline_add_completion(cur_mon->rs, cmd);
         }
         if (*p == '\0')
             break;
@@ -2735,7 +2846,7 @@ static void file_completion(const char *input)
             stat(file, &sb);
             if(S_ISDIR(sb.st_mode))
                 pstrcat(file, sizeof(file), "/");
-            readline_add_completion(file);
+            readline_add_completion(cur_mon->rs, file);
         }
     }
     closedir(ffs);
@@ -2748,7 +2859,7 @@ static void block_completion_it(void *opaque, BlockDriverState *bs)
 
     if (input[0] == '\0' ||
         !strncmp(name, (char *)input, strlen(input))) {
-        readline_add_completion(name);
+        readline_add_completion(cur_mon->rs, name);
     }
 }
 
@@ -2778,7 +2889,7 @@ static void parse_cmdline(const char *cmdline,
     *pnb_args = nb_args;
 }
 
-void readline_find_completion(const char *cmdline)
+static void monitor_find_completion(const char *cmdline)
 {
     const char *cmdname;
     char *args[MAX_ARGS];
@@ -2808,7 +2919,7 @@ void readline_find_completion(const char *cmdline)
             cmdname = "";
         else
             cmdname = args[0];
-        readline_set_completion_index(strlen(cmdname));
+        readline_set_completion_index(cur_mon->rs, strlen(cmdname));
         for(cmd = mon_cmds; cmd->name != NULL; cmd++) {
             cmd_completion(cmdname, cmd->name);
         }
@@ -2832,23 +2943,26 @@ void readline_find_completion(const char *cmdline)
         switch(*ptype) {
         case 'F':
             /* file completion */
-            readline_set_completion_index(strlen(str));
+            readline_set_completion_index(cur_mon->rs, strlen(str));
             file_completion(str);
             break;
         case 'B':
             /* block device name completion */
-            readline_set_completion_index(strlen(str));
+            readline_set_completion_index(cur_mon->rs, strlen(str));
             bdrv_iterate(block_completion_it, (void *)str);
             break;
         case 's':
             /* XXX: more generic ? */
             if (!strcmp(cmd->name, "info")) {
-                readline_set_completion_index(strlen(str));
+                readline_set_completion_index(cur_mon->rs, strlen(str));
                 for(cmd = info_cmds; cmd->name != NULL; cmd++) {
                     cmd_completion(str, cmd->name);
                 }
             } else if (!strcmp(cmd->name, "sendkey")) {
-                readline_set_completion_index(strlen(str));
+                char *sep = strrchr(str, '-');
+                if (sep)
+                    str = sep + 1;
+                readline_set_completion_index(cur_mon->rs, strlen(str));
                 for(key = key_defs; key->name != NULL; key++) {
                     cmd_completion(str, key->name);
                 }
@@ -2862,88 +2976,119 @@ void readline_find_completion(const char *cmdline)
         qemu_free(args[i]);
 }
 
-static int term_can_read(void *opaque)
+static int monitor_can_read(void *opaque)
 {
-    return 128;
+    Monitor *mon = opaque;
+
+    return (mon->suspend_cnt == 0) ? 128 : 0;
 }
 
-static void term_read(void *opaque, const uint8_t *buf, int size)
+static void monitor_read(void *opaque, const uint8_t *buf, int size)
 {
+    Monitor *old_mon = cur_mon;
     int i;
 
-    for (i = 0; i < size; i++)
-        readline_handle_byte(buf[i]);
-}
+    cur_mon = opaque;
 
-static int monitor_suspended;
+    if (cur_mon->rs) {
+        for (i = 0; i < size; i++)
+            readline_handle_byte(cur_mon->rs, buf[i]);
+    } else {
+        if (size == 0 || buf[size - 1] != 0)
+            monitor_printf(cur_mon, "corrupted command\n");
+        else
+            monitor_handle_command(cur_mon, (char *)buf);
+    }
+
+    cur_mon = old_mon;
+}
 
 static void monitor_command_cb(Monitor *mon, const char *cmdline, void *opaque)
 {
+    monitor_suspend(mon);
     monitor_handle_command(mon, cmdline);
-    if (!monitor_suspended)
-        readline_show_prompt();
-    else
-        monitor_suspended = 2;
+    monitor_resume(mon);
 }
 
-void monitor_suspend(Monitor *mon)
+int monitor_suspend(Monitor *mon)
 {
-    monitor_suspended = 1;
+    if (!mon->rs)
+        return -ENOTTY;
+    mon->suspend_cnt++;
+    return 0;
 }
 
 void monitor_resume(Monitor *mon)
 {
-    if (monitor_suspended == 2)
-        monitor_start_input();
-    monitor_suspended = 0;
-}
-
-static void monitor_start_input(void)
-{
-    readline_start("(qemu) ", 0, monitor_command_cb, NULL);
-    readline_show_prompt();
+    if (!mon->rs)
+        return;
+    if (--mon->suspend_cnt == 0)
+        readline_show_prompt(mon->rs);
 }
 
-static void term_event(void *opaque, int event)
+static void monitor_event(void *opaque, int event)
 {
     Monitor *mon = opaque;
 
-    if (event != CHR_EVENT_RESET)
-       return;
+    switch (event) {
+    case CHR_EVENT_MUX_IN:
+        readline_restart(mon->rs);
+        monitor_resume(mon);
+        monitor_flush(mon);
+        break;
+
+    case CHR_EVENT_MUX_OUT:
+        if (mon->suspend_cnt == 0)
+            monitor_printf(mon, "\n");
+        monitor_flush(mon);
+        monitor_suspend(mon);
+        break;
 
-    if (!hide_banner)
+    case CHR_EVENT_RESET:
         monitor_printf(mon, "QEMU %s monitor - type 'help' for more "
                        "information\n", QEMU_VERSION);
-    monitor_start_input();
+        if (mon->chr->focus == 0)
+            readline_show_prompt(mon->rs);
+        break;
+    }
 }
 
-static int is_first_init = 1;
 
-void monitor_init(CharDriverState *chr, int show_banner)
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 8
+ * End:
+ */
+
+void monitor_init(CharDriverState *chr, int flags)
 {
-    int i;
+    static int is_first_init = 1;
+    Monitor *mon;
 
     if (is_first_init) {
         key_timer = qemu_new_timer(vm_clock, release_keys, NULL);
-        if (!key_timer)
-            return;
-        for (i = 0; i < MAX_MON; i++) {
-            monitor_hd[i] = NULL;
-        }
         is_first_init = 0;
     }
-    for (i = 0; i < MAX_MON; i++) {
-        if (monitor_hd[i] == NULL) {
-            monitor_hd[i] = chr;
-            break;
-        }
-    }
 
-    hide_banner = !show_banner;
+    mon = qemu_mallocz(sizeof(*mon));
 
-    qemu_chr_add_handlers(chr, term_can_read, term_read, term_event, cur_mon);
+    mon->chr = chr;
+    mon->flags = flags;
+    if (mon->chr->focus != 0)
+        mon->suspend_cnt = 1; /* mux'ed monitors start suspended */
+    if (flags & MONITOR_USE_READLINE) {
+        mon->rs = readline_init(mon, monitor_find_completion);
+        monitor_read_command(mon, 0);
+    }
+
+    qemu_chr_add_handlers(chr, monitor_can_read, monitor_read, monitor_event,
+                          mon);
 
-    readline_start("", 0, monitor_command_cb, NULL);
+    LIST_INSERT_HEAD(&mon_list, mon, entry);
+    if (!cur_mon || (flags & MONITOR_IS_DEFAULT))
+        cur_mon = mon;
 }
 
 static void bdrv_password_cb(Monitor *mon, const char *password, void *opaque)
@@ -2955,16 +3100,18 @@ static void bdrv_password_cb(Monitor *mon, const char *password, void *opaque)
         monitor_printf(mon, "invalid password\n");
         ret = -EPERM;
     }
-    if (password_completion_cb)
-        password_completion_cb(password_opaque, ret);
+    if (mon->password_completion_cb)
+        mon->password_completion_cb(mon->password_opaque, ret);
 
-    monitor_start_input();
+    monitor_read_command(mon, 1);
 }
 
 void monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
                                  BlockDriverCompletionFunc *completion_cb,
                                  void *opaque)
 {
+    int err;
+
     if (!bdrv_key_required(bs)) {
         if (completion_cb)
             completion_cb(opaque, 0);
@@ -2974,8 +3121,11 @@ void monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
     monitor_printf(mon, "%s (%s) is encrypted.\n", bdrv_get_device_name(bs),
                    bdrv_get_encrypted_filename(bs));
 
-    password_completion_cb = completion_cb;
-    password_opaque = opaque;
+    mon->password_completion_cb = completion_cb;
+    mon->password_opaque = opaque;
+
+    err = monitor_read_password(mon, bdrv_password_cb, bs);
 
-    monitor_read_password(mon, bdrv_password_cb, bs);
+    if (err && completion_cb)
+        completion_cb(opaque, err);
 }