merge from master
diff --git a/adb/adb.c b/adb/adb.c
index e8d2c8f..283ebce 100644
--- a/adb/adb.c
+++ b/adb/adb.c
@@ -832,6 +832,7 @@
 {
 #if !ADB_HOST
     int secure = 0;
+    int port;
     char value[PROPERTY_VALUE_MAX];
 #endif
 
@@ -850,7 +851,7 @@
     HOST = 1;
     usb_vendors_init();
     usb_init();
-    local_init();
+    local_init(ADB_LOCAL_TRANSPORT_PORT);
 
     if(install_listener("tcp:5037", "*smartsocket*", NULL)) {
         exit(1);
@@ -918,14 +919,19 @@
     }
 
         /* for the device, start the usb transport if the
-        ** android usb device exists, otherwise start the
-        ** network transport.
+        ** android usb device exists and "service.adb.tcp"
+        ** is not set, otherwise start the network transport.
         */
-    if(access("/dev/android_adb", F_OK) == 0 ||
-       access("/dev/android", F_OK) == 0) {
+    property_get("service.adb.tcp.port", value, "0");
+    if (sscanf(value, "%d", &port) == 1 && port > 0) {
+        // listen on TCP port specified by service.adb.tcp.port property
+        local_init(port);
+    } else if (access("/dev/android_adb", F_OK) == 0) {
+        // listen on USB
         usb_init();
     } else {
-        local_init();
+        // listen on default port
+        local_init(ADB_LOCAL_TRANSPORT_PORT);
     }
     init_jdwp();
 #endif
@@ -1006,6 +1012,43 @@
         return 0;
     }
 
+    // add a new TCP transport
+    if (!strncmp(service, "connect:", 8)) {
+        char buffer[4096];
+        int port, fd;
+        char* host = service + 8;
+        char* portstr = strchr(host, ':');
+
+        if (!portstr) {
+            snprintf(buffer, sizeof(buffer), "unable to parse %s as <host>:<port>\n", host);
+            goto done;
+        }
+        // zero terminate host by overwriting the ':'
+        *portstr++ = 0;
+        if (sscanf(portstr, "%d", &port) == 0) {
+            snprintf(buffer, sizeof(buffer), "bad port number %s\n", portstr);
+            goto done;
+        }
+
+        fd = socket_network_client(host, port, SOCK_STREAM);
+        if (fd < 0) {
+            snprintf(buffer, sizeof(buffer), "unable to connect to %s:%d\n", host, port);
+            goto done;
+        }
+
+        D("client: connected on remote on fd %d\n", fd);
+        close_on_exec(fd);
+        disable_tcp_nagle(fd);
+        snprintf(buf, sizeof buf, "%s:%d", host, port);
+        register_socket_transport(fd, buf, port, 0);
+        snprintf(buffer, sizeof(buffer), "connected to %s:%d\n", host, port);
+
+done:
+        snprintf(buf, sizeof(buf), "OKAY%04x%s",(unsigned)strlen(buffer),buffer);
+        writex(reply_fd, buf, strlen(buf));
+        return 0;
+    }
+
     // returns our value for ADB_SERVER_VERSION
     if (!strcmp(service, "version")) {
         char version[12];
diff --git a/adb/adb.h b/adb/adb.h
index 8d57bf2..713666f 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -33,7 +33,7 @@
 #define ADB_VERSION_MAJOR 1         // Used for help/version information
 #define ADB_VERSION_MINOR 0         // Used for help/version information
 
-#define ADB_SERVER_VERSION    22    // Increment this when we want to force users to start a new adb server
+#define ADB_SERVER_VERSION    25    // Increment this when we want to force users to start a new adb server
 
 typedef struct amessage amessage;
 typedef struct apacket apacket;
@@ -262,15 +262,18 @@
 void   kick_transport( atransport*  t );
 
 /* initialize a transport object's func pointers and state */
-int  init_socket_transport(atransport *t, int s, int port);
-void init_usb_transport(atransport *t, usb_handle *usb);
+int  init_socket_transport(atransport *t, int s, int port, int local);
+void init_usb_transport(atransport *t, usb_handle *usb, int state);
 
 /* for MacOS X cleanup */
 void close_usb_devices();
 
 /* cause new transports to be init'd and added to the list */
-void register_socket_transport(int s, const char *serial, int  port);
-void register_usb_transport(usb_handle *h, const char *serial);
+void register_socket_transport(int s, const char *serial, int port, int local);
+void register_usb_transport(usb_handle *h, const char *serial, unsigned writeable);
+
+/* this should only be used for transports with connection_state == CS_NOPERM */
+void unregister_usb_transport(usb_handle *usb);
 
 int service_to_fd(const char *name);
 #if ADB_HOST
@@ -357,7 +360,7 @@
 #define ADB_PROTOCOL           0x1
 
 
-void local_init();
+void local_init(int port);
 int  local_connect(int  port);
 
 /* usb host/client interface */
@@ -384,7 +387,7 @@
 #define CS_DEVICE     2
 #define CS_HOST       3
 #define CS_RECOVERY   4
-#define CS_ERROR      5
+#define CS_NOPERM     5 /* Insufficient permissions to communicate with the device */
 
 extern int HOST;
 
diff --git a/adb/commandline.c b/adb/commandline.c
index 5414e5e..411bb82 100644
--- a/adb/commandline.c
+++ b/adb/commandline.c
@@ -96,7 +96,8 @@
         " -e                            - directs command to the only running emulator.\n"
         "                                 returns an error if more than one emulator is running.\n"
         " -s <serial number>            - directs command to the USB device or emulator with\n"
-        "                                 the given serial number\n"
+        "                                 the given serial number. Overrides ANDROID_SERIAL\n"
+        "                                 envivornment variable.\n"
         " -p <product name or path>     - simple product name like 'sooner', or\n"
         "                                 a relative/absolute path to a product\n"
         "                                 out directory like 'out/target/product/sooner'.\n"
@@ -104,6 +105,7 @@
         "                                 environment variable is used, which must\n"
         "                                 be an absolute path.\n"
         " devices                       - list all connected devices\n"
+        " connect <host>:<port>         - connect to a device via TCP/IP"
         "\n"
         "device commands:\n"
         "  adb push <local> <remote>    - copy file/dir to device\n"
@@ -148,7 +150,9 @@
         "  adb status-window            - continuously print device status for a specified device\n"
         "  adb remount                  - remounts the /system partition on the device read-write\n"
         "  adb reboot [bootloader|recovery] - reboots the device, optionally into the bootloader or recovery program\n"
-        "  adb root                     - restarts adb with root permissions\n"
+        "  adb root                     - restarts the adbd daemon with root permissions\n"
+        "  adb usb                      - restarts the adbd daemon listening on USB"
+        "  adb tcpip <port>             - restarts the adbd daemon listening on TCP on the specified port"
         "\n"
         "networking:\n"
         "  adb ppp <tty> [parameters]   - Run PPP over USB.\n"
@@ -767,6 +771,8 @@
     }
     // TODO: also try TARGET_PRODUCT/TARGET_DEVICE as a hint
 
+    serial = getenv("ANDROID_SERIAL");
+
         /* modifiers and flags */
     while(argc > 0) {
         if(!strcmp(argv[0],"nodaemon")) {
@@ -847,6 +853,22 @@
         }
     }
 
+    if(!strcmp(argv[0], "connect")) {
+        char *tmp;
+        if (argc != 2) {
+            fprintf(stderr, "Usage: adb connect <host>:<port>\n");
+            return 1;
+        }
+        snprintf(buf, sizeof buf, "host:%s:%s", argv[0], argv[1]);
+        tmp = adb_query(buf);
+        if(tmp) {
+            printf("%s\n", tmp);
+            return 0;
+        } else {
+            return 1;
+        }
+    }
+
     if (!strcmp(argv[0], "emu")) {
         return adb_send_emulator_command(argc, argv);
     }
@@ -905,35 +927,15 @@
         return 0;
     }
 
-    if(!strcmp(argv[0], "remount")) {
-        int fd = adb_connect("remount:");
-        if(fd >= 0) {
-            read_and_dump(fd);
-            adb_close(fd);
-            return 0;
-        }
-        fprintf(stderr,"error: %s\n", adb_error());
-        return 1;
-    }
-
-    if(!strcmp(argv[0], "reboot")) {
-        int fd;
+    if(!strcmp(argv[0], "remount") || !strcmp(argv[0], "reboot")
+            || !strcmp(argv[0], "tcpip") || !strcmp(argv[0], "usb")
+            || !strcmp(argv[0], "root")) {
+        char command[100];
         if (argc > 1)
-            snprintf(buf, sizeof(buf), "reboot:%s", argv[1]);
+            snprintf(command, sizeof(command), "%s:%s", argv[0], argv[1]);
         else
-            snprintf(buf, sizeof(buf), "reboot:");
-        fd = adb_connect(buf);
-        if(fd >= 0) {
-            read_and_dump(fd);
-            adb_close(fd);
-            return 0;
-        }
-        fprintf(stderr,"error: %s\n", adb_error());
-        return 1;
-    }
-
-    if(!strcmp(argv[0], "root")) {
-        int fd = adb_connect("root:");
+            snprintf(command, sizeof(command), "%s:", argv[0]);
+        int fd = adb_connect(command);
         if(fd >= 0) {
             read_and_dump(fd);
             adb_close(fd);
diff --git a/adb/get_my_path_darwin.c b/adb/get_my_path_darwin.c
index 00dfee4..6125cb4 100644
--- a/adb/get_my_path_darwin.c
+++ b/adb/get_my_path_darwin.c
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <utils/executablepath.h>
 #import <Carbon/Carbon.h>
 #include <unistd.h>
 
diff --git a/adb/services.c b/adb/services.c
index 517da55..2864ac9 100644
--- a/adb/services.c
+++ b/adb/services.c
@@ -120,6 +120,7 @@
         if (strcmp(value, "1") != 0) {
             snprintf(buf, sizeof(buf), "adbd cannot run as root in production builds\n");
             writex(fd, buf, strlen(buf));
+            adb_close(fd);
             return;
         }
 
@@ -134,13 +135,52 @@
     }
 }
 
-void reboot_service(int fd, char *arg)
+void restart_tcp_service(int fd, void *cookie)
+{
+    char buf[100];
+    char value[PROPERTY_VALUE_MAX];
+    int port = (int)cookie;
+
+    if (port <= 0) {
+        snprintf(buf, sizeof(buf), "invalid port\n");
+        writex(fd, buf, strlen(buf));
+        adb_close(fd);
+        return;
+    }
+
+    snprintf(value, sizeof(value), "%d", port);
+    property_set("service.adb.tcp.port", value);
+    snprintf(buf, sizeof(buf), "restarting in TCP mode port: %d\n", port);
+    writex(fd, buf, strlen(buf));
+    adb_close(fd);
+
+    // quit, and init will restart us in TCP mode
+    sleep(1);
+    exit(1);
+}
+
+void restart_usb_service(int fd, void *cookie)
+{
+    char buf[100];
+
+    property_set("service.adb.tcp.port", "0");
+    snprintf(buf, sizeof(buf), "restarting in USB mode\n");
+    writex(fd, buf, strlen(buf));
+    adb_close(fd);
+
+    // quit, and init will restart us in USB mode
+    sleep(1);
+    exit(1);
+}
+
+void reboot_service(int fd, void *arg)
 {
     char buf[100];
     int ret;
 
     sync();
-    ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, arg);
+    ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
+                    LINUX_REBOOT_CMD_RESTART2, (char *)arg);
     if (ret < 0) {
         snprintf(buf, sizeof(buf), "reboot failed: %s\n", strerror(errno));
         writex(fd, buf, strlen(buf));
@@ -415,12 +455,20 @@
     } else if(!strncmp(name, "remount:", 8)) {
         ret = create_service_thread(remount_service, NULL);
     } else if(!strncmp(name, "reboot:", 7)) {
-        char* arg = name + 7;
+        const char* arg = name + 7;
         if (*name == 0)
             arg = NULL;
-        ret = create_service_thread(reboot_service, arg);
+        ret = create_service_thread(reboot_service, (void *)arg);
     } else if(!strncmp(name, "root:", 5)) {
         ret = create_service_thread(restart_root_service, NULL);
+    } else if(!strncmp(name, "tcpip:", 6)) {
+        int port;
+        if (sscanf(name + 6, "%d", &port) == 0) {
+            port = 0;
+        }
+        ret = create_service_thread(restart_tcp_service, (void *)port);
+    } else if(!strncmp(name, "usb:", 4)) {
+        ret = create_service_thread(restart_usb_service, NULL);
 #endif
 #if 0
     } else if(!strncmp(name, "echo:", 5)){
diff --git a/adb/transport.c b/adb/transport.c
index c76f1a5..617dabf 100644
--- a/adb/transport.c
+++ b/adb/transport.c
@@ -584,18 +584,37 @@
         return;
     }
 
+    /* don't create transport threads for inaccessible devices */
+    if (t->connection_state != CS_NOPERM) {
         /* initial references are the two threads */
-    t->ref_count = 2;
+        t->ref_count = 2;
 
-    if(adb_socketpair(s)) {
-        fatal_errno("cannot open transport socketpair");
+        if(adb_socketpair(s)) {
+            fatal_errno("cannot open transport socketpair");
+        }
+
+        D("transport: %p (%d,%d) starting\n", t, s[0], s[1]);
+
+        t->transport_socket = s[0];
+        t->fd = s[1];
+
+        D("transport: %p install %d\n", t, t->transport_socket );
+        fdevent_install(&(t->transport_fde),
+                        t->transport_socket,
+                        transport_socket_events,
+                        t);
+
+        fdevent_set(&(t->transport_fde), FDE_READ);
+
+        if(adb_thread_create(&input_thread_ptr, input_thread, t)){
+            fatal_errno("cannot create input thread");
+        }
+
+        if(adb_thread_create(&output_thread_ptr, output_thread, t)){
+            fatal_errno("cannot create output thread");
+        }
     }
 
-    D("transport: %p (%d,%d) starting\n", t, s[0], s[1]);
-
-    t->transport_socket = s[0];
-    t->fd = s[1];
-
         /* put us on the master device list */
     adb_mutex_lock(&transport_lock);
     t->next = &transport_list;
@@ -604,22 +623,6 @@
     t->prev->next = t;
     adb_mutex_unlock(&transport_lock);
 
-    D("transport: %p install %d\n", t, t->transport_socket );
-    fdevent_install(&(t->transport_fde),
-                    t->transport_socket,
-                    transport_socket_events,
-                    t);
-
-    fdevent_set(&(t->transport_fde), FDE_READ);
-
-    if(adb_thread_create(&input_thread_ptr, input_thread, t)){
-        fatal_errno("cannot create input thread");
-    }
-
-    if(adb_thread_create(&output_thread_ptr, output_thread, t)){
-        fatal_errno("cannot create output thread");
-    }
-
     t->disconnects.next = t->disconnects.prev = &t->disconnects;
 
     update_transports();
@@ -717,6 +720,12 @@
 
     adb_mutex_lock(&transport_lock);
     for (t = transport_list.next; t != &transport_list; t = t->next) {
+        if (t->connection_state == CS_NOPERM) {
+        if (error_out)
+            *error_out = "insufficient permissions for device";
+            continue;
+        }
+
         /* check for matching serial number */
         if (serial) {
             if (t->serial && !strcmp(serial, t->serial)) {
@@ -763,7 +772,6 @@
                 *error_out = "device offline";
             result = NULL;
         }
-
          /* check for required connection state */
         if (result && state != CS_ANY && result->connection_state != state) {
             if (error_out)
@@ -793,6 +801,7 @@
     case CS_DEVICE: return "device";
     case CS_HOST: return "host";
     case CS_RECOVERY: return "recovery";
+    case CS_NOPERM: return "no permissions";
     default: return "unknown";
     }
 }
@@ -807,9 +816,10 @@
         /* XXX OVERRUN PROBLEMS XXX */
     adb_mutex_lock(&transport_lock);
     for(t = transport_list.next; t != &transport_list; t = t->next) {
-        len = snprintf(p, end - p, "%s\t%s\n",
-                t->serial ? t->serial : "",
-                statename(t));
+        const char* serial = t->serial;
+        if (!serial || !serial[0])
+            serial = "????????????";
+        len = snprintf(p, end - p, "%s\t%s\n", serial, statename(t));
 
         if (p + len >= end) {
             /* discard last line if buffer is too short */
@@ -839,11 +849,11 @@
 }
 #endif // ADB_HOST
 
-void register_socket_transport(int s, const char *serial, int  port)
+void register_socket_transport(int s, const char *serial, int port, int local)
 {
     atransport *t = calloc(1, sizeof(atransport));
     D("transport: %p init'ing for socket %d, on port %d\n", t, s, port);
-    if ( init_socket_transport(t, s, port) < 0 ) {
+    if ( init_socket_transport(t, s, port, local) < 0 ) {
         adb_close(s);
         free(t);
         return;
@@ -854,18 +864,32 @@
     register_transport(t);
 }
 
-void register_usb_transport(usb_handle *usb, const char *serial)
+void register_usb_transport(usb_handle *usb, const char *serial, unsigned writeable)
 {
     atransport *t = calloc(1, sizeof(atransport));
     D("transport: %p init'ing for usb_handle %p (sn='%s')\n", t, usb,
       serial ? serial : "");
-    init_usb_transport(t, usb);
+    init_usb_transport(t, usb, (writeable ? CS_OFFLINE : CS_NOPERM));
     if(serial) {
         t->serial = strdup(serial);
     }
     register_transport(t);
 }
 
+/* this should only be used for transports with connection_state == CS_NOPERM */
+void unregister_usb_transport(usb_handle *usb)
+{
+    atransport *t;
+    adb_mutex_lock(&transport_lock);
+    for(t = transport_list.next; t != &transport_list; t = t->next) {
+        if (t->usb == usb && t->connection_state == CS_NOPERM) {
+            t->next->prev = t->prev;
+            t->prev->next = t->next;
+            break;
+        }
+     }
+    adb_mutex_unlock(&transport_lock);
+}
 
 #undef TRACE_TAG
 #define TRACE_TAG  TRACE_RWX
diff --git a/adb/transport_local.c b/adb/transport_local.c
index be01f29..c528d1f 100644
--- a/adb/transport_local.c
+++ b/adb/transport_local.c
@@ -122,7 +122,7 @@
         close_on_exec(fd);
         disable_tcp_nagle(fd);
         snprintf(buf, sizeof buf, "%s%d", LOCAL_CLIENT_PREFIX, port - 1);
-        register_socket_transport(fd, buf, port);
+        register_socket_transport(fd, buf, port, 1);
         return 0;
     }
     return -1;
@@ -147,17 +147,18 @@
     return 0;
 }
 
-static void *server_socket_thread(void *x)
+static void *server_socket_thread(void * arg)
 {
     int serverfd, fd;
     struct sockaddr addr;
     socklen_t alen;
+    int port = (int)arg;
 
     D("transport: server_socket_thread() starting\n");
     serverfd = -1;
     for(;;) {
         if(serverfd == -1) {
-            serverfd = socket_inaddr_any_server(ADB_LOCAL_TRANSPORT_PORT, SOCK_STREAM);
+            serverfd = socket_inaddr_any_server(port, SOCK_STREAM);
             if(serverfd < 0) {
                 D("server: cannot bind socket yet\n");
                 adb_sleep_ms(1000);
@@ -167,20 +168,20 @@
         }
 
         alen = sizeof(addr);
-        D("server: trying to get new connection from %d\n", ADB_LOCAL_TRANSPORT_PORT);
+        D("server: trying to get new connection from %d\n", port);
         fd = adb_socket_accept(serverfd, &addr, &alen);
         if(fd >= 0) {
             D("server: new connection on fd %d\n", fd);
             close_on_exec(fd);
             disable_tcp_nagle(fd);
-            register_socket_transport(fd,"host",ADB_LOCAL_TRANSPORT_PORT);
+            register_socket_transport(fd, "host", port, 1);
         }
     }
     D("transport: server_socket_thread() exiting\n");
     return 0;
 }
 
-void local_init(void)
+void local_init(int port)
 {
     adb_thread_t thr;
     void* (*func)(void *);
@@ -193,7 +194,7 @@
 
     D("transport: local %s init\n", HOST ? "client" : "server");
 
-    if(adb_thread_create(&thr, func, 0)) {
+    if(adb_thread_create(&thr, func, (void *)port)) {
         fatal_errno("cannot create local socket %s thread",
                     HOST ? "client" : "server");
     }
@@ -225,7 +226,7 @@
     adb_close(t->fd);
 }
 
-int init_socket_transport(atransport *t, int s, int  port)
+int init_socket_transport(atransport *t, int s, int port, int local)
 {
     int  fail = 0;
 
@@ -239,7 +240,7 @@
     t->type = kTransportLocal;
 
 #if ADB_HOST
-    if (HOST) {
+    if (HOST && local) {
         adb_mutex_lock( &local_transports_lock );
         {
             int  index = (port - ADB_LOCAL_TRANSPORT_PORT)/2;
diff --git a/adb/transport_usb.c b/adb/transport_usb.c
index 3737c5c..2584163 100644
--- a/adb/transport_usb.c
+++ b/adb/transport_usb.c
@@ -110,7 +110,7 @@
     usb_kick(t->usb);
 }
 
-void init_usb_transport(atransport *t, usb_handle *h)
+void init_usb_transport(atransport *t, usb_handle *h, int state)
 {
     D("transport: usb\n");
     t->close = remote_close;
@@ -118,7 +118,7 @@
     t->read_from_remote = remote_read;
     t->write_to_remote = remote_write;
     t->sync_token = 1;
-    t->connection_state = CS_OFFLINE;
+    t->connection_state = state;
     t->type = kTransportUsb;
     t->usb = h;
 
diff --git a/adb/usb_linux.c b/adb/usb_linux.c
index 537122d..863af1d 100644
--- a/adb/usb_linux.c
+++ b/adb/usb_linux.c
@@ -57,6 +57,7 @@
     unsigned char ep_out;
 
     unsigned zero_mask;
+    unsigned writeable;
 
     struct usbdevfs_urb urb_in;
     struct usbdevfs_urb urb_out;
@@ -115,7 +116,7 @@
 }
 
 static void register_device(const char *dev_name, unsigned char ep_in, unsigned char ep_out,
-                            int ifc, const char *serial, unsigned zero_mask);
+                            int ifc, int serial_index, unsigned zero_mask);
 
 static inline int badname(const char *name)
 {
@@ -125,19 +126,18 @@
     return 0;
 }
 
-static int find_usb_device(const char *base,
-                           void (*register_device_callback) (const char *, unsigned char, unsigned char, int, const char *, unsigned))
+static void find_usb_device(const char *base,
+        void (*register_device_callback)
+                (const char *, unsigned char, unsigned char, int, int, unsigned))
 {
     char busname[32], devname[32];
     unsigned char local_ep_in, local_ep_out;
     DIR *busdir , *devdir ;
     struct dirent *de;
     int fd ;
-    int found_device = 0;
-    char serial[256];
 
     busdir = opendir(base);
-    if(busdir == 0) return 0;
+    if(busdir == 0) return;
 
     while((de = readdir(busdir)) != 0) {
         if(badname(de->d_name)) continue;
@@ -168,7 +168,7 @@
             }
 
 //            DBGX("[ scanning %s ]\n", devname);
-            if((fd = unix_open(devname, O_RDWR)) < 0) {
+            if((fd = unix_open(devname, O_RDONLY)) < 0) {
                 continue;
             }
 
@@ -263,67 +263,13 @@
                         local_ep_out = ep1->bEndpointAddress;
                     }
 
-                        // read the device's serial number
-                    serial[0] = 0;
-                    memset(serial, 0, sizeof(serial));
-                    if (device->iSerialNumber) {
-                        struct usbdevfs_ctrltransfer  ctrl;
-                        __u16 buffer[128];
-                        __u16 languages[128];
-                        int i, result;
-                        int languageCount = 0;
-
-                        memset(languages, 0, sizeof(languages));
-                        memset(&ctrl, 0, sizeof(ctrl));
-
-                            // read list of supported languages
-                        ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
-                        ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
-                        ctrl.wValue = (USB_DT_STRING << 8) | 0;
-                        ctrl.wIndex = 0;
-                        ctrl.wLength = sizeof(languages);
-                        ctrl.data = languages;
-
-                        result = ioctl(fd, USBDEVFS_CONTROL, &ctrl);
-                        if (result > 0)
-                            languageCount = (result - 2) / 2;
-
-                        for (i = 1; i <= languageCount; i++) {
-                            memset(buffer, 0, sizeof(buffer));
-                            memset(&ctrl, 0, sizeof(ctrl));
-
-                            ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
-                            ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
-                            ctrl.wValue = (USB_DT_STRING << 8) | device->iSerialNumber;
-                            ctrl.wIndex = languages[i];
-                            ctrl.wLength = sizeof(buffer);
-                            ctrl.data = buffer;
-
-                            result = ioctl(fd, USBDEVFS_CONTROL, &ctrl);
-                            if (result > 0) {
-                                int i;
-                                    // skip first word, and copy the rest to the serial string, changing shorts to bytes.
-                                result /= 2;
-                                for (i = 1; i < result; i++)
-                                    serial[i - 1] = buffer[i];
-                                serial[i - 1] = 0;
-                                break;
-                            }
-                        }
-                    }
-
                     register_device_callback(devname, local_ep_in, local_ep_out,
-                            interface->bInterfaceNumber, serial, zero_mask);
+                            interface->bInterfaceNumber, device->iSerialNumber, zero_mask);
 
-                    found_device = 1;
                     break;
                 } else {
                     // seek next interface descriptor
-                    if (i < interfaces - 1) {
-                        while (bufptr[1] != USB_DT_INTERFACE) {
-                            bufptr += bufptr[0];
-                        }
-                    }
+                    bufptr += (USB_DT_ENDPOINT_SIZE * interface->bNumEndpoints);
                  }
             } // end of for
 
@@ -332,8 +278,6 @@
         closedir(devdir);
     } //end of busdir while
     closedir(busdir);
-
-    return found_device;
 }
 
 void usb_cleanup()
@@ -537,26 +481,30 @@
     if(h->dead == 0) {
         h->dead = 1;
 
-        /* HACK ALERT!
-        ** Sometimes we get stuck in ioctl(USBDEVFS_REAPURB).
-        ** This is a workaround for that problem.
-        */
-        if (h->reaper_thread) {
-            pthread_kill(h->reaper_thread, SIGALRM);
-        }
+        if (h->writeable) {
+            /* HACK ALERT!
+            ** Sometimes we get stuck in ioctl(USBDEVFS_REAPURB).
+            ** This is a workaround for that problem.
+            */
+            if (h->reaper_thread) {
+                pthread_kill(h->reaper_thread, SIGALRM);
+            }
 
-        /* cancel any pending transactions
-        ** these will quietly fail if the txns are not active,
-        ** but this ensures that a reader blocked on REAPURB
-        ** will get unblocked
-        */
-        ioctl(h->desc, USBDEVFS_DISCARDURB, &h->urb_in);
-        ioctl(h->desc, USBDEVFS_DISCARDURB, &h->urb_out);
-        h->urb_in.status = -ENODEV;
-        h->urb_out.status = -ENODEV;
-        h->urb_in_busy = 0;
-        h->urb_out_busy = 0;
-        adb_cond_broadcast(&h->notify);
+            /* cancel any pending transactions
+            ** these will quietly fail if the txns are not active,
+            ** but this ensures that a reader blocked on REAPURB
+            ** will get unblocked
+            */
+            ioctl(h->desc, USBDEVFS_DISCARDURB, &h->urb_in);
+            ioctl(h->desc, USBDEVFS_DISCARDURB, &h->urb_out);
+            h->urb_in.status = -ENODEV;
+            h->urb_out.status = -ENODEV;
+            h->urb_in_busy = 0;
+            h->urb_out_busy = 0;
+            adb_cond_broadcast(&h->notify);
+        } else {
+            unregister_usb_transport(h);
+        }
     }
     adb_mutex_unlock(&h->lock);
 }
@@ -580,11 +528,11 @@
 
 static void register_device(const char *dev_name,
                             unsigned char ep_in, unsigned char ep_out,
-                            int interface,
-                            const char *serial, unsigned zero_mask)
+                            int interface, int serial_index, unsigned zero_mask)
 {
     usb_handle* usb = 0;
     int n = 0;
+    char serial[256];
 
         /* Since Linux will not reassign the device ID (and dev_name)
         ** as long as the device is open, we can add to the list here
@@ -610,6 +558,7 @@
     usb->ep_in = ep_in;
     usb->ep_out = ep_out;
     usb->zero_mask = zero_mask;
+    usb->writeable = 1;
 
     adb_cond_init(&usb->notify, 0);
     adb_mutex_init(&usb->lock, 0);
@@ -618,10 +567,66 @@
     usb->reaper_thread = 0;
 
     usb->desc = unix_open(usb->fname, O_RDWR);
-    if(usb->desc < 0) goto fail;
-    D("[ usb open %s fd = %d]\n", usb->fname, usb->desc);
-    n = ioctl(usb->desc, USBDEVFS_CLAIMINTERFACE, &interface);
-    if(n != 0) goto fail;
+    if(usb->desc < 0) {
+        /* if we fail, see if have read-only access */
+        usb->desc = unix_open(usb->fname, O_RDONLY);
+        if(usb->desc < 0) goto fail;
+        usb->writeable = 0;
+        D("[ usb open read-only %s fd = %d]\n", usb->fname, usb->desc);
+    } else {
+        D("[ usb open %s fd = %d]\n", usb->fname, usb->desc);
+        n = ioctl(usb->desc, USBDEVFS_CLAIMINTERFACE, &interface);
+        if(n != 0) goto fail;
+    }
+
+        /* read the device's serial number */
+    serial[0] = 0;
+    memset(serial, 0, sizeof(serial));
+    if (serial_index) {
+        struct usbdevfs_ctrltransfer  ctrl;
+        __u16 buffer[128];
+        __u16 languages[128];
+        int i, result;
+        int languageCount = 0;
+
+        memset(languages, 0, sizeof(languages));
+        memset(&ctrl, 0, sizeof(ctrl));
+
+            // read list of supported languages
+        ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
+        ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
+        ctrl.wValue = (USB_DT_STRING << 8) | 0;
+        ctrl.wIndex = 0;
+        ctrl.wLength = sizeof(languages);
+        ctrl.data = languages;
+
+        result = ioctl(usb->desc, USBDEVFS_CONTROL, &ctrl);
+        if (result > 0)
+            languageCount = (result - 2) / 2;
+
+        for (i = 1; i <= languageCount; i++) {
+            memset(buffer, 0, sizeof(buffer));
+            memset(&ctrl, 0, sizeof(ctrl));
+
+            ctrl.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE;
+            ctrl.bRequest = USB_REQ_GET_DESCRIPTOR;
+            ctrl.wValue = (USB_DT_STRING << 8) | serial_index;
+            ctrl.wIndex = languages[i];
+            ctrl.wLength = sizeof(buffer);
+            ctrl.data = buffer;
+
+            result = ioctl(usb->desc, USBDEVFS_CONTROL, &ctrl);
+            if (result > 0) {
+                int i;
+                // skip first word, and copy the rest to the serial string, changing shorts to bytes.
+                result /= 2;
+                for (i = 1; i < result; i++)
+                    serial[i - 1] = buffer[i];
+                serial[i - 1] = 0;
+                break;
+            }
+        }
+    }
 
         /* add to the end of the active handles */
     adb_mutex_lock(&usb_lock);
@@ -631,7 +636,7 @@
     usb->next->prev = usb;
     adb_mutex_unlock(&usb_lock);
 
-    register_usb_transport(usb, serial);
+    register_usb_transport(usb, serial, usb->writeable);
     return;
 
 fail:
diff --git a/adb/usb_linux_client.c b/adb/usb_linux_client.c
index 530bd04..0a21c6f 100644
--- a/adb/usb_linux_client.c
+++ b/adb/usb_linux_client.c
@@ -72,7 +72,7 @@
         usb->fd = fd;
 
         D("[ usb_thread - registering device ]\n");
-        register_usb_transport(usb, 0);
+        register_usb_transport(usb, 0, 1);
     }
 
     // never gets here
diff --git a/adb/usb_osx.c b/adb/usb_osx.c
index 4892c38..00d02da 100644
--- a/adb/usb_osx.c
+++ b/adb/usb_osx.c
@@ -194,30 +194,54 @@
         kr = (*dev)->GetDeviceProduct(dev, &product);
         kr = (*dev)->USBGetSerialNumberStringIndex(dev, &serialIndex);
 
-        if (serialIndex > 0) {
-            IOUSBDevRequest req;
-            UInt16          buffer[256];
+	if (serialIndex > 0) {
+		IOUSBDevRequest req;
+		UInt16          buffer[256];
+		UInt16          languages[128];
 
-            req.bmRequestType =
-                USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
-            req.bRequest = kUSBRqGetDescriptor;
-            req.wValue = (kUSBStringDesc << 8) | serialIndex;
-            req.wIndex = 0;
-            req.pData = buffer;
-            req.wLength = sizeof(buffer);
-            kr = (*dev)->DeviceRequest(dev, &req);
+		memset(languages, 0, sizeof(languages));
 
-            if (kr == kIOReturnSuccess && req.wLenDone > 0) {
-                int i, count;
+		req.bmRequestType =
+			USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
+		req.bRequest = kUSBRqGetDescriptor;
+		req.wValue = (kUSBStringDesc << 8) | 0;
+		req.wIndex = 0;
+		req.pData = languages;
+		req.wLength = sizeof(languages);
+		kr = (*dev)->DeviceRequest(dev, &req);
 
-                // skip first word, and copy the rest to the serial string,
-                // changing shorts to bytes.
-                count = (req.wLenDone - 1) / 2;
-                for (i = 0; i < count; i++)
-                  serial[i] = buffer[i + 1];
-                serial[i] = 0;
-            }
-        }
+		if (kr == kIOReturnSuccess && req.wLenDone > 0) {
+
+			int langCount = (req.wLenDone - 2) / 2, lang;
+
+			for (lang = 1; lang <= langCount; lang++) {
+
+                                memset(buffer, 0, sizeof(buffer));
+                                memset(&req, 0, sizeof(req));
+
+				req.bmRequestType =
+					USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice);
+				req.bRequest = kUSBRqGetDescriptor;
+				req.wValue = (kUSBStringDesc << 8) | serialIndex;
+				req.wIndex = languages[lang];
+				req.pData = buffer;
+				req.wLength = sizeof(buffer);
+				kr = (*dev)->DeviceRequest(dev, &req);
+
+				if (kr == kIOReturnSuccess && req.wLenDone > 0) {
+					int i, count;
+
+					// skip first word, and copy the rest to the serial string,
+					// changing shorts to bytes.
+					count = (req.wLenDone - 1) / 2;
+					for (i = 0; i < count; i++)
+						serial[i] = buffer[i + 1];
+					serial[i] = 0;
+                                        break;
+				}
+			}
+		}
+	}
         (*dev)->Release(dev);
 
         DBG("INFO: Found vid=%04x pid=%04x serial=%s\n", vendor, product,
@@ -232,7 +256,7 @@
         }
 
         DBG("AndroidDeviceAdded calling register_usb_transport\n");
-        register_usb_transport(handle, (serial[0] ? serial : NULL));
+        register_usb_transport(handle, (serial[0] ? serial : NULL), 1);
 
         // Register for an interest notification of this device being removed.
         // Pass the reference to our private data as the refCon for the
diff --git a/adb/usb_windows.c b/adb/usb_windows.c
index 0951f67..38c4cf4 100644
--- a/adb/usb_windows.c
+++ b/adb/usb_windows.c
@@ -488,7 +488,7 @@
                                 true)) {
             // Lets make sure that we don't duplicate this device
             if (register_new_device(handle)) {
-              register_usb_transport(handle, serial_number);
+              register_usb_transport(handle, serial_number, 1);
             } else {
               D("register_new_device failed for %s\n", interf_name);
               usb_cleanup_handle(handle);
diff --git a/fastboot/util_osx.c b/fastboot/util_osx.c
index 068241c..b43e316 100644
--- a/fastboot/util_osx.c
+++ b/fastboot/util_osx.c
@@ -26,7 +26,6 @@
  * SUCH DAMAGE.
  */
 
-#include <utils/executablepath.h>
 #import <Carbon/Carbon.h>
 #include <unistd.h>
 
diff --git a/include/arch/freebsd-x86/AndroidConfig.h b/include/arch/freebsd-x86/AndroidConfig.h
new file mode 100644
index 0000000..cc118f4
--- /dev/null
+++ b/include/arch/freebsd-x86/AndroidConfig.h
@@ -0,0 +1,317 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * Android config -- "FreeBSD".  Used for desktop x86 FreeBSD.
+ */
+#ifndef _ANDROID_CONFIG_H
+#define _ANDROID_CONFIG_H
+
+/*
+ * make sure we are building for FreeBSD
+ */
+#ifndef OS_FREEBSD
+#define OS_FREEBSD
+#endif
+/*
+ * ===========================================================================
+ *                              !!! IMPORTANT !!!
+ * ===========================================================================
+ *
+ * This file is included by ALL C/C++ source files.  Don't put anything in
+ * here unless you are absolutely certain it can't go anywhere else.
+ *
+ * Any C++ stuff must be wrapped with "#ifdef __cplusplus".  Do not use "//"
+ * comments.
+ */
+
+/*
+ * Threading model.  Choose one:
+ *
+ * HAVE_PTHREADS - use the pthreads library.
+ * HAVE_WIN32_THREADS - use Win32 thread primitives.
+ *  -- combine HAVE_CREATETHREAD, HAVE_CREATEMUTEX, and HAVE__BEGINTHREADEX
+ */
+#define HAVE_PTHREADS
+
+/*
+ * Do we have the futex syscall?
+ */
+/* #define HAVE_FUTEX */
+
+/*
+ * Process creation model.  Choose one:
+ *
+ * HAVE_FORKEXEC - use fork() and exec()
+ * HAVE_WIN32_PROC - use CreateProcess()
+ */
+#define HAVE_FORKEXEC
+
+/*
+ * Process out-of-memory adjustment.  Set if running on Linux,
+ * where we can write to /proc/<pid>/oom_adj to modify the out-of-memory
+ * badness adjustment.
+ */
+/* #define HAVE_OOM_ADJ */
+
+/*
+ * IPC model.  Choose one:
+ *
+ * HAVE_SYSV_IPC - use the classic SysV IPC mechanisms (semget, shmget).
+ * HAVE_MACOSX_IPC - use Macintosh IPC mechanisms (sem_open, mmap).
+ * HAVE_WIN32_IPC - use Win32 IPC (CreateSemaphore, CreateFileMapping).
+ * HAVE_ANDROID_IPC - use Android versions (?, mmap).
+ */
+#define HAVE_SYSV_IPC
+
+/*
+ * Memory-mapping model. Choose one:
+ *
+ * HAVE_POSIX_FILEMAP - use the Posix sys/mmap.h
+ * HAVE_WIN32_FILEMAP - use Win32 filemaps
+ */
+#define  HAVE_POSIX_FILEMAP
+
+/*
+ * Define this if you have <termio.h>
+ */
+/* #define  HAVE_TERMIO_H */
+
+/*
+ * Define this if you build against MSVCRT.DLL
+ */
+/* #define HAVE_MS_C_RUNTIME */
+
+/*
+ * Define this if you have sys/uio.h
+ */
+#define  HAVE_SYS_UIO_H
+
+/*
+ * Define this if your platforms implements symbolic links
+ * in its filesystems
+ */
+#define HAVE_SYMLINKS
+
+/*
+ * Define this if we have localtime_r().
+ */
+#define HAVE_LOCALTIME_R
+
+/*
+ * Define this if we have gethostbyname_r().
+ */
+/* #define HAVE_GETHOSTBYNAME_R */
+
+/*
+ * Define this if we have ioctl().
+ */
+#define HAVE_IOCTL
+
+/*
+ * Define this if we want to use WinSock.
+ */
+/* #define HAVE_WINSOCK */
+
+/*
+ * Define this if have clock_gettime() and friends
+ *
+ * Desktop Linux has this in librt, but it's broken in goobuntu, yielding
+ * mildly or wildly inaccurate results.
+ */
+#define HAVE_POSIX_CLOCKS
+
+/*
+ * Define this if we have pthread_cond_timedwait_monotonic() and
+ * clock_gettime(CLOCK_MONOTONIC).
+ */
+/* #define HAVE_TIMEDWAIT_MONOTONIC */
+
+/*
+ * Define this if we have linux style epoll()
+ */
+/* #define HAVE_EPOLL */
+
+/*
+ * Endianness of the target machine.  Choose one:
+ *
+ * HAVE_ENDIAN_H -- have endian.h header we can include.
+ * HAVE_LITTLE_ENDIAN -- we are little endian.
+ * HAVE_BIG_ENDIAN -- we are big endian.
+ */
+/* #define HAVE_ENDIAN_H */
+#define HAVE_LITTLE_ENDIAN
+
+/*
+ * Define this if you have sys/endian.h
+ * NOTE: mutually exclusive with HAVE_ENDIAN_H
+ */
+#define HAVE_SYS_ENDIAN_H
+
+/*
+ * We need to choose between 32-bit and 64-bit off_t.  All of our code should
+ * agree on the same size.  For desktop systems, use 64-bit values,
+ * because some of our libraries (e.g. wxWidgets) expect to be built that way.
+ */
+#define _FILE_OFFSET_BITS 64
+#define _LARGEFILE_SOURCE 1
+
+/*
+ * Defined if we have the backtrace() call for retrieving a stack trace.
+ * Needed for CallStack to operate; if not defined, CallStack is
+ * non-functional.
+ */
+#define HAVE_BACKTRACE 0
+
+/*
+ * Defined if we have the dladdr() call for retrieving the symbol associated
+ * with a memory address.  If not defined, stack crawls will not have symbolic
+ * information.
+ */
+#define HAVE_DLADDR 1
+
+/*
+ * Defined if we have the cxxabi.h header for demangling C++ symbols.  If
+ * not defined, stack crawls will be displayed with raw mangled symbols
+ */
+#define HAVE_CXXABI 0
+
+/*
+ * Defined if we have the gettid() system call.
+ */
+/* #define HAVE_GETTID */
+
+/* 
+ * Defined if we have the sched_setscheduler() call
+ */
+#define HAVE_SCHED_SETSCHEDULER
+
+/*
+ * Add any extra platform-specific defines here.
+ */
+
+/*
+ * Define if we have <malloc.h> header
+ */
+#define HAVE_MALLOC_H
+
+/*
+ * Define if we have Linux-style non-filesystem Unix Domain Sockets
+ */
+
+/*
+ * What CPU architecture does this platform use?
+ */
+#define ARCH_X86
+
+
+/*
+ * Define if we have Linux's inotify in <sys/inotify.h>.
+ */
+/*#define HAVE_INOTIFY 1*/
+
+/*
+ * Define if we have madvise() in <sys/mman.h>
+ */
+#define HAVE_MADVISE 1
+
+/*
+ * Define if tm struct has tm_gmtoff field
+ */
+#define HAVE_TM_GMTOFF 1
+
+/*
+ * Define if dirent struct has d_type field
+ */
+#define HAVE_DIRENT_D_TYPE 1
+
+/*
+ * Define if libc includes Android system properties implementation.
+ */
+/* #define HAVE_LIBC_SYSTEM_PROPERTIES */
+
+/*
+ * Define if system provides a system property server (should be
+ * mutually exclusive with HAVE_LIBC_SYSTEM_PROPERTIES).
+ */
+#define HAVE_SYSTEM_PROPERTY_SERVER
+
+/*
+ * sprintf() format string for shared library naming.
+ */
+#define OS_SHARED_LIB_FORMAT_STR    "lib%s.so"
+
+/*
+ * type for the third argument to mincore().
+ */
+#define MINCORE_POINTER_TYPE char *
+
+/*
+ * Do we have the sigaction flag SA_NOCLDWAIT?
+ */
+#define HAVE_SA_NOCLDWAIT
+
+/*
+ * Define if we include <sys/mount.h> for statfs()
+ */
+#define INCLUDE_SYS_MOUNT_FOR_STATFS 1
+  
+/*
+ * The default path separator for the platform
+ */
+#define OS_PATH_SEPARATOR '/'
+
+/*
+ * Is the filesystem case sensitive?
+ */
+#define OS_CASE_SENSITIVE
+
+/*
+ * Define if <sys/socket.h> exists.
+ */
+#define HAVE_SYS_SOCKET_H 1
+
+/*
+ * Define if the strlcpy() function exists on the system.
+ */
+#define HAVE_STRLCPY 1
+
+/*
+ * Define if prctl() exists
+ */
+/* #define HAVE_PRCTL 1 */
+
+/*
+ * Define if writev() exists
+ */
+#define HAVE_WRITEV 1
+
+/*
+ * Define if <alloca.h> does not exist
+ * NOTE: <alloca.h> defines alloca() which
+ *   on FreeBSD is defined in <stdlib.h>
+ */
+#define HAVE_NO_ALLOCA_H
+
+/*
+ * Defines CLOCK_PROCESS_CPUTIME_ID for clock_gettime()
+ * XXX: CLOCK_PROF seems to be commonly used replacement
+ */
+#ifndef  CLOCK_PROCESS_CPUTIME_ID
+#define CLOCK_PROCESS_CPUTIME_ID CLOCK_PROF
+#endif
+
+#endif /*_ANDROID_CONFIG_H*/
diff --git a/include/cutils/abort_socket.h b/include/cutils/abort_socket.h
new file mode 100644
index 0000000..fbb1112
--- /dev/null
+++ b/include/cutils/abort_socket.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* Helper to perform abortable blocking operations on a socket:
+ *   asocket_connect()
+ *   asocket_accept()
+ *   asocket_read()
+ *   asocket_write()
+ * These calls are similar to the regular syscalls, but can be aborted with:
+ *   asocket_abort()
+ *
+ * Calling close() on a regular POSIX socket does not abort blocked syscalls on
+ * that socket in other threads.
+ *
+ * After calling asocket_abort() the socket cannot be reused.
+ *
+ * Call asocket_destory() *after* all threads have finished with the socket to
+ * finish closing the socket and free the asocket structure.
+ *
+ * The helper is implemented by setting the socket non-blocking to initiate
+ * syscalls connect(), accept(), read(), write(), then using a blocking poll()
+ * on both the primary socket and a local pipe. This makes the poll() abortable
+ * by writing a byte to the local pipe in asocket_abort().
+ *
+ * asocket_create() sets the fd to non-blocking mode. It must not be changed to
+ * blocking mode.
+ *
+ * Using asocket will triple the number of file descriptors required per
+ * socket, due to the local pipe. It may be possible to use a global pipe per
+ * process rather than per socket, but we have not been able to come up with a
+ * race-free implementation yet.
+ *
+ * All functions except asocket_init() and asocket_destroy() are thread safe.
+ */
+
+#include <stdlib.h>
+#include <sys/socket.h>
+
+#ifndef __CUTILS_ABORT_SOCKET_H__
+#define __CUTILS_ABORT_SOCKET_H__
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct asocket {
+    int fd;           /* primary socket fd */
+    int abort_fd[2];  /* pipe used to abort */
+};
+
+/* Create an asocket from fd.
+ * Sets the socket to non-blocking mode.
+ * Returns NULL on error with errno set.
+ */
+struct asocket *asocket_init(int fd);
+
+/* Blocking socket I/O with timeout.
+ * Calling asocket_abort() from another thread will cause each of these
+ * functions to immediately return with value -1 and errno ECANCELED.
+ * timeout is in ms, use -1 to indicate no timeout. On timeout -1 is returned
+ * with errno ETIMEDOUT.
+ * EINTR is handled in-call.
+ * Other semantics are identical to the regular syscalls.
+ */
+int asocket_connect(struct asocket *s, const struct sockaddr *addr,
+        socklen_t addrlen, int timeout);
+
+int asocket_accept(struct asocket *s, struct sockaddr *addr,
+        socklen_t *addrlen, int timeout);
+
+int asocket_read(struct asocket *s, void *buf, size_t count, int timeout);
+
+int asocket_write(struct asocket *s, const void *buf, size_t count,
+        int timeout);
+
+/* Abort above calls and shutdown socket.
+ * Further I/O operations on this socket will immediately fail after this call.
+ * asocket_destroy() should be used to release resources once all threads
+ * have returned from blocking calls on the socket.
+ */
+void asocket_abort(struct asocket *s);
+
+/* Close socket and free asocket structure.
+ * Must not be called until all calls on this structure have completed.
+ */
+void asocket_destroy(struct asocket *s);
+
+#ifdef __cplusplus
+}
+#endif
+#endif //__CUTILS_ABORT_SOCKET__H__
diff --git a/init/builtins.c b/init/builtins.c
index 17df0af..43508ef 100644
--- a/init/builtins.c
+++ b/init/builtins.c
@@ -29,6 +29,7 @@
 #include <stdlib.h>
 #include <sys/mount.h>
 #include <sys/resource.h>
+#include <linux/loop.h>
 
 #include "init.h"
 #include "keywords.h"
@@ -130,6 +131,18 @@
     }
 }
 
+int do_chdir(int nargs, char **args)
+{
+    chdir(args[1]);
+    return 0;
+}
+
+int do_chroot(int nargs, char **args)
+{
+    chroot(args[1]);
+    return 0;
+}
+
 int do_class_start(int nargs, char **args)
 {
         /* Starting a class does not start services
@@ -205,7 +218,7 @@
 
 int do_import(int nargs, char **args)
 {
-    return -1;
+    return parse_config_file(args[1]);
 }
 
 int do_mkdir(int nargs, char **args)
@@ -257,7 +270,7 @@
 int do_mount(int nargs, char **args)
 {
     char tmp[64];
-    char *source;
+    char *source, *target, *system;
     char *options = NULL;
     unsigned flags = 0;
     int n, i;
@@ -275,15 +288,70 @@
             options = args[n];
     }
 
+    system = args[1];
     source = args[2];
+    target = args[3];
+
     if (!strncmp(source, "mtd@", 4)) {
         n = mtd_name_to_number(source + 4);
-        if (n >= 0) {
-            sprintf(tmp, "/dev/block/mtdblock%d", n);
-            source = tmp;
+        if (n < 0) {
+            return -1;
         }
+
+        sprintf(tmp, "/dev/block/mtdblock%d", n);
+
+        if (mount(tmp, target, system, flags, options) < 0) {
+            return -1;
+        }
+
+        return 0;
+    } else if (!strncmp(source, "loop@", 5)) {
+        int mode, loop, fd;
+        struct loop_info info;
+
+        mode = (flags & MS_RDONLY) ? O_RDONLY : O_RDWR;
+        fd = open(source + 5, mode);
+        if (fd < 0) {
+            return -1;
+        }
+
+        for (n = 0; ; n++) {
+            sprintf(tmp, "/dev/block/loop%d", n);
+            loop = open(tmp, mode);
+            if (loop < 0) {
+                return -1;
+            }
+
+            /* if it is a blank loop device */
+            if (ioctl(loop, LOOP_GET_STATUS, &info) < 0 && errno == ENXIO) {
+                /* if it becomes our loop device */
+                if (ioctl(loop, LOOP_SET_FD, fd) >= 0) {
+                    close(fd);
+
+                    if (mount(tmp, target, system, flags, options) < 0) {
+                        ioctl(loop, LOOP_CLR_FD, 0);
+                        close(loop);
+                        return -1;
+                    }
+
+                    close(loop);
+                    return 0;
+                }
+            }
+
+            close(loop);
+        }
+
+        close(fd);
+        ERROR("out of loopback devices");
+        return -1;
+    } else {
+        if (mount(source, target, system, flags, options) < 0) {
+            return -1;
+        }
+
+        return 0;
     }
-    return mount(source, args[3], args[1], flags, options);
 }
 
 int do_setkey(int nargs, char **args)
@@ -344,6 +412,8 @@
 
 int do_trigger(int nargs, char **args)
 {
+    action_for_each_trigger(args[1], action_add_queue_tail);
+    drain_action_queue();
     return 0;
 }
 
diff --git a/init/devices.c b/init/devices.c
index ac72b34..606a074 100644
--- a/init/devices.c
+++ b/init/devices.c
@@ -288,7 +288,7 @@
     chown(path, uid, gid);
 }
 
-#ifdef LOG_UEVENTS
+#if LOG_UEVENTS
 
 static inline suseconds_t get_usecs(void)
 {
@@ -393,6 +393,9 @@
         } else if(!strncmp(uevent->subsystem, "mtd", 3)) {
             base = "/dev/mtd/";
             mkdir(base, 0755);
+        } else if(!strncmp(uevent->subsystem, "sound", 5)) {
+            base = "/dev/snd/";
+            mkdir(base, 0755);
         } else if(!strncmp(uevent->subsystem, "misc", 4) &&
                     !strncmp(name, "log_", 4)) {
             base = "/dev/log/";
diff --git a/init/init.c b/init/init.c
old mode 100644
new mode 100755
index 0c1ad3f..adc4c9f
--- a/init/init.c
+++ b/init/init.c
@@ -65,8 +65,6 @@
 static int keychords_count = 0;
 static int keychords_length = 0;
 
-static void drain_action_queue(void);
-
 static void notify_service_state(const char *name, const char *state)
 {
     char pname[PROP_NAME_MAX];
@@ -256,7 +254,8 @@
         }
 
         if (!dynamic_args)
-            execve(svc->args[0], (char**) svc->args, (char**) ENV);
+            if (execve(svc->args[0], (char**) svc->args, (char**) ENV) < 0)
+                ERROR("cannot execve('%s'): %s\n", svc->args[0], strerror(errno));
         else {
             char *arg_ptrs[SVC_MAXARGS+1];
             int arg_idx = svc->nargs;
@@ -273,7 +272,8 @@
                     break;
             }
             arg_ptrs[arg_idx] = '\0';
-            execve(svc->args[0], (char**) arg_ptrs, (char**) ENV);
+            if (execve(svc->args[0], (char**) arg_ptrs, (char**) ENV) < 0)
+                ERROR("cannot execve('%s'): %s\n", svc->args[0], strerror(errno));
         }
         _exit(127);
     }
@@ -389,12 +389,13 @@
         }
     }
 
+    svc->flags |= SVC_RESTARTING;
+
     /* Execute all onrestart commands for this service. */
     list_for_each(node, &svc->onrestart.commands) {
         cmd = node_to_item(node, struct command, clist);
         cmd->func(cmd->nargs, cmd->args);
     }
-    svc->flags |= SVC_RESTARTING;
     notify_service_state(svc->name, "restarting");
     return 0;
 }
@@ -665,7 +666,7 @@
     }
 }
 
-static void drain_action_queue(void)
+void drain_action_queue(void)
 {
     struct listnode *node;
     struct command *cmd;
diff --git a/init/init.h b/init/init.h
index f306b7b..60c3055 100644
--- a/init/init.h
+++ b/init/init.h
@@ -165,6 +165,7 @@
 void service_start(struct service *svc, const char *dynamic_args);
 void property_changed(const char *name, const char *value);
 
+void drain_action_queue(void);
 struct action *action_remove_queue_head(void);
 void action_add_queue_tail(struct action *act);
 void action_for_each_trigger(const char *trigger,
diff --git a/init/keywords.h b/init/keywords.h
index 6f47379..1e2b9c8 100644
--- a/init/keywords.h
+++ b/init/keywords.h
@@ -1,5 +1,7 @@
 
 #ifndef KEYWORD
+int do_chroot(int nargs, char **args);
+int do_chdir(int nargs, char **args);
 int do_class_start(int nargs, char **args);
 int do_class_stop(int nargs, char **args);
 int do_domainname(int nargs, char **args);
@@ -31,6 +33,8 @@
     K_UNKNOWN,
 #endif
     KEYWORD(capability,  OPTION,  0, 0)
+    KEYWORD(chdir,       COMMAND, 1, do_chdir)
+    KEYWORD(chroot,      COMMAND, 1, do_chroot)
     KEYWORD(class,       OPTION,  0, 0)
     KEYWORD(class_start, COMMAND, 1, do_class_start)
     KEYWORD(class_stop,  COMMAND, 1, do_class_stop)
diff --git a/init/parser.c b/init/parser.c
index 33c1a68..0eb078d 100644
--- a/init/parser.c
+++ b/init/parser.c
@@ -128,6 +128,8 @@
     switch (*s++) {
     case 'c':
         if (!strcmp(s, "apability")) return K_capability;
+        if (!strcmp(s, "hdir")) return K_chdir;
+        if (!strcmp(s, "hroot")) return K_chroot;
         if (!strcmp(s, "lass")) return K_class;
         if (!strcmp(s, "lass_start")) return K_class_start;
         if (!strcmp(s, "lass_stop")) return K_class_stop;
diff --git a/init/readme.txt b/init/readme.txt
index 665090b..a185790 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -145,12 +145,18 @@
 hostname <name>
    Set the host name.
 
+chdir <directory>
+   Change working directory.
+
 chmod <octal-mode> <path>
    Change file access permissions.
 
 chown <owner> <group> <path>
    Change file owner and group.
 
+chroot <directory>
+  Change process root directory.
+
 class_start <serviceclass>
    Start all services of the specified class if they are
    not already running.
diff --git a/libcutils/Android.mk b/libcutils/Android.mk
index 18d0ee3..98e59ee 100644
--- a/libcutils/Android.mk
+++ b/libcutils/Android.mk
@@ -17,6 +17,7 @@
 include $(CLEAR_VARS)
 
 commonSources := \
+	abort_socket.c \
 	array.c \
 	hashmap.c \
 	atomic.c \
diff --git a/libcutils/abort_socket.c b/libcutils/abort_socket.c
new file mode 100644
index 0000000..6a5e5e4
--- /dev/null
+++ b/libcutils/abort_socket.c
@@ -0,0 +1,293 @@
+/*
+ * Copyright 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/poll.h>
+
+#include "cutils/abort_socket.h"
+
+struct asocket *asocket_init(int fd) {
+    int abort_fd[2];
+    int flags;
+    struct asocket *s;
+
+    /* set primary socket to non-blocking */
+    flags = fcntl(fd, F_GETFL);
+    if (flags == -1)
+        return NULL;
+    if (fcntl(fd, F_SETFL, flags | O_NONBLOCK))
+        return NULL;
+
+    /* create pipe with non-blocking write, so that asocket_close() cannot
+       block */
+    if (pipe(abort_fd))
+        return NULL;
+    flags = fcntl(abort_fd[1], F_GETFL);
+    if (flags == -1)
+        return NULL;
+    if (fcntl(abort_fd[1], F_SETFL, flags | O_NONBLOCK))
+        return NULL;
+
+    s = malloc(sizeof(struct asocket));
+    if (!s)
+        return NULL;
+
+    s->fd = fd;
+    s->abort_fd[0] = abort_fd[0];
+    s->abort_fd[1] = abort_fd[1];
+
+    return s;
+}
+
+int asocket_connect(struct asocket *s, const struct sockaddr *addr,
+        socklen_t addrlen, int timeout) {
+
+    int ret;
+
+    do {
+        ret = connect(s->fd, addr, addrlen);
+    } while (ret && errno == EINTR);
+
+    if (ret && errno == EINPROGRESS) {
+        /* ready to poll() */
+        socklen_t retlen;
+        struct pollfd pfd[2];
+
+        pfd[0].fd = s->fd;
+        pfd[0].events = POLLOUT;
+        pfd[0].revents = 0;
+        pfd[1].fd = s->abort_fd[0];
+        pfd[1].events = POLLIN;
+        pfd[1].revents = 0;
+
+        do {
+            ret = poll(pfd, 2, timeout);
+        } while (ret < 0 && errno == EINTR);
+
+        if (ret < 0)
+            return -1;
+        else if (ret == 0) {
+            /* timeout */
+            errno = ETIMEDOUT;
+            return -1;
+        }
+
+        if (pfd[1].revents) {
+            /* abort due to asocket_abort() */
+            errno = ECANCELED;
+            return -1;
+        }
+
+        if (pfd[0].revents) {
+            if (pfd[0].revents & POLLOUT) {
+                /* connect call complete, read return code */
+                retlen = sizeof(ret);
+                if (getsockopt(s->fd, SOL_SOCKET, SO_ERROR, &ret, &retlen))
+                    return -1;
+                /* got connect() return code */
+                if (ret) {
+                    errno = ret;
+                }
+            } else {
+                /* some error event on this fd */
+                errno = ECONNABORTED;
+                return -1;
+            }
+        }
+    }
+
+    return ret;
+}
+
+int asocket_accept(struct asocket *s, struct sockaddr *addr,
+        socklen_t *addrlen, int timeout) {
+
+    int ret;
+    struct pollfd pfd[2];
+
+    pfd[0].fd = s->fd;
+    pfd[0].events = POLLIN;
+    pfd[0].revents = 0;
+    pfd[1].fd = s->abort_fd[0];
+    pfd[1].events = POLLIN;
+    pfd[1].revents = 0;
+
+    do {
+        ret = poll(pfd, 2, timeout);
+    } while (ret < 0 && errno == EINTR);
+
+    if (ret < 0)
+        return -1;
+    else if (ret == 0) {
+        /* timeout */
+        errno = ETIMEDOUT;
+        return -1;
+    }
+
+    if (pfd[1].revents) {
+        /* abort due to asocket_abort() */
+        errno = ECANCELED;
+        return -1;
+    }
+
+    if (pfd[0].revents) {
+        if (pfd[0].revents & POLLIN) {
+            /* ready to accept() without blocking */
+            do {
+                ret = accept(s->fd, addr, addrlen);
+            } while (ret < 0 && errno == EINTR);
+        } else {
+            /* some error event on this fd */
+            errno = ECONNABORTED;
+            return -1;
+        }
+    }
+
+    return ret;
+}
+
+int asocket_read(struct asocket *s, void *buf, size_t count, int timeout) {
+    int ret;
+    struct pollfd pfd[2];
+
+    pfd[0].fd = s->fd;
+    pfd[0].events = POLLIN;
+    pfd[0].revents = 0;
+    pfd[1].fd = s->abort_fd[0];
+    pfd[1].events = POLLIN;
+    pfd[1].revents = 0;
+
+    do {
+        ret = poll(pfd, 2, timeout);
+    } while (ret < 0 && errno == EINTR);
+
+    if (ret < 0)
+        return -1;
+    else if (ret == 0) {
+        /* timeout */
+        errno = ETIMEDOUT;
+        return -1;
+    }
+
+    if (pfd[1].revents) {
+        /* abort due to asocket_abort() */
+        errno = ECANCELED;
+        return -1;
+    }
+
+    if (pfd[0].revents) {
+        if (pfd[0].revents & POLLIN) {
+            /* ready to read() without blocking */
+            do {
+                ret = read(s->fd, buf, count);
+            } while (ret < 0 && errno == EINTR);
+        } else {
+            /* some error event on this fd */
+            errno = ECONNABORTED;
+            return -1;
+        }
+    }
+
+    return ret;
+}
+
+int asocket_write(struct asocket *s, const void *buf, size_t count,
+        int timeout) {
+    int ret;
+    struct pollfd pfd[2];
+
+    pfd[0].fd = s->fd;
+    pfd[0].events = POLLOUT;
+    pfd[0].revents = 0;
+    pfd[1].fd = s->abort_fd[0];
+    pfd[1].events = POLLIN;
+    pfd[1].revents = 0;
+
+    do {
+        ret = poll(pfd, 2, timeout);
+    } while (ret < 0 && errno == EINTR);
+
+    if (ret < 0)
+        return -1;
+    else if (ret == 0) {
+        /* timeout */
+        errno = ETIMEDOUT;
+        return -1;
+    }
+
+    if (pfd[1].revents) {
+        /* abort due to asocket_abort() */
+        errno = ECANCELED;
+        return -1;
+    }
+
+    if (pfd[0].revents) {
+        if (pfd[0].revents & POLLOUT) {
+            /* ready to write() without blocking */
+            do {
+                ret = write(s->fd, buf, count);
+            } while (ret < 0 && errno == EINTR);
+        } else {
+            /* some error event on this fd */
+            errno = ECONNABORTED;
+            return -1;
+        }
+    }
+
+    return ret;
+}
+
+void asocket_abort(struct asocket *s) {
+    int ret;
+    char buf = 0;
+
+    /* Prevent further use of fd, without yet releasing the fd */
+    shutdown(s->fd, SHUT_RDWR);
+
+    /* wake up calls blocked at poll() */
+    do {
+        ret = write(s->abort_fd[1], &buf, 1);
+    } while (ret < 0 && errno == EINTR);
+}
+
+void asocket_destroy(struct asocket *s) {
+    struct asocket s_copy = *s;
+
+    /* Clients should *not* be using these fd's after calling
+       asocket_destroy(), but in case they do, set to -1 so they cannot use a
+       stale fd */
+    s->fd = -1;
+    s->abort_fd[0] = -1;
+    s->abort_fd[1] = -1;
+
+    /* Call asocket_abort() in case there are still threads blocked on this
+       socket. Clients should not rely on this behavior - it is racy because we
+       are about to close() these sockets - clients should instead make sure
+       all threads are done with the socket before calling asocket_destory().
+     */
+    asocket_abort(&s_copy);
+
+    /* enough safety checks, close and release memory */
+    close(s_copy.abort_fd[1]);
+    close(s_copy.abort_fd[0]);
+    close(s_copy.fd);
+
+    free(s);
+}
diff --git a/liblog/logprint.c b/liblog/logprint.c
index 2cf1254..080f9e3 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -23,7 +23,6 @@
 #include <stdlib.h>
 #include <stdint.h>
 #include <string.h>
-#include <alloca.h>
 #include <assert.h>
 #include <arpa/inet.h>
 
diff --git a/libpixelflinger/Android.mk b/libpixelflinger/Android.mk
index 50eb5f5..0cc85d9 100644
--- a/libpixelflinger/Android.mk
+++ b/libpixelflinger/Android.mk
@@ -64,12 +64,14 @@
 LOCAL_MODULE:= libpixelflinger
 LOCAL_SRC_FILES := $(PIXELFLINGER_SRC_FILES)
 LOCAL_CFLAGS := $(PIXELFLINGER_CFLAGS)
+
 ifneq ($(BUILD_TINY_ANDROID),true)
 # Really this should go away entirely or at least not depend on
 # libhardware, but this at least gets us built.
 LOCAL_SHARED_LIBRARIES += libhardware_legacy
 LOCAL_CFLAGS += -DWITH_LIB_HARDWARE
 endif
+
 ifeq ($(TARGET_ARCH),arm)
 LOCAL_WHOLE_STATIC_LIBRARIES := libpixelflinger_armv6
 endif
diff --git a/rootdir/etc/init.goldfish.sh b/rootdir/etc/init.goldfish.sh
index f1b801d..5ff0a3a 100755
--- a/rootdir/etc/init.goldfish.sh
+++ b/rootdir/etc/init.goldfish.sh
@@ -3,16 +3,20 @@
 ifconfig eth0 10.0.2.15 netmask 255.255.255.0 up
 route add default gw 10.0.2.2 dev eth0
 
-qemud=`getprop.ro.kernel.android.qemud`
-if test -z "$qemud"; then
+qemud=`getprop ro.kernel.android.qemud`
+case "$qemud" in
+    "")
     radio_ril=`getprop ro.kernel.android.ril`
-    if test -z "$radio_ril"; then
+    case "$radio_ril" in
+        "")
         # no need for the radio interface daemon
         # telephony is entirely emulated in Java
         setprop ro.radio.noril yes
         stop ril-daemon
-    fi
-fi
+        ;;
+    esac
+    ;;
+esac
 
 num_dns=`getprop ro.kernel.android.ndns`
 case "$num_dns" in
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 2bed980..9d30518 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -38,7 +38,7 @@
 # Create cgroup mount points for process groups
     mkdir /dev/cpuctl
     mount cgroup none /dev/cpuctl cpu
-    chown sytem system /dev/cpuctl
+    chown system system /dev/cpuctl
     chown system system /dev/cpuctl/tasks
     chmod 0777 /dev/cpuctl/tasks
     write /dev/cpuctl/cpu.shares 1024
diff --git a/toolbox/mount.c b/toolbox/mount.c
index 86047a9..472c952 100644
--- a/toolbox/mount.c
+++ b/toolbox/mount.c
@@ -138,14 +138,17 @@
 
     if (loop) {
         int file_fd, device_fd;
+        int flags;
+
+        flags = (rwflag & MS_RDONLY) ? O_RDONLY : O_RDWR;
         
         // FIXME - only one loop mount supported at a time
-        file_fd = open(dev, O_RDWR);
+        file_fd = open(dev, flags);
         if (file_fd < -1) {
             perror("open backing file failed");
             return 1;
         }
-        device_fd = open(LOOP_DEVICE, O_RDWR);
+        device_fd = open(LOOP_DEVICE, flags);
         if (device_fd < -1) {
             perror("open loop device failed");
             close(file_fd);
diff --git a/vold/blkdev.c b/vold/blkdev.c
index e10eafc..2c5681a 100644
--- a/vold/blkdev.c
+++ b/vold/blkdev.c
@@ -112,7 +112,7 @@
             goto out;
         }
 
-        for (i = 0; i < 4; i++) {
+        for (i = 0; i < NDOSPART; i++) {
             struct dos_partition part;
 
             dos_partition_dec(block + DOSPARTOFF + i * sizeof(struct dos_partition), &part);
@@ -134,7 +134,7 @@
         struct dos_partition part;
         int part_no = blk->minor -1;
 
-        if (part_no < 4) {
+        if (part_no < NDOSPART) {
             dos_partition_dec(block + DOSPARTOFF + part_no * sizeof(struct dos_partition), &part);
             blk->part_type = part.dp_typ;
         } else {
diff --git a/vold/mmc.c b/vold/mmc.c
index cbddb92..6ad97f4 100644
--- a/vold/mmc.c
+++ b/vold/mmc.c
@@ -25,6 +25,7 @@
 #include "vold.h"
 #include "mmc.h"
 #include "media.h"
+#include "diskmbr.h" /* for NDOSPART */
 
 #define DEBUG_BOOTSTRAP 0
 
@@ -157,6 +158,10 @@
 
     sprintf(filename, "/sys%s/name", devpath);
     p = read_file(filename, &sz);
+    if (!p) {
+        LOGE("Unable to read MMC name: %s", filename);
+        return -errno;
+    }
     p[strlen(p) - 1] = '\0';
     sprintf(tmp, "MMC_NAME=%s", p);
     free(p);
@@ -233,7 +238,7 @@
          *mmcblk_devname != '/'; mmcblk_devname--);
     mmcblk_devname++;
 
-    for (part_no = 0; part_no < 4; part_no++) {
+    for (part_no = 1; part_no <= NDOSPART; part_no++) {
         char part_file[255];
         sprintf(part_file, "/sys%s/%sp%d", devpath, mmcblk_devname, part_no);
         if (!access(part_file, F_OK)) {