merge from donut
diff --git a/adb/services.c b/adb/services.c
index 0a5edcf..78d092b 100644
--- a/adb/services.c
+++ b/adb/services.c
@@ -31,6 +31,8 @@
 #    include <netinet/in.h>
 #    include <netdb.h>
 #  endif
+#else
+#include <sys/poll.h>
 #endif
 
 typedef struct stinfo stinfo;
@@ -196,12 +198,9 @@
     return s[0];
 }
 
+#if !ADB_HOST
 static int create_subprocess(const char *cmd, const char *arg0, const char *arg1)
 {
-#ifdef HAVE_WIN32_PROC
-	fprintf(stderr, "error: create_subprocess not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1);
-	return -1;
-#else /* !HAVE_WIN32_PROC */
     char *devname;
     int ptm;
     pid_t pid;
@@ -244,7 +243,6 @@
                 cmd, strerror(errno), errno);
         exit(-1);
     } else {
-#if !ADB_HOST
         // set child's OOM adjustment to zero
         char text[64];
         snprintf(text, sizeof text, "/proc/%d/oom_adj", pid);
@@ -255,11 +253,11 @@
         } else {
            D("adb: unable to open %s\n", text);
         }
-#endif
+
         return ptm;
     }
-#endif /* !HAVE_WIN32_PROC */
 }
+#endif /* !ADB_HOST */
 
 #if ADB_HOST
 #define SHELL_COMMAND "/bin/sh"
@@ -267,6 +265,76 @@
 #define SHELL_COMMAND "/system/bin/sh"
 #endif
 
+#if !ADB_HOST
+static void shell_service(int s, void *command)
+{
+    char    buffer[MAX_PAYLOAD];
+    char    buffer2[MAX_PAYLOAD];
+    struct pollfd ufds[2];
+    int     fd, ret = 0;
+    unsigned count = 0;
+    char** args = (char **)command;
+    fd = create_subprocess(SHELL_COMMAND, args[0], args[1]);
+
+    while (1) {
+        while (count < sizeof(buffer)) {
+            ufds[0].fd = fd;
+            ufds[0].events = POLLIN | POLLHUP;
+            ufds[0].revents = 0;
+            ufds[1].fd = s;
+            ufds[1].events = POLLIN | POLLHUP;
+            ufds[1].revents = 0;
+            // use a 100ms timeout so we don't block indefinitely with our
+            // buffer partially filled.
+            ret = poll(ufds, 2, 100);
+            if (ret <= 0) {
+                D("poll returned %d\n", ret);
+                // file has closed or we timed out
+                // set ret to 1 so we don't exit the outer loop
+                ret = 1;
+                break;
+            }
+
+            if (ufds[0].revents & POLLIN) {
+                ret = adb_read(fd, buffer + count, sizeof(buffer) - count);
+                D("read fd ret: %d, count: %d\n", ret, count);
+                if (ret > 0)
+                    count += ret;
+                else
+                    break;
+            }
+            if (ufds[1].revents & POLLIN) {
+                ret = adb_read(s, buffer2, sizeof(buffer2));
+                D("read s ret: %d\n", ret);
+                if (ret > 0)
+                    adb_write(fd, buffer2, ret);
+                else
+                    break;
+            }
+
+            if ((ufds[0].revents & POLLHUP) || (ufds[1].revents & POLLHUP)) {
+                // set flag to exit after flushing the buffer
+                ret = -1;
+                break;
+            }
+        }
+
+        D("writing: %d\n", count);
+        if (count > 0) {
+            adb_write(s, buffer, count);
+            count = 0;
+        }
+        if (ret <= 0)
+            break;
+    }
+
+    D("shell_service done\n");
+
+    adb_close(fd);
+    adb_close(s);
+}
+#endif // !ADB_HOST
+
 int service_to_fd(const char *name)
 {
     int ret = -1;
@@ -317,14 +385,16 @@
         ret = create_jdwp_connection_fd(atoi(name+5));
     } else if (!strncmp(name, "log:", 4)) {
         ret = create_service_thread(log_service, get_log_file_path(name + 4));
-#endif
     } else if(!HOST && !strncmp(name, "shell:", 6)) {
+        const char* args[2];
         if(name[6]) {
-            ret = create_subprocess(SHELL_COMMAND, "-c", name + 6);
+            args[0] = "-c";
+            args[1] = name + 6;
         } else {
-            ret = create_subprocess(SHELL_COMMAND, "-", 0);
+            args[0] = "-";
+            args[1] = 0;
         }
-#if !ADB_HOST
+        ret = create_service_thread(shell_service, (void *)args);
     } else if(!strncmp(name, "sync:", 5)) {
         ret = create_service_thread(file_sync_service, NULL);
     } else if(!strncmp(name, "remount:", 8)) {
diff --git a/adb/usb_linux.c b/adb/usb_linux.c
index 95c2ce6..537122d 100644
--- a/adb/usb_linux.c
+++ b/adb/usb_linux.c
@@ -318,9 +318,13 @@
                     found_device = 1;
                     break;
                 } else {
-                        // skip to next interface
-                    bufptr += (interface->bNumEndpoints * USB_DT_ENDPOINT_SIZE);
-                }
+                    // seek next interface descriptor
+                    if (i < interfaces - 1) {
+                        while (bufptr[1] != USB_DT_INTERFACE) {
+                            bufptr += bufptr[0];
+                        }
+                    }
+                 }
             } // end of for
 
             adb_close(fd);
diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c
index 9a15146..f8c54d7 100644
--- a/adb/usb_vendors.c
+++ b/adb/usb_vendors.c
@@ -39,11 +39,17 @@
 #define VENDOR_ID_GOOGLE        0x18d1
 // HTC's USB Vendor ID
 #define VENDOR_ID_HTC           0x0bb4
+// Samsung's USB Vendor ID
+#define VENDOR_ID_SAMSUNG       0x04e8
+// Motorola's USB Vendor ID
+#define VENDOR_ID_MOTOROLA      0x22b8
 
 /** built-in vendor list */
 int builtInVendorIds[] = {
     VENDOR_ID_GOOGLE,
     VENDOR_ID_HTC,
+    VENDOR_ID_SAMSUNG,
+    VENDOR_ID_MOTOROLA,
 };
 
 #define BUILT_IN_VENDOR_COUNT    (sizeof(builtInVendorIds)/sizeof(builtInVendorIds[0]))
diff --git a/rootdir/init.rc b/rootdir/init.rc
index dab9027..a648ad8 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -287,7 +287,7 @@
 service installd /system/bin/installd
     socket installd stream 600 system system
 
-service flash_recovery /system/bin/flash_image recovery /system/recovery.img
+service flash_recovery /system/etc/install-recovery.sh
     oneshot
 
 service racoon /system/bin/racoon