Added support for vendor partition to adb

Remount will now remount the vendor partition as well, if it exists.
Sync will also allow you to sync vendor, and will include it by
default if it exists.

Change-Id: Iea1e8212f445e96233438a8d8a9d3266bf3d6557
Signed-off-by: Daniel Rosenberg <drosen@google.com>
diff --git a/commandline.c b/commandline.c
index 507f73e..6e85a14 100644
--- a/commandline.c
+++ b/commandline.c
@@ -41,7 +41,7 @@
 
 void get_my_path(char *s, size_t maxLen);
 int find_sync_dirs(const char *srcarg,
-        char **android_srcdir_out, char **data_srcdir_out);
+        char **android_srcdir_out, char **data_srcdir_out, char **vendor_srcdir_out);
 int install_app(transport_type transport, char* serial, int argc, char** argv);
 int uninstall_app(transport_type transport, char* serial, int argc, char** argv);
 
@@ -196,7 +196,7 @@
         "  adb get-serialno             - prints: <serial-number>\n"
         "  adb get-devpath              - prints: <device-path>\n"
         "  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 remount                  - remounts the /system and /vendor (if present) partitions on the device read-write\n"
         "  adb reboot [bootloader|recovery] - reboots the device, optionally into the bootloader or recovery program\n"
         "  adb reboot-bootloader        - reboots the device into the bootloader\n"
         "  adb root                     - restarts the adbd daemon with root permissions\n"
@@ -212,9 +212,9 @@
         "adb sync notes: adb sync [ <directory> ]\n"
         "  <localdir> can be interpreted in several ways:\n"
         "\n"
-        "  - If <directory> is not specified, both /system and /data partitions will be updated.\n"
+        "  - If <directory> is not specified, /system, /vendor (if present), and /data partitions will be updated.\n"
         "\n"
-        "  - If it is \"system\" or \"data\", only the corresponding partition\n"
+        "  - If it is \"system\", \"vendor\" or \"data\", only the corresponding partition\n"
         "    is updated.\n"
         "\n"
         "environmental variables:\n"
@@ -1498,7 +1498,7 @@
     }
 
     if(!strcmp(argv[0], "sync")) {
-        char *srcarg, *android_srcpath, *data_srcpath;
+        char *srcarg, *android_srcpath, *data_srcpath, *vendor_srcpath;
         int listonly = 0;
 
         int ret;
@@ -1518,15 +1518,18 @@
         } else {
             return usage();
         }
-        ret = find_sync_dirs(srcarg, &android_srcpath, &data_srcpath);
+        ret = find_sync_dirs(srcarg, &android_srcpath, &data_srcpath, &vendor_srcpath);
         if(ret != 0) return usage();
 
         if(android_srcpath != NULL)
             ret = do_sync_sync(android_srcpath, "/system", listonly);
+        if(ret == 0 && vendor_srcpath != NULL)
+            ret = do_sync_sync(vendor_srcpath, "/vendor", listonly);
         if(ret == 0 && data_srcpath != NULL)
             ret = do_sync_sync(data_srcpath, "/data", listonly);
 
         free(android_srcpath);
+        free(vendor_srcpath);
         free(data_srcpath);
         return ret;
     }
@@ -1637,25 +1640,30 @@
 }
 
 int find_sync_dirs(const char *srcarg,
-        char **android_srcdir_out, char **data_srcdir_out)
+        char **android_srcdir_out, char **data_srcdir_out, char **vendor_srcdir_out)
 {
-    char *android_srcdir, *data_srcdir;
+    char *android_srcdir = NULL, *data_srcdir = NULL, *vendor_srcdir = NULL;
+    struct stat st;
 
     if(srcarg == NULL) {
         android_srcdir = product_file("system");
         data_srcdir = product_file("data");
+        vendor_srcdir = product_file("vendor");
+        /* Check if vendor partition exists */
+        if (lstat(vendor_srcdir, &st) || !S_ISDIR(st.st_mode))
+            vendor_srcdir = NULL;
     } else {
         /* srcarg may be "data", "system" or NULL.
          * if srcarg is NULL, then both data and system are synced
          */
         if(strcmp(srcarg, "system") == 0) {
             android_srcdir = product_file("system");
-            data_srcdir = NULL;
         } else if(strcmp(srcarg, "data") == 0) {
-            android_srcdir = NULL;
             data_srcdir = product_file("data");
+        } else if(strcmp(srcarg, "vendor") == 0) {
+            vendor_srcdir = product_file("vendor");
         } else {
-            /* It's not "system" or "data".
+            /* It's not "system", "vendor", or "data".
              */
             return 1;
         }
@@ -1666,11 +1674,15 @@
     else
         free(android_srcdir);
 
-    if(data_srcdir_out != NULL)
-        *data_srcdir_out = data_srcdir;
+    if(vendor_srcdir_out != NULL)
+        *vendor_srcdir_out = vendor_srcdir;
     else
-        free(data_srcdir);
+        free(vendor_srcdir);
 
+    if(data_srcdir_out != NULL)
+            *data_srcdir_out = data_srcdir;
+        else
+            free(data_srcdir);
     return 0;
 }
 
diff --git a/file_sync_client.c b/file_sync_client.c
index d3cb113..c1ab808 100644
--- a/file_sync_client.c
+++ b/file_sync_client.c
@@ -697,30 +697,33 @@
             continue;
         strcpy(stat_path, lpath);
         strcat(stat_path, de->d_name);
-        stat(stat_path, &st);
 
-        if (S_ISDIR(st.st_mode)) {
-            ci = mkcopyinfo(lpath, rpath, name, 1);
-            ci->next = dirlist;
-            dirlist = ci;
-        } else {
-            ci = mkcopyinfo(lpath, rpath, name, 0);
-            if(lstat(ci->src, &st)) {
-                fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno));
-                free(ci);
-                closedir(d);
-                return -1;
-            }
-            if(!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
-                fprintf(stderr, "skipping special file '%s'\n", ci->src);
-                free(ci);
+        if(!lstat(stat_path, &st)) {
+            if (S_ISDIR(st.st_mode)) {
+                ci = mkcopyinfo(lpath, rpath, name, 1);
+                ci->next = dirlist;
+                dirlist = ci;
             } else {
-                ci->time = st.st_mtime;
-                ci->mode = st.st_mode;
-                ci->size = st.st_size;
-                ci->next = *filelist;
-                *filelist = ci;
+                ci = mkcopyinfo(lpath, rpath, name, 0);
+                if(lstat(ci->src, &st)) {
+                    fprintf(stderr,"cannot stat '%s': %s\n", ci->src, strerror(errno));
+                    free(ci);
+                    closedir(d);
+                    return -1;
+                }
+                if(!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
+                    fprintf(stderr, "skipping special file '%s'\n", ci->src);
+                    free(ci);
+                } else {
+                    ci->time = st.st_mtime;
+                    ci->mode = st.st_mode;
+                    ci->size = st.st_size;
+                    ci->next = *filelist;
+                    *filelist = ci;
+                }
             }
+        } else {
+            fprintf(stderr, "cannot lstat '%s': %s\n",stat_path , strerror(errno));
         }
     }
 
diff --git a/file_sync_service.c b/file_sync_service.c
index 1d80d26..e6f64bb 100644
--- a/file_sync_service.c
+++ b/file_sync_service.c
@@ -39,6 +39,11 @@
     return (strncmp(SYSTEM, name, strlen(SYSTEM)) == 0);
 }
 
+static bool is_on_vendor(const char *name) {
+    const char *VENDOR = "/vendor/";
+    return (strncmp(VENDOR, name, strlen(VENDOR)) == 0);
+}
+
 static int mkdirs(char *name)
 {
     int ret;
@@ -54,7 +59,7 @@
         x = adb_dirstart(x);
         if(x == 0) return 0;
         *x = 0;
-        if (is_on_system(name)) {
+        if (is_on_system(name) || is_on_vendor(name)) {
             fs_config(name, 1, &uid, &gid, &mode, &cap);
         }
         ret = adb_mkdir(name, mode);
@@ -369,7 +374,7 @@
         if(*tmp == '/') {
             tmp++;
         }
-        if (is_on_system(path)) {
+        if (is_on_system(path) || is_on_vendor(path)) {
             fs_config(tmp, 0, &uid, &gid, &mode, &cap);
         }
         ret = handle_send_file(s, path, uid, gid, mode, buffer, do_unlink);
diff --git a/remount_service.c b/remount_service.c
index d3a649b..fd81e28 100644
--- a/remount_service.c
+++ b/remount_service.c
@@ -29,6 +29,7 @@
 
 
 static int system_ro = 1;
+static int vendor_ro = 1;
 
 /* Returns the device used to mount a directory in /proc/mounts */
 static char *find_mount(const char *dir)
@@ -67,18 +68,27 @@
     return NULL;
 }
 
+static int hasVendorPartition()
+{
+    struct stat info;
+    if (!lstat("/vendor", &info))
+        if ((info.st_mode & S_IFMT) == S_IFDIR)
+          return true;
+    return false;
+}
+
 /* Init mounts /system as read only, remount to enable writes. */
-static int remount_system()
+static int remount(const char* dir, int* dir_ro)
 {
     char *dev;
     int fd;
     int OFF = 0;
 
-    if (system_ro == 0) {
+    if (dir_ro == 0) {
         return 0;
     }
 
-    dev = find_mount("/system");
+    dev = find_mount(dir);
 
     if (!dev)
         return -1;
@@ -90,11 +100,11 @@
     ioctl(fd, BLKROSET, &OFF);
     adb_close(fd);
 
-    system_ro = mount(dev, "/system", "none", MS_REMOUNT, NULL);
+    *dir_ro = mount(dev, dir, "none", MS_REMOUNT, NULL);
 
     free(dev);
 
-    return system_ro;
+    return *dir_ro;
 }
 
 static void write_string(int fd, const char* str)
@@ -104,16 +114,25 @@
 
 void remount_service(int fd, void *cookie)
 {
-    int ret = remount_system();
-
-    if (!ret)
-       write_string(fd, "remount succeeded\n");
-    else {
-        char    buffer[200];
-        snprintf(buffer, sizeof(buffer), "remount failed: %s\n", strerror(errno));
+    char buffer[200];
+    if (remount("/system", &system_ro)) {
+        snprintf(buffer, sizeof(buffer), "remount of system failed: %s\n",strerror(errno));
         write_string(fd, buffer);
     }
 
+    if (hasVendorPartition()) {
+        if (remount("/vendor", &vendor_ro)) {
+            snprintf(buffer, sizeof(buffer), "remount of vendor failed: %s\n",strerror(errno));
+            write_string(fd, buffer);
+        }
+    }
+
+    if (!system_ro && (!vendor_ro || !hasVendorPartition()))
+        write_string(fd, "remount succeeded\n");
+    else {
+        write_string(fd, "remount failed\n");
+    }
+
     adb_close(fd);
 }