fs_config: replace getenv('OUT') by new fs_config parameter

Using a getenv('OUT') in such a deep down function is a wrong design
choice. Replacing with explicit parameter that may be NULL in case
device specific files can be accessed from /.
Since TARGET_COPY_OUT_SYSTEM may be defined to something different than
system we also ensure that we use a path relative to TARGET_OUT to
compute path to fs_config_* files.

Bug: 21989305
Bug: 22048934
Change-Id: Id91bc183b29beac7379d1117ad83bd3346e6897b
Signed-off-by: Thierry Strudel <tstrudel@google.com>
diff --git a/adb/file_sync_service.cpp b/adb/file_sync_service.cpp
index e8e9a0f..5d17335 100644
--- a/adb/file_sync_service.cpp
+++ b/adb/file_sync_service.cpp
@@ -57,7 +57,7 @@
         if(x == 0) return 0;
         *x = 0;
         if (should_use_fs_config(name)) {
-            fs_config(name, 1, &uid, &gid, &mode, &cap);
+            fs_config(name, 1, NULL, &uid, &gid, &mode, &cap);
         }
         ret = adb_mkdir(name, mode);
         if((ret < 0) && (errno != EEXIST)) {
@@ -366,7 +366,7 @@
         tmp++;
     }
     if (should_use_fs_config(path)) {
-        fs_config(tmp, 0, &uid, &gid, &mode, &cap);
+        fs_config(tmp, 0, NULL, &uid, &gid, &mode, &cap);
     }
     return handle_send_file(s, path, uid, gid, mode, buffer, do_unlink);
 }
diff --git a/cpio/mkbootfs.c b/cpio/mkbootfs.c
index 7175749..0e35323 100644
--- a/cpio/mkbootfs.c
+++ b/cpio/mkbootfs.c
@@ -41,6 +41,7 @@
 };
 
 static struct fs_config_entry* canned_config = NULL;
+static char *target_out_path = NULL;
 
 /* Each line in the canned file should be a path plus three ints (uid,
  * gid, mode). */
@@ -79,7 +80,8 @@
     } else {
         // Use the compiled-in fs_config() function.
         unsigned st_mode = s->st_mode;
-        fs_config(path, S_ISDIR(s->st_mode), &s->st_uid, &s->st_gid, &st_mode, &capabilities);
+        fs_config(path, S_ISDIR(s->st_mode), target_out_path,
+                       &s->st_uid, &s->st_gid, &st_mode, &capabilities);
         s->st_mode = (typeof(s->st_mode)) st_mode;
     }
 }
@@ -328,6 +330,12 @@
     argc--;
     argv++;
 
+    if (argc > 1 && strcmp(argv[0], "-d") == 0) {
+        target_out_path = argv[1];
+        argc -= 2;
+        argv += 2;
+    }
+
     if (argc > 1 && strcmp(argv[0], "-f") == 0) {
         read_canned_config(argv[1]);
         argc -= 2;
diff --git a/fs_mgr/fs_mgr_format.c b/fs_mgr/fs_mgr_format.c
index 95c6a74..c73045d 100644
--- a/fs_mgr/fs_mgr_format.c
+++ b/fs_mgr/fs_mgr_format.c
@@ -52,7 +52,7 @@
     info.len = ((off64_t)nr_sec * 512);
 
     /* Use make_ext4fs_internal to avoid wiping an already-wiped partition. */
-    rc = make_ext4fs_internal(fd, NULL, fs_mnt_point, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL);
+    rc = make_ext4fs_internal(fd, NULL, NULL, fs_mnt_point, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL);
     if (rc) {
         ERROR("make_ext4fs returned %d.\n", rc);
     }
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index 02fe2b5..2ed27dc 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -206,13 +206,13 @@
  * Used in:
  *  build/tools/fs_config/fs_config.c
  *  build/tools/fs_get_stats/fs_get_stats.c
- *  external/genext2fs/genext2fs.c
+ *  system/extras/ext4_utils/make_ext4fs_main.c
  *  external/squashfs-tools/squashfs-tools/android.c
  *  system/core/cpio/mkbootfs.c
  *  system/core/adb/file_sync_service.cpp
  *  system/extras/ext4_utils/canned_fs_config.c
  */
-void fs_config(const char *path, int dir,
+void fs_config(const char *path, int dir, const char *target_out_path,
                unsigned *uid, unsigned *gid, unsigned *mode, uint64_t *capabilities);
 
 ssize_t fs_config_generate(char *buffer, size_t length, const struct fs_path_config *pc);
diff --git a/libcutils/fs_config.c b/libcutils/fs_config.c
index 9f8023e..9a1ad19 100644
--- a/libcutils/fs_config.c
+++ b/libcutils/fs_config.c
@@ -149,14 +149,21 @@
     { 00644, AID_ROOT,      AID_ROOT,      0, 0 },
 };
 
-static int fs_config_open(int dir)
+static int fs_config_open(int dir, const char *target_out_path)
 {
     int fd = -1;
 
-    const char *out = getenv("OUT");
-    if (out && *out) {
+    if (target_out_path && *target_out_path) {
+        /* target_out_path is the path to the directory holding content of system partition
+           but as we cannot guaranty it ends with '/system' we need this below skip_len logic */
         char *name = NULL;
-        asprintf(&name, "%s%s", out, dir ? conf_dir : conf_file);
+        int target_out_path_len = strlen(target_out_path);
+        int skip_len = strlen("/system");
+
+        if (target_out_path[target_out_path_len] == '/') {
+            skip_len++;
+        }
+        asprintf(&name, "%s%s", target_out_path, (dir ? conf_dir : conf_file) + skip_len);
         if (name) {
             fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_BINARY));
             free(name);
@@ -187,7 +194,7 @@
     return !strncmp(prefix, path, len);
 }
 
-void fs_config(const char *path, int dir,
+void fs_config(const char *path, int dir, const char *target_out_path,
                unsigned *uid, unsigned *gid, unsigned *mode, uint64_t *capabilities)
 {
     const struct fs_path_config *pc;
@@ -199,7 +206,7 @@
 
     plen = strlen(path);
 
-    fd = fs_config_open(dir);
+    fd = fs_config_open(dir, target_out_path);
     if (fd >= 0) {
         struct fs_path_config_from_file header;