Add new "qemu monitor" command to the console.

This allows you to access the QEMU virtual machine monitor directly
from the console (instead of playing with the command-line to do it).

The implementation of the 'quit' command has been modified to simply
close the connection, instead of stopping the emulator program.

This patch introduces changes that allow a console session to be
detached and redirected at runtime to other internal services of
the emulator program. This will be useful in the future to implement
other features.

+ doc typo
+ add proper definitions for CONFIG_ANDROID on config-host.h
+ remove obsolete sysdeps.h dependency in android/console.c

Change-Id: If16cfe41c12a26eb8f56e3a9c24452eafa5efab4
diff --git a/CHANGES.TXT b/CHANGES.TXT
index 726701c..183c45e 100644
--- a/CHANGES.TXT
+++ b/CHANGES.TXT
@@ -62,6 +62,12 @@
  - Add a PulseAudio audio backend on Linux. It will be used by default
    unless it's impossible to connect to the PA daemon.
 
+ - It is now possible to access the QEMU monitor from the console.
+   Just type "qemu monitor" and you will be at the monitor prompt.
+
+   Note that the monitor 'quit' command will not stop the emulator,
+   but will simply close the connection instead.
+
 ==============================================================================
 Changes between 7.0 and 6.0
 
diff --git a/android-configure.sh b/android-configure.sh
index 70cd3de..8b65c22 100755
--- a/android-configure.sh
+++ b/android-configure.sh
@@ -466,6 +466,8 @@
     echo "#define MAP_ANONYMOUS    MAP_ANON" >> $config_h
 fi
 
+echo "#define CONFIG_ANDROID       1" >> $config_h
+
 log "Generate   : $config_h"
 
 echo "Ready to go. Type 'make' to build emulator"
diff --git a/android/config/darwin-x86/config-host.h b/android/config/darwin-x86/config-host.h
index b25d8fe..f02a109 100644
--- a/android/config/darwin-x86/config-host.h
+++ b/android/config/darwin-x86/config-host.h
@@ -13,3 +13,4 @@
 #define CONFIG_BSD 1
 #define CONFIG_SKINS 1
 #define CONFIG_UNAME_RELEASE ""
+#define CONFIG_ANDROID 1
diff --git a/android/config/freebsd-x86/config-host.h b/android/config/freebsd-x86/config-host.h
index 805e5de..844698a 100644
--- a/android/config/freebsd-x86/config-host.h
+++ b/android/config/freebsd-x86/config-host.h
@@ -11,3 +11,4 @@
 #define CONFIG_BSD 1
 #define CONFIG_UNAME_RELEASE ""
 #define CONFIG_SKINS 1
+#define CONFIG_ANDROID 1
diff --git a/android/config/linux-x86/config-host.h b/android/config/linux-x86/config-host.h
index 904dbfa..1a86213 100644
--- a/android/config/linux-x86/config-host.h
+++ b/android/config/linux-x86/config-host.h
@@ -12,3 +12,4 @@
 #define CONFIG_IOTHREAD 1
 #define CONFIG_IOVEC 1
 #define CONFIG_FDATASYNC 1
+#define CONFIG_ANDROID 1
diff --git a/android/config/windows/config-host.h b/android/config/windows/config-host.h
index 6e18a02..a1b022e 100644
--- a/android/config/windows/config-host.h
+++ b/android/config/windows/config-host.h
@@ -9,3 +9,4 @@
 #define QEMU_PKGVERSION "Android"
 #define CONFIG_SKINS 1
 #define CONFIG_UNAME_RELEASE ""
+#define CONFIG_ANDROID 1
diff --git a/android/console.c b/android/console.c
index c3500e4..d341d71 100644
--- a/android/console.c
+++ b/android/console.c
@@ -38,6 +38,7 @@
 #include "android/utils/stralloc.h"
 #include "tcpdump.h"
 #include "net.h"
+#include "monitor.h"
 
 #include <stdlib.h>
 #include <stdio.h>
@@ -55,13 +56,6 @@
 #include "libslirp.h"
 #endif
 
-/* set to 1 to use the i/o and event functions
- * defined in "telephony/sysdeps.h"
- */
-#define  USE_SYSDEPS  0
-
-#include "sysdeps.h"
-
 #define  DEBUG  1
 
 #if 1
@@ -88,12 +82,7 @@
 } RedirRec, *Redir;
 
 
-#if USE_SYSDEPS
-typedef SysChannel  Socket;
-#else /* !USE_SYSDEPS */
-typedef int         Socket;
-#endif /* !USE_SYSDEPS */
-
+typedef int Socket;
 
 typedef struct ControlClientRec_
 {
@@ -178,19 +167,53 @@
     return -1;
 }
 
+/* Detach the socket descriptor from a given ControlClient
+ * and return its value. This is useful either when destroying
+ * the client, or redirecting the socket to another service.
+ *
+ * NOTE: this does not close the socket.
+ */
+static int
+control_client_detach( ControlClient  client )
+{
+    int  result;
+
+    if (client->sock < 0)
+        return -1;
+
+    qemu_set_fd_handler( client->sock, NULL, NULL, NULL );
+    result = client->sock;
+    client->sock = -1;
+
+    return result;
+}
+
+static void  control_client_read( void*  _client );  /* forward */
+
+/* Reattach a control client to a given socket.
+ * Return the old socket descriptor for the client.
+ */
+static int
+control_client_reattach( ControlClient client, int fd )
+{
+    int result = control_client_detach(client);
+    client->sock = fd;
+    qemu_set_fd_handler( fd, control_client_read, NULL, client );
+    return result;
+}
+
 static void
 control_client_destroy( ControlClient  client )
 {
     ControlGlobal  global = client->global;
     ControlClient  *pnode = &global->clients;
+    int            sock;
 
     D(( "destroying control client %p\n", client ));
 
-#if USE_SYSDEPS
-    sys_channel_on( client->sock, 0, NULL, NULL );
-#else
-    qemu_set_fd_handler( client->sock, NULL, NULL, NULL );
-#endif
+    sock = control_client_detach( client );
+    if (sock >= 0)
+        socket_close(sock);
 
     for ( ;; ) {
         ControlClient  node = *pnode;
@@ -204,18 +227,9 @@
         pnode = &node->next;
     }
 
-#if USE_SYSDEPS
-    sys_channel_close( client->sock );
-    client->sock = NULL;
-#else
-    socket_close( client->sock );
-    client->sock = -1;
-#endif
-
     free( client );
 }
 
-static void  control_client_read( void*  _client );  /* forward */
 
 
 static void  control_control_write( ControlClient  client, const char*  buff, int  len )
@@ -226,11 +240,7 @@
         len = strlen(buff);
 
     while (len > 0) {
-#if USE_SYSDEPS
-        ret = sys_channel_write( client->sock, buff, len );
-#else
         ret = socket_send( client->sock, buff, len);
-#endif
         if (ret < 0) {
             if (errno != EINTR && errno != EWOULDBLOCK && errno != EAGAIN)
                 return;
@@ -263,23 +273,15 @@
     ControlClient  client = calloc( sizeof(*client), 1 );
 
     if (client) {
-#if !USE_SYSDEPS
         socket_set_nodelay( socket );
         socket_set_nonblock( socket );
-#endif
         client->finished = 0;
         client->global  = global;
         client->sock    = socket;
         client->next    = global->clients;
         global->clients = client;
 
-#if USE_SYSDEPS
-        sys_channel_on( socket, SYS_EVENT_READ,
-                        (SysChannelCallback) control_client_read,
-                        client );
-#else
         qemu_set_fd_handler( socket, control_client_read, NULL, client );
-#endif
     }
     return client;
 }
@@ -490,11 +492,7 @@
     int            size;
 
     D(( "in control_client read: " ));
-#if USE_SYSDEPS
-    size = sys_channel_read( client->sock, buf, sizeof(buf) );
-#else
     size = socket_recv( client->sock, buf, sizeof(buf) );
-#endif
     if (size < 0) {
         D(( "size < 0, exiting with %d: %s\n", errno, errno_str ));
 		if (errno != EWOULDBLOCK && errno != EAGAIN && errno != EINTR)
@@ -549,13 +547,6 @@
 
     D(( "control_global_accept: just in (fd=%p)\n", (void*)global->listen_fd ));
 
-#if USE_SYSDEPS
-    fd = sys_channel_create_tcp_handler( global->listen_fd );
-    if (fd == NULL) {
-        perror("accept");
-        return;
-    }
-#else
     for(;;) {
         fd = socket_accept( global->listen_fd, NULL );
         if (fd < 0 && errno != EINTR) {
@@ -569,7 +560,6 @@
     }
 
     socket_set_xreuseaddr( fd );
-#endif
 
     D(( "control_global_accept: creating new client\n" ));
     client = control_client_create( fd, global );
@@ -586,28 +576,11 @@
                      int            control_port )
 {
     Socket  fd;
-#if !USE_SYSDEPS
     int     ret;
     SockAddress  sockaddr;
-#endif
 
     memset( global, 0, sizeof(*global) );
 
-    sys_main_init();
-
-#if USE_SYSDEPS
-    fd = sys_channel_create_tcp_server( control_port );
-    if (fd == NULL) {
-        return -1;
-    }
-
-    D(("global fd=%p\n", fd));
-
-    global->listen_fd = fd;
-    sys_channel_on( fd, SYS_EVENT_READ,
-                    (SysChannelCallback) control_global_accept,
-                    global );
-#else
     fd = socket_create_inet( SOCKET_STREAM );
     if (fd < 0) {
         perror("socket");
@@ -637,7 +610,6 @@
     global->listen_fd = fd;
 
     qemu_set_fd_handler( fd, control_global_accept, NULL, global );
-#endif
     return 0;
 }
 
@@ -1959,7 +1931,7 @@
 static int
 do_geo_fix( ControlClient  client, char*  args )
 {
-#define  MAX_GEO_PARAMS  4
+#define  MAX_GEO_PARAMS  5
     char*   p = args;
     int     n_params = 0;
     double  params[ MAX_GEO_PARAMS ];
@@ -2151,6 +2123,49 @@
 /********************************************************************************************/
 /********************************************************************************************/
 /*****                                                                                 ******/
+/*****                           Q E M U   C O M M A N D S                             ******/
+/*****                                                                                 ******/
+/********************************************************************************************/
+/********************************************************************************************/
+
+static int
+do_qemu_monitor( ControlClient client, char* args )
+{
+    char             socketname[32];
+    int              fd;
+    CharDriverState* cs;
+
+    if (args != NULL) {
+        control_write( client, "KO: no argument for 'qemu monitor'\r\n" );
+        return -1;
+    }
+    /* Detach the client socket, and re-attach it to a monitor */
+    fd = control_client_detach(client);
+    snprintf(socketname, sizeof socketname, "tcp:socket=%d", fd);
+    cs = qemu_chr_open("monitor", socketname, NULL);
+    if (cs == NULL) {
+        control_client_reattach(client, fd);
+        control_write( client, "KO: internal error: could not detach from console !\r\n" );
+        return -1;
+    }
+    monitor_init(cs, MONITOR_USE_READLINE|MONITOR_QUIT_DOESNT_EXIT);
+    control_client_destroy(client);
+    return 0;
+}
+
+static const CommandDefRec  qemu_commands[] =
+{
+    { "monitor", "enter QEMU monitor",
+    "Enter the QEMU virtual machine monitor\r\n",
+    NULL, do_qemu_monitor, NULL },
+
+    { NULL, NULL, NULL, NULL, NULL, NULL }
+};
+
+
+/********************************************************************************************/
+/********************************************************************************************/
+/*****                                                                                 ******/
 /*****                           M A I N   C O M M A N D S                             ******/
 /*****                                                                                 ******/
 /********************************************************************************************/
@@ -2212,6 +2227,10 @@
     "allows you to modify the emulator window\r\n", NULL,
     NULL, window_commands },
 
+    { "qemu", "QEMU-specific commands",
+    "allows to connect to the QEMU virtual machine monitor\r\n", NULL,
+    NULL, qemu_commands },
+
     { NULL, NULL, NULL, NULL, NULL, NULL }
 };
 
diff --git a/console.h b/console.h
index fd283ba..3d0c4f4 100644
--- a/console.h
+++ b/console.h
@@ -330,9 +330,4 @@
 /* curses.c */
 void curses_display_init(DisplayState *ds, int full_screen);
 
-#if defined(CONFIG_ANDROID)
-/* android-display.c */
-void android_display_init(DisplayState *ds);
-#endif
-
 #endif
diff --git a/docs/CHAR-DEVICES.TXT b/docs/CHAR-DEVICES.TXT
index 9805a4a..d6b2701 100644
--- a/docs/CHAR-DEVICES.TXT
+++ b/docs/CHAR-DEVICES.TXT
@@ -20,9 +20,9 @@
     were really written (which can be 0) and the caller must deal with it.
     This is very similar to writing to a non-blocking BSD socket on Unix.
 
-       int  qemu_chr_read( CharDriverState*  cs,
-                           const uint8_t*    data,
-                           int               datalen );
+       int  qemu_chr_write( CharDriverState*  cs,
+                            const uint8_t*    data,
+                            int               datalen );
 
     This function may return -1 in case of error, but this depends entirely
     on the underlying implementation (some of them will just return 0 instead).
diff --git a/monitor.c b/monitor.c
index f640bf8..3c23397 100644
--- a/monitor.c
+++ b/monitor.c
@@ -70,6 +70,8 @@
     const char *help;
 } mon_cmd_t;
 
+#define MON_CMD_T_INITIALIZER { NULL, NULL, NULL, NULL, NULL }
+
 struct Monitor {
     CharDriverState *chr;
     int flags;
@@ -81,6 +83,7 @@
     BlockDriverCompletionFunc *password_completion_cb;
     void *password_opaque;
     QLIST_ENTRY(Monitor) entry;
+    int has_quit;
 };
 
 static QLIST_HEAD(mon_list, Monitor) mon_list;
@@ -409,7 +412,11 @@
 
 static void do_quit(Monitor *mon)
 {
-    exit(0);
+    if ((mon->flags & MONITOR_QUIT_DOESNT_EXIT) == 0) {
+        exit(0);
+    }
+    /* we cannot destroy the monitor just yet, so flag it instead */
+    mon->has_quit = 1;
 }
 
 static int eject_device(Monitor *mon, BlockDriverState *bs, int force)
@@ -1661,7 +1668,7 @@
 
 static const mon_cmd_t mon_cmds[] = {
 #include "qemu-monitor.h"
-    { NULL, NULL, },
+    MON_CMD_T_INITIALIZER
 };
 
 /* Please update qemu-monitor.hx when adding or changing commands */
@@ -1741,7 +1748,7 @@
       "", "show balloon information" },
     { "qtree", "", do_info_qtree,
       "", "show device tree" },
-    { NULL, NULL, },
+    MON_CMD_T_INITIALIZER
 };
 
 /*******************************************************************/
@@ -1759,6 +1766,8 @@
     int type;
 } MonitorDef;
 
+#define MONITOR_DEF_INITIALIZER  { NULL, 0, NULL, 0 }
+
 #if defined(TARGET_I386)
 static target_long monitor_get_pc (const struct MonitorDef *md, int val)
 {
@@ -2085,7 +2094,7 @@
     { "fprs", offsetof(CPUState, fprs) },
 #endif
 #endif
-    { NULL },
+    MONITOR_DEF_INITIALIZER
 };
 
 static void expr_error(Monitor *mon, const char *msg)
@@ -2938,6 +2947,8 @@
     return (mon->suspend_cnt == 0) ? 128 : 0;
 }
 
+static void monitor_done(Monitor *mon); // forward
+
 static void monitor_read(void *opaque, const uint8_t *buf, int size)
 {
     Monitor *old_mon = cur_mon;
@@ -2955,6 +2966,9 @@
             monitor_handle_command(cur_mon, (char *)buf);
     }
 
+    if (cur_mon->has_quit) {
+        monitor_done(cur_mon);
+    }
     cur_mon = old_mon;
 }
 
@@ -3046,6 +3060,19 @@
         cur_mon = mon;
 }
 
+static void monitor_done(Monitor *mon)
+{
+    if (cur_mon == mon)
+        cur_mon = NULL;
+
+    QLIST_REMOVE(mon, entry);
+
+    readline_free(mon->rs);
+    qemu_chr_close(mon->chr);
+
+    qemu_free(mon);
+}
+
 static void bdrv_password_cb(Monitor *mon, const char *password, void *opaque)
 {
     BlockDriverState *bs = opaque;
diff --git a/monitor.h b/monitor.h
index 13e8cc7..5a4eef8 100644
--- a/monitor.h
+++ b/monitor.h
@@ -8,8 +8,9 @@
 extern Monitor *cur_mon;
 
 /* flags for monitor_init */
-#define MONITOR_IS_DEFAULT    0x01
-#define MONITOR_USE_READLINE  0x02
+#define MONITOR_IS_DEFAULT        0x01
+#define MONITOR_USE_READLINE      0x02
+#define MONITOR_QUIT_DOESNT_EXIT  0x04  /* prevent 'quit' from exiting the emulator */
 
 void monitor_init(CharDriverState *chr, int flags);
 
diff --git a/qemu-char-android.c b/qemu-char-android.c
index b468606..ca854b9 100644
--- a/qemu-char-android.c
+++ b/qemu-char-android.c
@@ -2088,6 +2088,17 @@
             fd = unix_connect(host_str);
         }
     } else {
+#ifdef CONFIG_ANDROID
+        if (!strncmp(host_str,"socket=",7)) {
+            char *end;
+            long val = strtol(host_str+7, &end, 10);
+            if (val <= 0 || end == host_str+7) {
+                printf("Invalid socket number: '%s'\n", host_str+7);
+                goto fail;
+            }
+            fd = (int) val;
+        } else
+#endif
         if (is_listen) {
             fd = inet_listen(host_str, chr->filename + offset, 256 - offset,
                              SOCKET_STREAM, 0);
diff --git a/readline.c b/readline.c
index 92f9cd1..16ec704 100644
--- a/readline.c
+++ b/readline.c
@@ -474,3 +474,12 @@
 
     return rs;
 }
+
+void readline_free(ReadLineState *rs)
+{
+    if (rs) {
+        rs->mon = NULL;
+        rs->completion_finder = NULL;
+        qemu_free(rs);
+    }
+}
diff --git a/readline.h b/readline.h
index fc9806e..f46f92a 100644
--- a/readline.h
+++ b/readline.h
@@ -52,4 +52,6 @@
 ReadLineState *readline_init(Monitor *mon,
                              ReadLineCompletionFunc *completion_finder);
 
+void readline_free(ReadLineState *rs);
+
 #endif /* !READLINE_H */
diff --git a/telephony/android_modem.c b/telephony/android_modem.c
index 1e060dd..2f4c98e 100644
--- a/telephony/android_modem.c
+++ b/telephony/android_modem.c
@@ -359,6 +359,8 @@
 
     modem->sim = asimcard_create(base_port);
 
+    sys_main_init();
+
     return  modem;
 }