Merge "Accept address ranges in r" into honeycomb
diff --git a/include/sysutils/SocketListener.h b/include/sysutils/SocketListener.h
index c7edfeb..6592b01 100644
--- a/include/sysutils/SocketListener.h
+++ b/include/sysutils/SocketListener.h
@@ -30,7 +30,7 @@
     pthread_t               mThread;
 
 public:
-    SocketListener(const char *socketNames, bool listen);
+    SocketListener(const char *socketName, bool listen);
     SocketListener(int socketFd, bool listen);
 
     virtual ~SocketListener();
diff --git a/init/builtins.c b/init/builtins.c
index 915c5aa..490ad48 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -485,6 +485,16 @@
     return symlink(args[1], args[2]);
 }
 
+int do_rm(int nargs, char **args)
+{
+    return unlink(args[1]);
+}
+
+int do_rmdir(int nargs, char **args)
+{
+    return rmdir(args[1]);
+}
+
 int do_sysclktz(int nargs, char **args)
 {
     struct timezone tz;
diff --git a/init/init_parser.c b/init/init_parser.c
index 00e6b9e..0898ae8 100644
--- a/init/init_parser.c
+++ b/init/init_parser.c
@@ -125,6 +125,8 @@
         break;
     case 'r':
         if (!strcmp(s, "estart")) return K_restart;
+        if (!strcmp(s, "mdir")) return K_rmdir;
+        if (!strcmp(s, "m")) return K_rm;
         break;
     case 's':
         if (!strcmp(s, "ervice")) return K_service;
diff --git a/init/keywords.h b/init/keywords.h
index d15ad49..c977fd7 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -15,6 +15,8 @@
 int do_mkdir(int nargs, char **args);
 int do_mount(int nargs, char **args);
 int do_restart(int nargs, char **args);
+int do_rm(int nargs, char **args);
+int do_rmdir(int nargs, char **args);
 int do_setkey(int nargs, char **args);
 int do_setprop(int nargs, char **args);
 int do_setrlimit(int nargs, char **args);
@@ -59,6 +61,8 @@
     KEYWORD(oneshot,     OPTION,  0, 0)
     KEYWORD(onrestart,   OPTION,  0, 0)
     KEYWORD(restart,     COMMAND, 1, do_restart)
+    KEYWORD(rm,          COMMAND, 1, do_rm)
+    KEYWORD(rmdir,       COMMAND, 1, do_rmdir)
     KEYWORD(service,     SECTION, 0, 0)
     KEYWORD(setenv,      OPTION,  2, 0)
     KEYWORD(setkey,      COMMAND, 0, do_setkey)
diff --git a/libsysutils/src/FrameworkClient.cpp b/libsysutils/src/FrameworkClient.cpp
index 562dd67..2f37055 100644
--- a/libsysutils/src/FrameworkClient.cpp
+++ b/libsysutils/src/FrameworkClient.cpp
@@ -14,13 +14,15 @@
 }
 
 int FrameworkClient::sendMsg(const char *msg) {
+    int ret;
     if (mSocket < 0) {
         errno = EHOSTUNREACH;
         return -1;
     }
 
     pthread_mutex_lock(&mWriteMutex);
-    if (write(mSocket, msg, strlen(msg) +1) < 0) {
+    ret = TEMP_FAILURE_RETRY(write(mSocket, msg, strlen(msg) +1));
+    if (ret < 0) {
         SLOGW("Unable to send msg '%s' (%s)", msg, strerror(errno));
     }
     pthread_mutex_unlock(&mWriteMutex);
@@ -28,13 +30,13 @@
 }
 
 int FrameworkClient::sendMsg(const char *msg, const char *data) {
-    char *buffer = (char *) alloca(strlen(msg) + strlen(data) + 1);
+    size_t bufflen = strlen(msg) + strlen(data) + 1;
+    char *buffer = (char *) alloca(bufflen);
     if (!buffer) {
         errno = -ENOMEM;
         return -1;
     }
-    strcpy(buffer, msg);
-    strcat(buffer, data);
+    snprintf(buffer, bufflen, "%s%s", msg, data);
     return sendMsg(buffer);
 }
 
diff --git a/libsysutils/src/FrameworkListener.cpp b/libsysutils/src/FrameworkListener.cpp
index 4da8eb6..3416ceb 100644
--- a/libsysutils/src/FrameworkListener.cpp
+++ b/libsysutils/src/FrameworkListener.cpp
@@ -34,7 +34,8 @@
     char buffer[255];
     int len;
 
-    if ((len = read(c->getSocket(), buffer, sizeof(buffer) -1)) < 0) {
+    len = TEMP_FAILURE_RETRY(read(c->getSocket(), buffer, sizeof(buffer)));
+    if (len < 0) {
         SLOGE("read() failed (%s)", strerror(errno));
         return false;
     } else if (!len)
@@ -45,6 +46,7 @@
 
     for (i = 0; i < len; i++) {
         if (buffer[i] == '\0') {
+            /* IMPORTANT: dispatchCommand() expects a zero-terminated string */
             dispatchCommand(c, buffer + offset);
             offset = i + 1;
         }
@@ -63,6 +65,7 @@
     char tmp[255];
     char *p = data;
     char *q = tmp;
+    char *qlimit = tmp + sizeof(tmp) - 1;
     bool esc = false;
     bool quote = false;
     int k;
@@ -72,6 +75,8 @@
     while(*p) {
         if (*p == '\\') {
             if (esc) {
+                if (q >= qlimit)
+                    goto overflow;
                 *q++ = '\\';
                 esc = false;
             } else
@@ -79,11 +84,15 @@
             p++;
             continue;
         } else if (esc) {
-            if (*p == '"')
+            if (*p == '"') {
+                if (q >= qlimit)
+                    goto overflow;
                 *q++ = '"';
-            else if (*p == '\\')
+            } else if (*p == '\\') {
+                if (q >= qlimit)
+                    goto overflow;
                 *q++ = '\\';
-            else {
+            } else {
                 cli->sendMsg(500, "Unsupported escape sequence", false);
                 goto out;
             }
@@ -101,9 +110,13 @@
             continue;
         }
 
+        if (q >= qlimit)
+            goto overflow;
         *q = *p++;
         if (!quote && *q == ' ') {
             *q = '\0';
+            if (argc >= CMD_ARGS_MAX)
+                goto overflow;
             argv[argc++] = strdup(tmp);
             memset(tmp, 0, sizeof(tmp));
             q = tmp;
@@ -112,6 +125,9 @@
         q++;
     }
 
+    *q = '\0';
+    if (argc >= CMD_ARGS_MAX)
+        goto overflow;
     argv[argc++] = strdup(tmp);
 #if 0
     for (k = 0; k < argc; k++) {
@@ -123,7 +139,7 @@
         cli->sendMsg(500, "Unclosed quotes error", false);
         goto out;
     }
-    
+
     for (i = mCommands->begin(); i != mCommands->end(); ++i) {
         FrameworkCommand *c = *i;
 
@@ -141,4 +157,8 @@
     for (j = 0; j < argc; j++)
         free(argv[j]);
     return;
+
+overflow:
+    cli->sendMsg(500, "Command too long", false);
+    goto out;
 }
diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp
index 86c1f42..c8d3b1f 100644
--- a/libsysutils/src/NetlinkEvent.cpp
+++ b/libsysutils/src/NetlinkEvent.cpp
@@ -56,45 +56,76 @@
     }
 }
 
+/* If the string between 'str' and 'end' begins with 'prefixlen' characters
+ * from the 'prefix' array, then return 'str + prefixlen', otherwise return
+ * NULL.
+ */
+static const char*
+has_prefix(const char* str, const char* end, const char* prefix, size_t prefixlen)
+{
+    if ((end-str) >= (ptrdiff_t)prefixlen && !memcmp(str, prefix, prefixlen))
+        return str + prefixlen;
+    else
+        return NULL;
+}
+
+/* Same as strlen(x) for constant string literals ONLY */
+#define CONST_STRLEN(x)  (sizeof(x)-1)
+
+/* Convenience macro to call has_prefix with a constant string literal  */
+#define HAS_CONST_PREFIX(str,end,prefix)  has_prefix((str),(end),prefix,CONST_STRLEN(prefix))
+
+
 bool NetlinkEvent::decode(char *buffer, int size) {
-    char *s = buffer;
-    char *end;
+    const char *s = buffer;
+    const char *end;
     int param_idx = 0;
     int i;
     int first = 1;
 
+    if (size == 0)
+        return false;
+
+    /* Ensure the buffer is zero-terminated, the code below depends on this */
+    buffer[size-1] = '\0';
+
     end = s + size;
     while (s < end) {
         if (first) {
-            char *p;
-            for (p = s; *p != '@'; p++);
-            p++;
-            mPath = strdup(p);
+            const char *p;
+            /* buffer is 0-terminated, no need to check p < end */
+            for (p = s; *p != '@'; p++) {
+                if (!*p) { /* no '@', should not happen */
+                    return false;
+                }
+            }
+            mPath = strdup(p+1);
             first = 0;
         } else {
-            if (!strncmp(s, "ACTION=", strlen("ACTION="))) {
-                char *a = s + strlen("ACTION=");
+            const char* a;
+            if ((a = HAS_CONST_PREFIX(s, end, "ACTION=")) != NULL) {
                 if (!strcmp(a, "add"))
                     mAction = NlActionAdd;
                 else if (!strcmp(a, "remove"))
                     mAction = NlActionRemove;
                 else if (!strcmp(a, "change"))
                     mAction = NlActionChange;
-            } else if (!strncmp(s, "SEQNUM=", strlen("SEQNUM=")))
-                mSeq = atoi(s + strlen("SEQNUM="));
-            else if (!strncmp(s, "SUBSYSTEM=", strlen("SUBSYSTEM=")))
-                mSubsystem = strdup(s + strlen("SUBSYSTEM="));
-            else
+            } else if ((a = HAS_CONST_PREFIX(s, end, "SEQNUM=")) != NULL) {
+                mSeq = atoi(a);
+            } else if ((a = HAS_CONST_PREFIX(s, end, "SUBSYSTEM=")) != NULL) {
+                mSubsystem = strdup(a);
+            } else if (param_idx < NL_PARAMS_MAX) {
                 mParams[param_idx++] = strdup(s);
+            }
         }
-        s+= strlen(s) + 1;
+        s += strlen(s) + 1;
     }
     return true;
 }
 
 const char *NetlinkEvent::findParam(const char *paramName) {
     size_t len = strlen(paramName);
-    for (int i = 0; mParams[i] && i < NL_PARAMS_MAX; ++i) {
+    for (int i = 0; i < NL_PARAMS_MAX && mParams[i] != NULL; ++i) {
         const char *ptr = mParams[i] + len;
         if (!strncmp(mParams[i], paramName, len) && *ptr == '=')
             return ++ptr;
diff --git a/libsysutils/src/NetlinkListener.cpp b/libsysutils/src/NetlinkListener.cpp
index e2a354e..a4f62c6 100644
--- a/libsysutils/src/NetlinkListener.cpp
+++ b/libsysutils/src/NetlinkListener.cpp
@@ -34,7 +34,8 @@
     int socket = cli->getSocket();
     int count;
 
-    if ((count = recv(socket, mBuffer, sizeof(mBuffer), 0)) < 0) {
+    count = TEMP_FAILURE_RETRY(recv(socket, mBuffer, sizeof(mBuffer), 0));
+    if (count < 0) {
         SLOGE("recv failed (%s)", strerror(errno));
         return false;
     }
diff --git a/libsysutils/src/ServiceManager.cpp b/libsysutils/src/ServiceManager.cpp
index 1ba6ef0..41ac1dd 100644
--- a/libsysutils/src/ServiceManager.cpp
+++ b/libsysutils/src/ServiceManager.cpp
@@ -10,7 +10,39 @@
 ServiceManager::ServiceManager() {
 }
 
+/* The service name should not exceed SERVICE_NAME_MAX to avoid
+ * some weird things. This is due to the fact that:
+ *
+ * - Starting a service is done by writing its name to the "ctl.start"
+ *   system property. This triggers the init daemon to actually start
+ *   the service for us.
+ *
+ * - Stopping the service is done by writing its name to "ctl.stop"
+ *   in a similar way.
+ *
+ * - Reading the status of a service is done by reading the property
+ *   named "init.svc.<name>"
+ *
+ * If strlen(<name>) > (PROPERTY_KEY_MAX-1)-9, then you can start/stop
+ * the service by writing to ctl.start/stop, but you won't be able to
+ * read its state due to the truncation of "init.svc.<name>" into a
+ * zero-terminated buffer of PROPERTY_KEY_MAX characters.
+ */
+#define SERVICE_NAME_MAX  (PROPERTY_KEY_MAX-10)
+
+/* The maximum amount of time to wait for a service to start or stop,
+ * in micro-seconds (really an approximation) */
+#define  SLEEP_MAX_USEC     2000000  /* 2 seconds */
+
+/* The minimal sleeping interval between checking for the service's state
+ * when looping for SLEEP_MAX_USEC */
+#define  SLEEP_MIN_USEC      200000  /* 200 msec */
+
 int ServiceManager::start(const char *name) {
+    if (strlen(name) > SERVICE_NAME_MAX) {
+        SLOGE("Service name '%s' is too long", name);
+        return 0;
+    }
     if (isRunning(name)) {
         SLOGW("Service '%s' is already running", name);
         return 0;
@@ -19,13 +51,14 @@
     SLOGD("Starting service '%s'", name);
     property_set("ctl.start", name);
 
-    int count = 200;
-    while(count--) {
-        sched_yield();
+    int count = SLEEP_MAX_USEC;
+    while(count > 0) {
+        usleep(SLEEP_MIN_USEC);
+        count -= SLEEP_MIN_USEC;
         if (isRunning(name))
             break;
     }
-    if (!count) {
+    if (count <= 0) {
         SLOGW("Timed out waiting for service '%s' to start", name);
         errno = ETIMEDOUT;
         return -1;
@@ -35,6 +68,10 @@
 }
 
 int ServiceManager::stop(const char *name) {
+    if (strlen(name) > SERVICE_NAME_MAX) {
+        SLOGE("Service name '%s' is too long", name);
+        return 0;
+    }
     if (!isRunning(name)) {
         SLOGW("Service '%s' is already stopped", name);
         return 0;
@@ -43,28 +80,33 @@
     SLOGD("Stopping service '%s'", name);
     property_set("ctl.stop", name);
 
-    int count = 200;
-    while(count--) {
-        sched_yield();
+    int count = SLEEP_MAX_USEC;
+    while(count > 0) {
+        usleep(SLEEP_MIN_USEC);
+        count -= SLEEP_MIN_USEC;
         if (!isRunning(name))
             break;
     }
 
-    if (!count) {
+    if (count <= 0) {
         SLOGW("Timed out waiting for service '%s' to stop", name);
         errno = ETIMEDOUT;
         return -1;
     }
-    SLOGD("Sucessfully stopped '%s'", name);
+    SLOGD("Successfully stopped '%s'", name);
     return 0;
 }
 
 bool ServiceManager::isRunning(const char *name) {
     char propVal[PROPERTY_VALUE_MAX];
-    char propName[255];
+    char propName[PROPERTY_KEY_MAX];
+    int  ret;
 
-    snprintf(propName, sizeof(propVal), "init.svc.%s", name);
-
+    ret = snprintf(propName, sizeof(propName), "init.svc.%s", name);
+    if (ret > (int)sizeof(propName)-1) {
+        SLOGD("Service name '%s' is too long", name);
+        return false;
+    }
 
     if (property_get(propName, propVal, NULL)) {
         if (!strcmp(propVal, "running"))
diff --git a/libsysutils/src/SocketClient.cpp b/libsysutils/src/SocketClient.cpp
index c9c7417..a6aed26 100644
--- a/libsysutils/src/SocketClient.cpp
+++ b/libsysutils/src/SocketClient.cpp
@@ -32,14 +32,24 @@
 
 int SocketClient::sendMsg(int code, const char *msg, bool addErrno) {
     char *buf;
+    const char* arg;
+    const char* fmt;
+    char tmp[1];
+    int  len;
 
     if (addErrno) {
-        buf = (char *) alloca(strlen(msg) + strlen(strerror(errno)) + 8);
-        sprintf(buf, "%.3d %s (%s)", code, msg, strerror(errno));
+        fmt = "%.3d %s (%s)";
+        arg = strerror(errno);
     } else {
-        buf = (char *) alloca(strlen(msg) + strlen("XXX "));
-        sprintf(buf, "%.3d %s", code, msg);
+        fmt = "%.3d %s";
+        arg = NULL;
     }
+    /* Measure length of required buffer */
+    len = snprintf(tmp, sizeof tmp, fmt, code, msg, arg);
+    /* Allocate in the stack, then write to it */
+    buf = (char*)alloca(len+1);
+    snprintf(buf, len+1, fmt, code, msg, arg);
+    /* Send the zero-terminated message */
     return sendMsg(buf);
 }
 
@@ -68,18 +78,24 @@
 
     pthread_mutex_lock(&mWriteMutex);
     while (brtw > 0) {
-        if ((rc = write(mSocket, p, brtw)) < 0) {
-            SLOGW("write error (%s)", strerror(errno));
-            pthread_mutex_unlock(&mWriteMutex);
-            return -1;
-        } else if (!rc) {
+        rc = write(mSocket, p, brtw);
+        if (rc > 0) {
+            p += rc;
+            brtw -= rc;
+            continue;
+        }
+
+        if (rc < 0 && errno == EINTR)
+            continue;
+
+        pthread_mutex_unlock(&mWriteMutex);
+        if (rc == 0) {
             SLOGW("0 length write :(");
             errno = EIO;
-            pthread_mutex_unlock(&mWriteMutex);
-            return -1;
+        } else {
+            SLOGW("write error (%s)", strerror(errno));
         }
-        p += rc;
-        brtw -= rc;
+        return -1;
     }
     pthread_mutex_unlock(&mWriteMutex);
     return 0;
diff --git a/libsysutils/src/SocketListener.cpp b/libsysutils/src/SocketListener.cpp
index 1bc06db..677c57d 100644
--- a/libsysutils/src/SocketListener.cpp
+++ b/libsysutils/src/SocketListener.cpp
@@ -54,7 +54,7 @@
         close(mCtrlPipe[1]);
     }
     SocketClientCollection::iterator it;
-    for (it = mClients->begin(); it != mClients->end(); ++it) {
+    for (it = mClients->begin(); it != mClients->end();) {
         delete (*it);
         it = mClients->erase(it);
     }
@@ -96,8 +96,10 @@
 
 int SocketListener::stopListener() {
     char c = 0;
+    int  rc;
 
-    if (write(mCtrlPipe[1], &c, 1) != 1) {
+    rc = TEMP_FAILURE_RETRY(write(mCtrlPipe[1], &c, 1));
+    if (rc != 1) {
         SLOGE("Error writing to control pipe (%s)", strerror(errno));
         return -1;
     }
@@ -118,7 +120,7 @@
     }
 
     SocketClientCollection::iterator it;
-    for (it = mClients->begin(); it != mClients->end(); ++it) {
+    for (it = mClients->begin(); it != mClients->end();) {
         delete (*it);
         it = mClients->erase(it);
     }
@@ -135,11 +137,13 @@
 
 void SocketListener::runListener() {
 
+    SocketClientCollection *pendingList = new SocketClientCollection();
+
     while(1) {
         SocketClientCollection::iterator it;
         fd_set read_fds;
         int rc = 0;
-        int max = 0;
+        int max = -1;
 
         FD_ZERO(&read_fds);
 
@@ -154,13 +158,16 @@
 
         pthread_mutex_lock(&mClientsLock);
         for (it = mClients->begin(); it != mClients->end(); ++it) {
-            FD_SET((*it)->getSocket(), &read_fds);
-            if ((*it)->getSocket() > max)
-                max = (*it)->getSocket();
+            int fd = (*it)->getSocket();
+            FD_SET(fd, &read_fds);
+            if (fd > max)
+                max = fd;
         }
         pthread_mutex_unlock(&mClientsLock);
 
         if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {
+            if (errno == EINTR)
+                continue;
             SLOGE("select failed (%s)", strerror(errno));
             sleep(1);
             continue;
@@ -171,10 +178,14 @@
             break;
         if (mListen && FD_ISSET(mSock, &read_fds)) {
             struct sockaddr addr;
-            socklen_t alen = sizeof(addr);
+            socklen_t alen;
             int c;
 
-            if ((c = accept(mSock, &addr, &alen)) < 0) {
+            do {
+                alen = sizeof(addr);
+                c = accept(mSock, &addr, &alen);
+            } while (c < 0 && errno == EINTR);
+            if (c < 0) {
                 SLOGE("accept failed (%s)", strerror(errno));
                 sleep(1);
                 continue;
@@ -184,27 +195,41 @@
             pthread_mutex_unlock(&mClientsLock);
         }
 
-        do {
-            pthread_mutex_lock(&mClientsLock);
-            for (it = mClients->begin(); it != mClients->end(); ++it) {
-                int fd = (*it)->getSocket();
-                if (FD_ISSET(fd, &read_fds)) {
-                    pthread_mutex_unlock(&mClientsLock);
-                    if (!onDataAvailable(*it)) {
-                        close(fd);
-                        pthread_mutex_lock(&mClientsLock);
-                        delete *it;
-                        it = mClients->erase(it);
-                        pthread_mutex_unlock(&mClientsLock);
-                    }
-                    FD_CLR(fd, &read_fds);
-                    pthread_mutex_lock(&mClientsLock);
-                    continue;
-                }
+        /* Add all active clients to the pending list first */
+        pendingList->clear();
+        pthread_mutex_lock(&mClientsLock);
+        for (it = mClients->begin(); it != mClients->end(); ++it) {
+            int fd = (*it)->getSocket();
+            if (FD_ISSET(fd, &read_fds)) {
+                pendingList->push_back(*it);
             }
-            pthread_mutex_unlock(&mClientsLock);
-        } while (0);
+        }
+        pthread_mutex_unlock(&mClientsLock);
+
+        /* Process the pending list, since it is owned by the thread,
+         * there is no need to lock it */
+        while (!pendingList->empty()) {
+            /* Pop the first item from the list */
+            it = pendingList->begin();
+            SocketClient* c = *it;
+            pendingList->erase(it);
+            /* Process it, if false is returned, remove and destroy it */
+            if (!onDataAvailable(c)) {
+                /* Remove the client from our array */
+                pthread_mutex_lock(&mClientsLock);
+                for (it = mClients->begin(); it != mClients->end(); ++it) {
+                    if (*it == c) {
+                        mClients->erase(it);
+                        break;
+                    }
+                }
+                pthread_mutex_unlock(&mClientsLock);
+                /* Destroy the client */
+                delete c;
+            }
+        }
     }
+    delete pendingList;
 }
 
 void SocketListener::sendBroadcast(int code, const char *msg, bool addErrno) {
diff --git a/rootdir/etc/init.goldfish.rc b/rootdir/etc/init.goldfish.rc
index 6f30843..1ac09ca 100644
--- a/rootdir/etc/init.goldfish.rc
+++ b/rootdir/etc/init.goldfish.rc
@@ -6,6 +6,7 @@
 
 on boot
     setprop ARGH ARGH
+    setprop net.eth0.gw 10.0.2.2
     setprop net.eth0.dns1 10.0.2.3
     setprop net.gprs.local-ip 10.0.2.15
     setprop ro.radio.use-ppp no
@@ -22,6 +23,11 @@
     stop dund
     stop akmd
 
+# start essential services
+    start qemud
+    start goldfish-logcat
+    start goldfish-setup
+
     setprop ro.setupwizard.mode EMULATOR
 
 # enable Google-specific location features,
@@ -42,6 +48,8 @@
 # something else.
 
 service goldfish-setup /system/etc/init.goldfish.sh
+    user root
+    group root
     oneshot
 
 service qemud /system/bin/qemud
@@ -52,7 +60,7 @@
 # program to check wether it runs on the emulator
 # if it does, it redirects its output to the device
 # named by the androidboot.console kernel option
-# if not, is simply exit immediately
+# if not, is simply exits immediately
 
 service goldfish-logcat /system/bin/logcat -Q
     oneshot
diff --git a/rootdir/etc/init.goldfish.sh b/rootdir/etc/init.goldfish.sh
index cfa2c82..1156dd7 100755
--- a/rootdir/etc/init.goldfish.sh
+++ b/rootdir/etc/init.goldfish.sh
@@ -1,8 +1,26 @@
 #!/system/bin/sh
 
+# Setup networking when boot starts
 ifconfig eth0 10.0.2.15 netmask 255.255.255.0 up
 route add default gw 10.0.2.2 dev eth0
 
+# ro.kernel.android.qemud is normally set when we
+# want the RIL (radio interface layer) to talk to
+# the emulated modem through qemud.
+#
+# However, this will be undefined in two cases:
+#
+# - When we want the RIL to talk directly to a guest
+#   serial device that is connected to a host serial
+#   device by the emulator.
+#
+# - We don't want to use the RIL but the VM-based
+#   modem emulation that runs inside the guest system
+#   instead.
+#
+# The following detects the latter case and sets up the
+# system for it.
+#
 qemud=`getprop ro.kernel.android.qemud`
 case "$qemud" in
     "")
@@ -18,17 +36,18 @@
     ;;
 esac
 
-num_dns=`getprop ro.kernel.android.ndns`
+# Setup additionnal DNS servers if needed
+num_dns=`getprop ro.kernel.ndns`
 case "$num_dns" in
     2) setprop net.eth0.dns2 10.0.2.4
-    ;;
+       ;;
     3) setprop net.eth0.dns2 10.0.2.4
-    setprop net.eth0.dns3 10.0.2.5
-    ;;
+       setprop net.eth0.dns3 10.0.2.5
+       ;;
     4) setprop net.eth0.dns2 10.0.2.4
-    setprop net.eth0.dns3 10.0.2.5
-    setprop net.eth0.dns4 10.0.2.6
-    ;;
+       setprop net.eth0.dns3 10.0.2.5
+       setprop net.eth0.dns4 10.0.2.6
+       ;;
 esac
 
 # disable boot animation for a faster boot sequence when needed
@@ -42,10 +61,6 @@
 #
 /system/bin/qemu-props
 
-# this line doesn't really do anything useful. however without it the
-# previous setprop doesn't seem to apply for some really odd reason
-setprop ro.qemu.init.completed 1
-
 # set up the second interface (for inter-emulator connections)
 # if required
 my_ip=`getprop net.shared_net_ip`
diff --git a/rootdir/etc/ueventd.goldfish.rc b/rootdir/etc/ueventd.goldfish.rc
index e69de29..b5828e7 100644
--- a/rootdir/etc/ueventd.goldfish.rc
+++ b/rootdir/etc/ueventd.goldfish.rc
@@ -0,0 +1,4 @@
+# These settings are specific to running under the Android emulator
+/dev/qemu_trace           0666   system     system
+/dev/ttyS*                0666   system     system
+/proc                     0666   system     system
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 1136057..f76ee37 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -297,6 +297,9 @@
 on property:vold.decrypt=trigger_post_fs_data
     trigger post-fs-data
 
+on property:vold.decrypt=trigger_restart_min_framework
+    class_start main
+
 on property:vold.decrypt=trigger_restart_framework
     class_start main
     class_start late_start
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc
index a3ddf2b..d343bd4 100644
--- a/rootdir/ueventd.rc
+++ b/rootdir/ueventd.rc
@@ -63,7 +63,6 @@
 /dev/snd/dsp1             0660   system     audio
 /dev/snd/mixer            0660   system     audio
 /dev/smd0                 0640   radio      radio
-/dev/qemu_trace           0666   system     system
 /dev/qmi                  0640   radio      radio
 /dev/qmi0                 0640   radio      radio
 /dev/qmi1                 0640   radio      radio
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c
index 21a44ce..cc2cce7 100644
--- a/sdcard/sdcard.c
+++ b/sdcard/sdcard.c
@@ -116,6 +116,15 @@
 
 #define PATH_BUFFER_SIZE 1024
 
+static void normalize_name(char *name)
+{
+    if (force_lower_case) {
+        char ch;
+        while ((ch = *name) != 0)
+            *name++ = tolower(ch);
+    }
+}
+
 /*
  * Get the real-life absolute path to a node.
  *   node: start at this node
@@ -146,6 +155,7 @@
         out[0] = '/';
     }
 
+    normalize_name(out);
     return out;
 }
 
@@ -457,15 +467,6 @@
     return 0;
 }
 
-static void normalize_name(char *name)
-{
-    if (force_lower_case) {
-        char ch;
-        while ((ch = *name) != 0)
-            *name++ = tolower(ch);
-    }
-}
-
 static void recursive_fix_files(const char* path) {
     DIR* dir;
     struct dirent* entry;
@@ -549,7 +550,6 @@
 
     switch (hdr->opcode) {
     case FUSE_LOOKUP: { /* bytez[] -> entry_out */
-        normalize_name((char*) data);
         TRACE("LOOKUP %llx %s\n", hdr->nodeid, (char*) data);
         lookup_entry(fuse, node, (char*) data, hdr->unique);
         return;
@@ -609,8 +609,6 @@
         char *name = ((char*) data) + sizeof(*req);
         int res;
 
-        normalize_name(name);
-
         TRACE("MKNOD %s @ %llx\n", name, hdr->nodeid);
         path = node_get_path(node, buffer, name);
 
@@ -630,8 +628,6 @@
         char *name = ((char*) data) + sizeof(*req);
         int res;
 
-        normalize_name(name);
-
         TRACE("MKDIR %s @ %llx 0%o\n", name, hdr->nodeid, req->mode);
         path = node_get_path(node, buffer, name);
 
@@ -647,7 +643,6 @@
     case FUSE_UNLINK: { /* bytez[] -> */
         char *path, buffer[PATH_BUFFER_SIZE];
         int res;
-        normalize_name((char*) data);
         TRACE("UNLINK %s @ %llx\n", (char*) data, hdr->nodeid);
         path = node_get_path(node, buffer, (char*) data);
         res = unlink(path);
@@ -657,7 +652,6 @@
     case FUSE_RMDIR: { /* bytez[] -> */
         char *path, buffer[PATH_BUFFER_SIZE];
         int res;
-        normalize_name((char*) data);
         TRACE("RMDIR %s @ %llx\n", (char*) data, hdr->nodeid);
         path = node_get_path(node, buffer, (char*) data);
         res = rmdir(path);
@@ -674,9 +668,6 @@
         struct node *newparent;
         int res;
 
-        normalize_name(oldname);
-        normalize_name(newname);
-
         TRACE("RENAME %s->%s @ %llx\n", oldname, newname, hdr->nodeid);
 
         target = lookup_child_by_name(node, oldname);
@@ -723,7 +714,6 @@
             return;
         }
 
-        normalize_name(buffer);
         path = node_get_path(node, buffer, 0);
         TRACE("OPEN %llx '%s' 0%o fh=%p\n", hdr->nodeid, path, req->flags, h);
         h->fd = open(path, req->flags);
@@ -825,7 +815,6 @@
             return;
         }
 
-        normalize_name(buffer);
         path = node_get_path(node, buffer, 0);
         TRACE("OPENDIR %llx '%s'\n", hdr->nodeid, path);
         h->d = opendir(path);