am 143b9e3d: Merge changes I1730d1df,I42c18cb5,I03bb5cc1

* commit '143b9e3dd6b86d5ac14b6d57588561aed45ab7ca':
  adb: use oom_score_adj instead of oom_adj
  Add "exec" service: shell commands with no pty.
  adb: added support for adb pull -a to preserve time stamps and mode
diff --git a/adb/Android.mk b/adb/Android.mk
index 50e28a6..80427b8 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -102,7 +102,6 @@
 
 LOCAL_SRC_FILES := \
 	adb.c \
-	backup_service.c \
 	fdevent.c \
 	transport.c \
 	transport_local.c \
diff --git a/adb/adb.h b/adb/adb.h
index 2504f99..4704abb 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -326,11 +326,6 @@
 int handle_forward_request(const char* service, transport_type ttype, char* serial, int reply_fd);
 
 #if !ADB_HOST
-typedef enum {
-    BACKUP,
-    RESTORE
-} BackupOperation;
-int backup_service(BackupOperation operation, char* args);
 void framebuffer_service(int fd, void *cookie);
 void remount_service(int fd, void *cookie);
 #endif
@@ -418,7 +413,7 @@
 #  define  D(...)          ((void)0)
 #  define  DR(...)         ((void)0)
 #  define  ADB_TRACING     0
-#endif
+#endif /* ADB_TRACE */
 
 
 #if !DEBUG_PACKETS
@@ -476,6 +471,11 @@
 extern int HOST;
 extern int SHELL_EXIT_NOTIFY_FD;
 
+typedef enum {
+    SUBPROC_PTY = 0,
+    SUBPROC_RAW = 1,
+} subproc_mode;
+
 #define CHUNK_SIZE (64*1024)
 
 #if !ADB_HOST
diff --git a/adb/backup_service.c b/adb/backup_service.c
deleted file mode 100644
index 654e0f3..0000000
--- a/adb/backup_service.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2011 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 <unistd.h>
-#include <stdio.h>
-
-#include "sysdeps.h"
-
-#define TRACE_TAG  TRACE_ADB
-#include "adb.h"
-
-typedef struct {
-    pid_t pid;
-    int fd;
-} backup_harvest_params;
-
-// socketpair but do *not* mark as close_on_exec
-static int backup_socketpair(int sv[2]) {
-    int rc = unix_socketpair( AF_UNIX, SOCK_STREAM, 0, sv );
-    if (rc < 0)
-        return -1;
-
-    return 0;
-}
-
-// harvest the child process then close the read end of the socketpair
-static void* backup_child_waiter(void* args) {
-    int status;
-    backup_harvest_params* params = (backup_harvest_params*) args;
-
-    waitpid(params->pid, &status, 0);
-    adb_close(params->fd);
-    free(params);
-    return NULL;
-}
-
-/* returns the data socket passing the backup data here for forwarding */
-int backup_service(BackupOperation op, char* args) {
-    pid_t pid;
-    int s[2];
-    char* operation;
-
-    // Command string depends on our invocation
-    if (op == BACKUP) {
-        operation = "backup";
-    } else {
-        operation = "restore";
-    }
-
-    D("backup_service(%s, %s)\n", operation, args);
-
-    // set up the pipe from the subprocess to here
-    // parent will read s[0]; child will write s[1]
-    if (backup_socketpair(s)) {
-        D("can't create backup/restore socketpair\n");
-        fprintf(stderr, "unable to create backup/restore socketpair\n");
-        return -1;
-    }
-
-    D("Backup/restore socket pair: (send=%d, receive=%d)\n", s[1], s[0]);
-    close_on_exec(s[0]);    // only the side we hold on to
-
-    // spin off the child process to run the backup command
-    pid = fork();
-    if (pid < 0) {
-        // failure
-        D("can't fork for %s\n", operation);
-        fprintf(stderr, "unable to fork for %s\n", operation);
-        adb_close(s[0]);
-        adb_close(s[1]);
-        return -1;
-    }
-
-    // Great, we're off and running.
-    if (pid == 0) {
-        // child -- actually run the backup here
-        char* p;
-        int argc;
-        char portnum[16];
-        char** bu_args;
-
-        // fixed args:  [0] is 'bu', [1] is the port number, [2] is the 'operation' string
-        argc = 3;
-        for (p = (char*)args; p && *p; ) {
-            argc++;
-            while (*p && *p != ':') p++;
-            if (*p == ':') p++;
-        }
-
-        bu_args = (char**) alloca(argc*sizeof(char*) + 1);
-
-        // run through again to build the argv array
-        argc = 0;
-        bu_args[argc++] = "bu";
-        snprintf(portnum, sizeof(portnum), "%d", s[1]);
-        bu_args[argc++] = portnum;
-        bu_args[argc++] = operation;
-        for (p = (char*)args; p && *p; ) {
-            bu_args[argc++] = p;
-            while (*p && *p != ':') p++;
-            if (*p == ':') {
-                *p = 0;
-                p++;
-            }
-        }
-        bu_args[argc] = NULL;
-
-        // Close the half of the socket that we don't care about, route 'bu's console
-        // to the output socket, and off we go
-        adb_close(s[0]);
-
-        // off we go
-        execvp("/system/bin/bu", (char * const *)bu_args);
-        // oops error - close up shop and go home
-        fprintf(stderr, "Unable to exec 'bu', bailing\n");
-        exit(-1);
-    } else {
-        adb_thread_t t;
-        backup_harvest_params* params;
-
-        // parent, i.e. adbd -- close the sending half of the socket
-        D("fork() returned pid %d\n", pid);
-        adb_close(s[1]);
-
-        // spin a thread to harvest the child process
-        params = (backup_harvest_params*) malloc(sizeof(backup_harvest_params));
-        params->pid = pid;
-        params->fd = s[0];
-        if (adb_thread_create(&t, backup_child_waiter, params)) {
-            adb_close(s[0]);
-            free(params);
-            D("Unable to create child harvester\n");
-            return -1;
-        }
-    }
-
-    // we'll be reading from s[0] as the data is sent by the child process
-    return s[0];
-}
diff --git a/adb/commandline.c b/adb/commandline.c
index 18dc6e0..1ba6049 100644
--- a/adb/commandline.c
+++ b/adb/commandline.c
@@ -110,9 +110,10 @@
         "  adb push [-p] <local> <remote>\n"
         "                               - copy file/dir to device\n"
         "                                 ('-p' to display the transfer progress)\n"
-        "  adb pull [-p] <remote> [<local>]\n"
+        "  adb pull [-p] [-a] <remote> [<local>]\n"
         "                               - copy file/dir from device\n"
         "                                 ('-p' to display the transfer progress)\n"
+        "                                 ('-a' means copy timestamp and mode)\n"
         "  adb sync [ <directory> ]     - copy host->device only if changed\n"
         "                                 (-l means list but don't copy)\n"
         "                                 (see 'adb help all')\n"
@@ -285,8 +286,17 @@
     long total = 0;
 
     D("copy_to_file(%d -> %d)\n", inFd, outFd);
+#ifdef HAVE_TERMIO_H
+    if (inFd == STDIN_FILENO) {
+        stdin_raw_init(STDIN_FILENO);
+    }
+#endif
     for (;;) {
-        len = adb_read(inFd, buf, BUFSIZE);
+        if (inFd == STDIN_FILENO) {
+            len = unix_read(inFd, buf, BUFSIZE);
+        } else {
+            len = adb_read(inFd, buf, BUFSIZE);
+        }
         if (len == 0) {
             D("copy_to_file() : read 0 bytes; exiting\n");
             break;
@@ -299,9 +309,19 @@
             D("copy_to_file() : error %d\n", errno);
             break;
         }
-        adb_write(outFd, buf, len);
+        if (outFd == STDOUT_FILENO) {
+            fwrite(buf, 1, len, stdout);
+            fflush(stdout);
+        } else {
+            adb_write(outFd, buf, len);
+        }
         total += len;
     }
+#ifdef HAVE_TERMIO_H
+    if (inFd == STDIN_FILENO) {
+        stdin_raw_restore(STDIN_FILENO);
+    }
+#endif
     D("copy_to_file() finished after %lu bytes\n", total);
     free(buf);
 }
@@ -938,13 +958,19 @@
     return path_buf;
 }
 
-
-static void parse_push_pull_args(char** arg, int narg, char const** path1, char const** path2,
-                                 int* show_progress) {
+static void parse_push_pull_args(char **arg, int narg, char const **path1, char const **path2,
+                                 int *show_progress, int *copy_attrs) {
     *show_progress = 0;
+    *copy_attrs = 0;
 
-    if ((narg > 0) && !strcmp(*arg, "-p")) {
-        *show_progress = 1;
+    while (narg > 0) {
+        if (!strcmp(*arg, "-p")) {
+            *show_progress = 1;
+        } else if (!strcmp(*arg, "-a")) {
+            *copy_attrs = 1;
+        } else {
+            break;
+        }
         ++arg;
         --narg;
     }
@@ -968,7 +994,6 @@
     int is_server = 0;
     int persist = 0;
     int r;
-    int quote;
     transport_type ttype = kTransportAny;
     char* serial = NULL;
     char* server_port_str = NULL;
@@ -1189,19 +1214,14 @@
             return r;
         }
 
-        snprintf(buf, sizeof buf, "shell:%s", argv[1]);
+        snprintf(buf, sizeof(buf), "shell:%s", argv[1]);
         argc -= 2;
         argv += 2;
-        while(argc-- > 0) {
-            strcat(buf, " ");
-
-            /* quote empty strings and strings with spaces */
-            quote = (**argv == 0 || strchr(*argv, ' '));
-            if (quote)
-                strcat(buf, "\"");
-            strcat(buf, *argv++);
-            if (quote)
-                strcat(buf, "\"");
+        while (argc-- > 0) {
+            char *quoted = dupAndQuote(*argv++);
+            strncat(buf, " ", sizeof(buf) - 1);
+            strncat(buf, quoted, sizeof(buf) - 1);
+            free(quoted);
         }
 
         for(;;) {
@@ -1233,6 +1253,36 @@
         }
     }
 
+    if (!strcmp(argv[0], "exec-in") || !strcmp(argv[0], "exec-out")) {
+        int exec_in = !strcmp(argv[0], "exec-in");
+        int fd;
+
+        snprintf(buf, sizeof buf, "exec:%s", argv[1]);
+        argc -= 2;
+        argv += 2;
+        while (argc-- > 0) {
+            char *quoted = dupAndQuote(*argv++);
+            strncat(buf, " ", sizeof(buf) - 1);
+            strncat(buf, quoted, sizeof(buf) - 1);
+            free(quoted);
+        }
+
+        fd = adb_connect(buf);
+        if (fd < 0) {
+            fprintf(stderr, "error: %s\n", adb_error());
+            return -1;
+        }
+
+        if (exec_in) {
+            copy_to_file(STDIN_FILENO, fd);
+        } else {
+            copy_to_file(fd, STDOUT_FILENO);
+        }
+
+        adb_close(fd);
+        return 0;
+    }
+
     if(!strcmp(argv[0], "kill-server")) {
         int fd;
         fd = _adb_connect("host:kill");
@@ -1415,9 +1465,10 @@
 
     if(!strcmp(argv[0], "push")) {
         int show_progress = 0;
+        int copy_attrs = 0; // unused
         const char* lpath = NULL, *rpath = NULL;
 
-        parse_push_pull_args(&argv[1], argc - 1, &lpath, &rpath, &show_progress);
+        parse_push_pull_args(&argv[1], argc - 1, &lpath, &rpath, &show_progress, &copy_attrs);
 
         if ((lpath != NULL) && (rpath != NULL)) {
             return do_sync_push(lpath, rpath, 0 /* no verify APK */, show_progress);
@@ -1428,12 +1479,13 @@
 
     if(!strcmp(argv[0], "pull")) {
         int show_progress = 0;
+        int copy_attrs = 0;
         const char* rpath = NULL, *lpath = ".";
 
-        parse_push_pull_args(&argv[1], argc - 1, &rpath, &lpath, &show_progress);
+        parse_push_pull_args(&argv[1], argc - 1, &rpath, &lpath, &show_progress, &copy_attrs);
 
         if (rpath != NULL) {
-            return do_sync_pull(rpath, lpath, show_progress);
+            return do_sync_pull(rpath, lpath, show_progress, copy_attrs);
         }
 
         return usage();
diff --git a/adb/file_sync_client.c b/adb/file_sync_client.c
index dc4e77f..3f540c1 100644
--- a/adb/file_sync_client.c
+++ b/adb/file_sync_client.c
@@ -139,7 +139,8 @@
 
 static syncsendbuf send_buffer;
 
-int sync_readtime(int fd, const char *path, unsigned *timestamp)
+int sync_readtime(int fd, const char *path, unsigned int *timestamp,
+                  unsigned int *mode)
 {
     syncmsg msg;
     int len = strlen(path);
@@ -161,6 +162,7 @@
     }
 
     *timestamp = ltohl(msg.stat.time);
+    *mode = ltohl(msg.stat.mode);
     return 0;
 }
 
@@ -237,7 +239,7 @@
     if (show_progress) {
         // Determine local file size.
         struct stat st;
-        if (lstat(path, &st)) {
+        if (fstat(lfd, &st)) {
             fprintf(stderr,"cannot stat '%s': %s\n", path, strerror(errno));
             return -1;
         }
@@ -931,8 +933,21 @@
     return 0;
 }
 
+static int set_time_and_mode(const char *lpath, unsigned int time, unsigned int mode)
+{
+    struct timeval times[2] = { {time, 0}, {time, 0} };
+    int r1 = utimes(lpath, times);
+
+    /* use umask for permissions */
+    mode_t mask=umask(0000);
+    umask(mask);
+    int r2 = chmod(lpath, mode & ~mask);
+
+    return r1 ? : r2;
+}
+
 static int copy_remote_dir_local(int fd, const char *rpath, const char *lpath,
-                                 int checktimestamps)
+                                 int copy_attrs)
 {
     copyinfo *filelist = 0;
     copyinfo *ci, *next;
@@ -962,26 +977,6 @@
         return -1;
     }
 
-#if 0
-    if (checktimestamps) {
-        for (ci = filelist; ci != 0; ci = ci->next) {
-            if (sync_start_readtime(fd, ci->dst)) {
-                return 1;
-            }
-        }
-        for (ci = filelist; ci != 0; ci = ci->next) {
-            unsigned int timestamp, mode, size;
-            if (sync_finish_readtime(fd, &timestamp, &mode, &size))
-                return 1;
-            if (size == ci->size) {
-                /* for links, we cannot update the atime/mtime */
-                if ((S_ISREG(ci->mode & mode) && timestamp == ci->time) ||
-                    (S_ISLNK(ci->mode & mode) && timestamp >= ci->time))
-                    ci->flag = 1;
-            }
-        }
-    }
-#endif
     for (ci = filelist; ci != 0; ci = next) {
         next = ci->next;
         if (ci->flag == 0) {
@@ -989,6 +984,10 @@
             if (sync_recv(fd, ci->src, ci->dst, 0 /* no show progress */)) {
                 return 1;
             }
+
+            if (copy_attrs && set_time_and_mode(ci->dst, ci->time, ci->mode)) {
+               return 1;
+            }
             pulled++;
         } else {
             skipped++;
@@ -1003,9 +1002,9 @@
     return 0;
 }
 
-int do_sync_pull(const char *rpath, const char *lpath, int show_progress)
+int do_sync_pull(const char *rpath, const char *lpath, int show_progress, int copy_attrs)
 {
-    unsigned mode;
+    unsigned mode, time;
     struct stat st;
 
     int fd;
@@ -1016,7 +1015,7 @@
         return 1;
     }
 
-    if(sync_readmode(fd, rpath, &mode)) {
+    if(sync_readtime(fd, rpath, &time, &mode)) {
         return 1;
     }
     if(mode == 0) {
@@ -1047,13 +1046,15 @@
         if (sync_recv(fd, rpath, lpath, show_progress)) {
             return 1;
         } else {
+            if (copy_attrs && set_time_and_mode(lpath, time, mode))
+                return 1;
             END();
             sync_quit(fd);
             return 0;
         }
     } else if(S_ISDIR(mode)) {
         BEGIN();
-        if (copy_remote_dir_local(fd, rpath, lpath, 0)) {
+        if (copy_remote_dir_local(fd, rpath, lpath, copy_attrs)) {
             return 1;
         } else {
             END();
diff --git a/adb/file_sync_service.h b/adb/file_sync_service.h
index 3e7e096..8ea239e 100644
--- a/adb/file_sync_service.h
+++ b/adb/file_sync_service.h
@@ -80,7 +80,7 @@
 int do_sync_ls(const char *path);
 int do_sync_push(const char *lpath, const char *rpath, int verifyApk, int show_progress);
 int do_sync_sync(const char *lpath, const char *rpath, int listonly);
-int do_sync_pull(const char *rpath, const char *lpath, int show_progress);
+int do_sync_pull(const char *rpath, const char *lpath, int show_progress, int pullTime);
 
 #define SYNC_DATA_MAX (64*1024)
 
diff --git a/adb/services.c b/adb/services.c
index 7b809da..e48e460 100644
--- a/adb/services.c
+++ b/adb/services.c
@@ -184,11 +184,26 @@
 }
 
 #if !ADB_HOST
-static int create_subprocess(const char *cmd, const char *arg0, const char *arg1, pid_t *pid)
+
+static void init_subproc_child()
 {
+    setsid();
+
+    // Set OOM score adjustment to prevent killing
+    int fd = adb_open("/proc/self/oom_score_adj", O_WRONLY);
+    if (fd >= 0) {
+        adb_write(fd, "0", 1);
+        adb_close(fd);
+    } else {
+       D("adb: unable to update oom_score_adj\n");
+    }
+}
+
+static int create_subproc_pty(const char *cmd, const char *arg0, const char *arg1, pid_t *pid)
+{
+    D("create_subproc_pty(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1);
 #ifdef HAVE_WIN32_PROC
-    D("create_subprocess(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1);
-    fprintf(stderr, "error: create_subprocess not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1);
+    fprintf(stderr, "error: create_subproc_pty not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1);
     return -1;
 #else /* !HAVE_WIN32_PROC */
     char *devname;
@@ -215,47 +230,74 @@
         return -1;
     }
 
-    if(*pid == 0){
-        int pts;
+    if (*pid == 0) {
+        init_subproc_child();
 
-        setsid();
-
-        pts = unix_open(devname, O_RDWR);
-        if(pts < 0) {
+        int pts = unix_open(devname, O_RDWR);
+        if (pts < 0) {
             fprintf(stderr, "child failed to open pseudo-term slave: %s\n", devname);
             exit(-1);
         }
 
-        dup2(pts, 0);
-        dup2(pts, 1);
-        dup2(pts, 2);
+        dup2(pts, STDIN_FILENO);
+        dup2(pts, STDOUT_FILENO);
+        dup2(pts, STDERR_FILENO);
 
         adb_close(pts);
         adb_close(ptm);
 
-        // set OOM adjustment to zero
-        char text[64];
-        snprintf(text, sizeof text, "/proc/%d/oom_adj", getpid());
-        int fd = adb_open(text, O_WRONLY);
-        if (fd >= 0) {
-            adb_write(fd, "0", 1);
-            adb_close(fd);
-        } else {
-           D("adb: unable to open %s\n", text);
-        }
         execl(cmd, cmd, arg0, arg1, NULL);
         fprintf(stderr, "- exec '%s' failed: %s (%d) -\n",
                 cmd, strerror(errno), errno);
         exit(-1);
     } else {
-        // Don't set child's OOM adjustment to zero.
-        // Let the child do it itself, as sometimes the parent starts
-        // running before the child has a /proc/pid/oom_adj.
-        // """adb: unable to open /proc/644/oom_adj""" seen in some logs.
         return ptm;
     }
 #endif /* !HAVE_WIN32_PROC */
 }
+
+static int create_subproc_raw(const char *cmd, const char *arg0, const char *arg1, pid_t *pid)
+{
+    D("create_subproc_raw(cmd=%s, arg0=%s, arg1=%s)\n", cmd, arg0, arg1);
+#ifdef HAVE_WIN32_PROC
+    fprintf(stderr, "error: create_subproc_raw not implemented on Win32 (%s %s %s)\n", cmd, arg0, arg1);
+    return -1;
+#else /* !HAVE_WIN32_PROC */
+
+    // 0 is parent socket, 1 is child socket
+    int sv[2];
+    if (unix_socketpair(AF_UNIX, SOCK_STREAM, 0, sv) < 0) {
+        printf("[ cannot create socket pair - %s ]\n", strerror(errno));
+        return -1;
+    }
+
+    *pid = fork();
+    if (*pid < 0) {
+        printf("- fork failed: %s -\n", strerror(errno));
+        adb_close(sv[0]);
+        adb_close(sv[1]);
+        return -1;
+    }
+
+    if (*pid == 0) {
+        adb_close(sv[0]);
+        init_subproc_child();
+
+        // Only hook up stdin/stdout; drop stderr
+        dup2(sv[1], STDIN_FILENO);
+        dup2(sv[1], STDOUT_FILENO);
+        adb_close(sv[1]);
+
+        execl(cmd, cmd, arg0, arg1, NULL);
+        fprintf(stderr, "- exec '%s' failed: %s (%d) -\n",
+                cmd, strerror(errno), errno);
+        exit(-1);
+    } else {
+        adb_close(sv[1]);
+        return sv[0];
+    }
+#endif /* !HAVE_WIN32_PROC */
+}
 #endif  /* !ABD_HOST */
 
 #if ADB_HOST
@@ -296,18 +338,32 @@
     }
 }
 
-static int create_subproc_thread(const char *name)
+static int create_subproc_thread(const char *name, const subproc_mode mode)
 {
     stinfo *sti;
     adb_thread_t t;
     int ret_fd;
-    pid_t pid;
-    if(name) {
-        ret_fd = create_subprocess(SHELL_COMMAND, "-c", name, &pid);
+    pid_t pid = -1;
+
+    const char *arg0, *arg1;
+    if (name == 0 || *name == 0) {
+        arg0 = "-"; arg1 = 0;
     } else {
-        ret_fd = create_subprocess(SHELL_COMMAND, "-", 0, &pid);
+        arg0 = "-c"; arg1 = name;
     }
-    D("create_subprocess() ret_fd=%d pid=%d\n", ret_fd, pid);
+
+    switch (mode) {
+    case SUBPROC_PTY:
+        ret_fd = create_subproc_pty(SHELL_COMMAND, arg0, arg1, &pid);
+        break;
+    case SUBPROC_RAW:
+        ret_fd = create_subproc_raw(SHELL_COMMAND, arg0, arg1, &pid);
+        break;
+    default:
+        fprintf(stderr, "invalid subproc_mode %d\n", mode);
+        return -1;
+    }
+    D("create_subproc ret_fd=%d pid=%d\n", ret_fd, pid);
 
     sti = malloc(sizeof(stinfo));
     if(sti == 0) fatal("cannot allocate stinfo");
@@ -315,14 +371,14 @@
     sti->cookie = (void*) (uintptr_t) pid;
     sti->fd = ret_fd;
 
-    if(adb_thread_create( &t, service_bootstrap_func, sti)){
+    if (adb_thread_create(&t, service_bootstrap_func, sti)) {
         free(sti);
         adb_close(ret_fd);
-        printf("cannot create service thread\n");
+        fprintf(stderr, "cannot create service thread\n");
         return -1;
     }
 
-    D("service thread started, fd=%d pid=%d\n",ret_fd, pid);
+    D("service thread started, fd=%d pid=%d\n", ret_fd, pid);
     return ret_fd;
 }
 #endif
@@ -367,27 +423,35 @@
     } else if (!strncmp(name, "jdwp:", 5)) {
         ret = create_jdwp_connection_fd(atoi(name+5));
     } else if(!HOST && !strncmp(name, "shell:", 6)) {
-        if(name[6]) {
-            ret = create_subproc_thread(name + 6);
-        } else {
-            ret = create_subproc_thread(0);
-        }
+        ret = create_subproc_thread(name + 6, SUBPROC_PTY);
+    } else if(!HOST && !strncmp(name, "exec:", 5)) {
+        ret = create_subproc_thread(name + 5, SUBPROC_RAW);
     } else if(!strncmp(name, "sync:", 5)) {
         ret = create_service_thread(file_sync_service, NULL);
     } else if(!strncmp(name, "remount:", 8)) {
         ret = create_service_thread(remount_service, NULL);
     } else if(!strncmp(name, "reboot:", 7)) {
         void* arg = strdup(name + 7);
-        if(arg == 0) return -1;
+        if (arg == NULL) return -1;
         ret = create_service_thread(reboot_service, arg);
     } else if(!strncmp(name, "root:", 5)) {
         ret = create_service_thread(restart_root_service, NULL);
     } else if(!strncmp(name, "backup:", 7)) {
-        char* arg = strdup(name+7);
+        char* arg = strdup(name + 7);
         if (arg == NULL) return -1;
-        ret = backup_service(BACKUP, arg);
+        char* c = arg;
+        for (; *c != '\0'; c++) {
+            if (*c == ':')
+                *c = ' ';
+        }
+        char* cmd;
+        if (asprintf(&cmd, "/system/bin/bu backup %s", arg) != -1) {
+            ret = create_subproc_thread(cmd, SUBPROC_RAW);
+            free(cmd);
+        }
+        free(arg);
     } else if(!strncmp(name, "restore:", 8)) {
-        ret = backup_service(RESTORE, NULL);
+        ret = create_subproc_thread("/system/bin/bu restore", SUBPROC_RAW);
     } else if(!strncmp(name, "tcpip:", 6)) {
         int port;
         if (sscanf(name + 6, "%d", &port) == 0) {