Loading core/Makefile +5 −3 Original line number Diff line number Diff line Loading @@ -1173,6 +1173,7 @@ $(BUILT_TARGET_FILES_PACKAGE): \ $(INSTALLED_CACHEIMAGE_TARGET) \ $(INSTALLED_VENDORIMAGE_TARGET) \ $(INSTALLED_ANDROID_INFO_TXT_TARGET) \ $(SELINUX_FC) \ $(built_ota_tools) \ $(APKCERTS_FILE) \ $(HOST_OUT_EXECUTABLES)/fs_config \ Loading Loading @@ -1260,13 +1261,14 @@ ifdef PRODUCT_EXTRA_RECOVERY_KEYS $(hide) echo "extra_recovery_keys=$(PRODUCT_EXTRA_RECOVERY_KEYS)" >> $(zip_root)/META/misc_info.txt endif $(hide) echo "mkbootimg_args=$(BOARD_MKBOOTIMG_ARGS)" >> $(zip_root)/META/misc_info.txt $(hide) echo "use_set_metadata=1" >> $(zip_root)/META/misc_info.txt $(call generate-userimage-prop-dictionary, $(zip_root)/META/misc_info.txt) @# Zip everything up, preserving symlinks $(hide) (cd $(zip_root) && zip -qry ../$(notdir $@) .) @# Run fs_config on all the system, boot ramdisk, and recovery ramdisk files in the zip, and save the output $(hide) zipinfo -1 $@ | awk 'BEGIN { FS="SYSTEM/" } /^SYSTEM\// {print "system/" $$2}' | $(HOST_OUT_EXECUTABLES)/fs_config > $(zip_root)/META/filesystem_config.txt $(hide) zipinfo -1 $@ | awk 'BEGIN { FS="BOOT/RAMDISK/" } /^BOOT\/RAMDISK\// {print $$2}' | $(HOST_OUT_EXECUTABLES)/fs_config > $(zip_root)/META/boot_filesystem_config.txt $(hide) zipinfo -1 $@ | awk 'BEGIN { FS="RECOVERY/RAMDISK/" } /^RECOVERY\/RAMDISK\// {print $$2}' | $(HOST_OUT_EXECUTABLES)/fs_config > $(zip_root)/META/recovery_filesystem_config.txt $(hide) zipinfo -1 $@ | awk 'BEGIN { FS="SYSTEM/" } /^SYSTEM\// {print "system/" $$2}' | $(HOST_OUT_EXECUTABLES)/fs_config -C -S $(SELINUX_FC) > $(zip_root)/META/filesystem_config.txt $(hide) zipinfo -1 $@ | awk 'BEGIN { FS="BOOT/RAMDISK/" } /^BOOT\/RAMDISK\// {print $$2}' | $(HOST_OUT_EXECUTABLES)/fs_config -C -S $(SELINUX_FC) > $(zip_root)/META/boot_filesystem_config.txt $(hide) zipinfo -1 $@ | awk 'BEGIN { FS="RECOVERY/RAMDISK/" } /^RECOVERY\/RAMDISK\// {print $$2}' | $(HOST_OUT_EXECUTABLES)/fs_config -C -S $(SELINUX_FC) > $(zip_root)/META/recovery_filesystem_config.txt $(hide) (cd $(zip_root) && zip -q ../$(notdir $@) META/*filesystem_config.txt) .PHONY: target-files-package Loading tools/fs_config/Android.mk +1 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := fs_config.c LOCAL_MODULE := fs_config LOCAL_STATIC_LIBRARIES := libselinux LOCAL_FORCE_STATIC_EXECUTABLE := true include $(BUILD_HOST_EXECUTABLE) tools/fs_config/fs_config.c +90 −5 Original line number Diff line number Diff line Loading @@ -15,10 +15,16 @@ */ #include <stdio.h> #include <stdlib.h> #include <sys/stat.h> #include <errno.h> #include <unistd.h> #include <string.h> #include <inttypes.h> #include <selinux/selinux.h> #include <selinux/label.h> #include <selinux/android.h> #include "private/android_filesystem_config.h" Loading @@ -27,6 +33,11 @@ // filename along with its desired uid, gid, and mode (in octal). // The leading slash should be stripped from the input. // // After the first 4 columns, optional key=value pairs are emitted // for each file. Currently, the following keys are supported: // * -S: selabel=[selinux_label] // * -C: capabilities=[hex capabilities value] // // Example input: // // system/etc/dbus.conf Loading @@ -37,11 +48,52 @@ // system/etc/dbus.conf 1002 1002 440 // data/app 1000 1000 771 // // or if, for example, -S is used: // // system/etc/dbus.conf 1002 1002 440 selabel=u:object_r:system_file:s0 // data/app 1000 1000 771 selabel=u:object_r:apk_data_file:s0 // // Note that the output will omit the trailing slash from // directories. static struct selabel_handle* get_sehnd(const char* context_file) { struct selinux_opt seopts[] = { { SELABEL_OPT_PATH, context_file } }; struct selabel_handle* sehnd = selabel_open(SELABEL_CTX_FILE, seopts, 1); if (!sehnd) { perror("error running selabel_open"); exit(EXIT_FAILURE); } return sehnd; } static void usage() { fprintf(stderr, "Usage: fs_config [-S context_file] [-C]\n"); } int main(int argc, char** argv) { char buffer[1024]; const char* context_file = NULL; struct selabel_handle* sehnd = NULL; int print_capabilities = 0; int opt; while((opt = getopt(argc, argv, "CS:")) != -1) { switch(opt) { case 'C': print_capabilities = 1; break; case 'S': context_file = optarg; break; default: usage(); exit(EXIT_FAILURE); } } if (context_file != NULL) { sehnd = get_sehnd(context_file); } while (fgets(buffer, 1023, stdin) != NULL) { int is_dir = 0; Loading @@ -64,7 +116,40 @@ int main(int argc, char** argv) { unsigned uid = 0, gid = 0, mode = 0; uint64_t capabilities; fs_config(buffer, is_dir, &uid, &gid, &mode, &capabilities); printf("%s %d %d %o\n", buffer, uid, gid, mode); printf("%s %d %d %o", buffer, uid, gid, mode); if (sehnd != NULL) { size_t buffer_strlen = strnlen(buffer, sizeof(buffer)); if (buffer_strlen >= sizeof(buffer)) { fprintf(stderr, "non null terminated buffer, aborting\n"); exit(EXIT_FAILURE); } size_t full_name_size = buffer_strlen + 2; char* full_name = (char*) malloc(full_name_size); if (full_name == NULL) { perror("malloc"); exit(EXIT_FAILURE); } full_name[0] = '/'; strncpy(full_name + 1, buffer, full_name_size - 1); full_name[full_name_size - 1] = '\0'; char* secontext; if (selabel_lookup(sehnd, &secontext, full_name, ( mode | (is_dir ? S_IFDIR : S_IFREG)))) { secontext = strdup("u:object_r:unlabeled:s0"); } printf(" selabel=%s", secontext); free(full_name); freecon(secontext); } if (print_capabilities) { printf(" capabilities=0x%" PRIx64, capabilities); } printf("\n"); } return 0; } tools/releasetools/edify_generator.py +25 −6 Original line number Diff line number Diff line Loading @@ -217,14 +217,33 @@ class EdifyGenerator(object): else: raise ValueError("don't know how to write \"%s\" partitions" % (p.fs_type,)) def SetPermissions(self, fn, uid, gid, mode): def SetPermissions(self, fn, uid, gid, mode, selabel, capabilities): """Set file ownership and permissions.""" if not self.info.get("use_set_metadata", False): self.script.append('set_perm(%d, %d, 0%o, "%s");' % (uid, gid, mode, fn)) else: if capabilities is None: capabilities = "0x0" cmd = 'set_metadata("%s", "uid", %d, "gid", %d, "mode", 0%o, ' \ '"capabilities", %s' % (fn, uid, gid, mode, capabilities) if selabel is not None: cmd += ', "selabel", "%s"' % ( selabel ) cmd += ');' self.script.append(cmd) def SetPermissionsRecursive(self, fn, uid, gid, dmode, fmode): def SetPermissionsRecursive(self, fn, uid, gid, dmode, fmode, selabel, capabilities): """Recursively set path ownership and permissions.""" if not self.info.get("use_set_metadata", False): self.script.append('set_perm_recursive(%d, %d, 0%o, 0%o, "%s");' % (uid, gid, dmode, fmode, fn)) else: if capabilities is None: capabilities = "0x0" cmd = 'set_metadata_recursive("%s", "uid", %d, "gid", %d, ' \ '"dmode", 0%o, "fmode", 0%o, "capabilities", %s' \ % (fn, uid, gid, dmode, fmode, capabilities) if selabel is not None: cmd += ', "selabel", "%s"' % ( selabel ) cmd += ');' self.script.append(cmd) def MakeSymlinks(self, symlink_list): """Create symlinks, given a list of (dest, link) pairs.""" Loading tools/releasetools/ota_from_target_files +51 −39 Original line number Diff line number Diff line Loading @@ -117,6 +117,8 @@ class Item: self.uid = None self.gid = None self.mode = None self.selabel = None self.capabilities = None self.dir = dir if name: Loading Loading @@ -147,82 +149,88 @@ class Item: @classmethod def GetMetadata(cls, input_zip): try: # See if the target_files contains a record of what the uid, # gid, and mode is supposed to be. # The target_files contains a record of what the uid, # gid, and mode are supposed to be. output = input_zip.read("META/filesystem_config.txt") except KeyError: # Run the external 'fs_config' program to determine the desired # uid, gid, and mode for every Item object. Note this uses the # one in the client now, which might not be the same as the one # used when this target_files was built. p = common.Run(["fs_config"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) suffix = { False: "", True: "/" } input = "".join(["%s%s\n" % (i.name, suffix[i.dir]) for i in cls.ITEMS.itervalues() if i.name]) output, error = p.communicate(input) assert not error for line in output.split("\n"): if not line: continue name, uid, gid, mode = line.split() columns = line.split() name, uid, gid, mode = columns[:4] selabel = None capabilities = None # After the first 4 columns, there are a series of key=value # pairs. Extract out the fields we care about. for element in columns[4:]: key, value = element.split("=") if key == "selabel": selabel = value if key == "capabilities": capabilities = value i = cls.ITEMS.get(name, None) if i is not None: i.uid = int(uid) i.gid = int(gid) i.mode = int(mode, 8) i.selabel = selabel i.capabilities = capabilities if i.dir: i.children.sort(key=lambda i: i.name) # set metadata for the files generated by this script. i = cls.ITEMS.get("system/recovery-from-boot.p", None) if i: i.uid, i.gid, i.mode = 0, 0, 0644 if i: i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0644, None, None i = cls.ITEMS.get("system/etc/install-recovery.sh", None) if i: i.uid, i.gid, i.mode = 0, 0, 0544 if i: i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0544, None, None def CountChildMetadata(self): """Count up the (uid, gid, mode) tuples for all children and determine the best strategy for using set_perm_recursive and """Count up the (uid, gid, mode, selabel, capabilities) tuples for all children and determine the best strategy for using set_perm_recursive and set_perm to correctly chown/chmod all the files to their desired values. Recursively calls itself for all descendants. Returns a dict of {(uid, gid, dmode, fmode): count} counting up Returns a dict of {(uid, gid, dmode, fmode, selabel, capabilities): count} counting up all descendants of this node. (dmode or fmode may be None.) Also sets the best_subtree of each directory Item to the (uid, gid, dmode, fmode) tuple that will match the most descendants of that Item. dmode, fmode, selabel, capabilities) tuple that will match the most descendants of that Item. """ assert self.dir d = self.descendants = {(self.uid, self.gid, self.mode, None): 1} d = self.descendants = {(self.uid, self.gid, self.mode, None, self.selabel, self.capabilities): 1} for i in self.children: if i.dir: for k, v in i.CountChildMetadata().iteritems(): d[k] = d.get(k, 0) + v else: k = (i.uid, i.gid, None, i.mode) k = (i.uid, i.gid, None, i.mode, i.selabel, i.capabilities) d[k] = d.get(k, 0) + 1 # Find the (uid, gid, dmode, fmode) tuple that matches the most # descendants. # Find the (uid, gid, dmode, fmode, selabel, capabilities) # tuple that matches the most descendants. # First, find the (uid, gid) pair that matches the most # descendants. ug = {} for (uid, gid, _, _), count in d.iteritems(): for (uid, gid, _, _, _, _), count in d.iteritems(): ug[(uid, gid)] = ug.get((uid, gid), 0) + count ug = MostPopularKey(ug, (0, 0)) # Now find the dmode and fmode that match the most descendants # with that (uid, gid), and choose those. # Now find the dmode, fmode, selabel, and capabilities that match # the most descendants with that (uid, gid), and choose those. best_dmode = (0, 0755) best_fmode = (0, 0644) best_selabel = (0, None) best_capabilities = (0, None) for k, count in d.iteritems(): if k[:2] != ug: continue if k[2] is not None and count >= best_dmode[0]: best_dmode = (count, k[2]) if k[3] is not None and count >= best_fmode[0]: best_fmode = (count, k[3]) self.best_subtree = ug + (best_dmode[1], best_fmode[1]) if k[4] is not None and count >= best_selabel[0]: best_selabel = (count, k[4]) if k[5] is not None and count >= best_capabilities[0]: best_capabilities = (count, k[5]) self.best_subtree = ug + (best_dmode[1], best_fmode[1], best_selabel[1], best_capabilities[1]) return d Loading @@ -234,7 +242,7 @@ class Item: self.CountChildMetadata() def recurse(item, current): # current is the (uid, gid, dmode, fmode) tuple that the current # current is the (uid, gid, dmode, fmode, selabel, capabilities) tuple that the current # item (and all its children) have already been set to. We only # need to issue set_perm/set_perm_recursive commands if we're # supposed to be something different. Loading @@ -244,17 +252,21 @@ class Item: current = item.best_subtree if item.uid != current[0] or item.gid != current[1] or \ item.mode != current[2]: script.SetPermissions("/"+item.name, item.uid, item.gid, item.mode) item.mode != current[2] or item.selabel != current[4] or \ item.capabilities != current[5]: script.SetPermissions("/"+item.name, item.uid, item.gid, item.mode, item.selabel, item.capabilities) for i in item.children: recurse(i, current) else: if item.uid != current[0] or item.gid != current[1] or \ item.mode != current[3]: script.SetPermissions("/"+item.name, item.uid, item.gid, item.mode) item.mode != current[3] or item.selabel != current[4] or \ item.capabilities != current[5]: script.SetPermissions("/"+item.name, item.uid, item.gid, item.mode, item.selabel, item.capabilities) recurse(self, (-1, -1, -1, -1)) recurse(self, (-1, -1, -1, -1, None, None)) def CopySystemFiles(input_zip, output_zip=None, Loading Loading @@ -733,7 +745,7 @@ def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip): for item in deferred_patch_list: fn, tf, sf, size, _ = item script.ApplyPatch("/"+fn, "-", tf.size, tf.sha1, sf.sha1, "patch/"+fn+".p") script.SetPermissions("/system/build.prop", 0, 0, 0644) script.SetPermissions("/system/build.prop", 0, 0, 0644, None, None) script.AddToZip(target_zip, output_zip) WriteMetadata(metadata, output_zip) Loading Loading
core/Makefile +5 −3 Original line number Diff line number Diff line Loading @@ -1173,6 +1173,7 @@ $(BUILT_TARGET_FILES_PACKAGE): \ $(INSTALLED_CACHEIMAGE_TARGET) \ $(INSTALLED_VENDORIMAGE_TARGET) \ $(INSTALLED_ANDROID_INFO_TXT_TARGET) \ $(SELINUX_FC) \ $(built_ota_tools) \ $(APKCERTS_FILE) \ $(HOST_OUT_EXECUTABLES)/fs_config \ Loading Loading @@ -1260,13 +1261,14 @@ ifdef PRODUCT_EXTRA_RECOVERY_KEYS $(hide) echo "extra_recovery_keys=$(PRODUCT_EXTRA_RECOVERY_KEYS)" >> $(zip_root)/META/misc_info.txt endif $(hide) echo "mkbootimg_args=$(BOARD_MKBOOTIMG_ARGS)" >> $(zip_root)/META/misc_info.txt $(hide) echo "use_set_metadata=1" >> $(zip_root)/META/misc_info.txt $(call generate-userimage-prop-dictionary, $(zip_root)/META/misc_info.txt) @# Zip everything up, preserving symlinks $(hide) (cd $(zip_root) && zip -qry ../$(notdir $@) .) @# Run fs_config on all the system, boot ramdisk, and recovery ramdisk files in the zip, and save the output $(hide) zipinfo -1 $@ | awk 'BEGIN { FS="SYSTEM/" } /^SYSTEM\// {print "system/" $$2}' | $(HOST_OUT_EXECUTABLES)/fs_config > $(zip_root)/META/filesystem_config.txt $(hide) zipinfo -1 $@ | awk 'BEGIN { FS="BOOT/RAMDISK/" } /^BOOT\/RAMDISK\// {print $$2}' | $(HOST_OUT_EXECUTABLES)/fs_config > $(zip_root)/META/boot_filesystem_config.txt $(hide) zipinfo -1 $@ | awk 'BEGIN { FS="RECOVERY/RAMDISK/" } /^RECOVERY\/RAMDISK\// {print $$2}' | $(HOST_OUT_EXECUTABLES)/fs_config > $(zip_root)/META/recovery_filesystem_config.txt $(hide) zipinfo -1 $@ | awk 'BEGIN { FS="SYSTEM/" } /^SYSTEM\// {print "system/" $$2}' | $(HOST_OUT_EXECUTABLES)/fs_config -C -S $(SELINUX_FC) > $(zip_root)/META/filesystem_config.txt $(hide) zipinfo -1 $@ | awk 'BEGIN { FS="BOOT/RAMDISK/" } /^BOOT\/RAMDISK\// {print $$2}' | $(HOST_OUT_EXECUTABLES)/fs_config -C -S $(SELINUX_FC) > $(zip_root)/META/boot_filesystem_config.txt $(hide) zipinfo -1 $@ | awk 'BEGIN { FS="RECOVERY/RAMDISK/" } /^RECOVERY\/RAMDISK\// {print $$2}' | $(HOST_OUT_EXECUTABLES)/fs_config -C -S $(SELINUX_FC) > $(zip_root)/META/recovery_filesystem_config.txt $(hide) (cd $(zip_root) && zip -q ../$(notdir $@) META/*filesystem_config.txt) .PHONY: target-files-package Loading
tools/fs_config/Android.mk +1 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := fs_config.c LOCAL_MODULE := fs_config LOCAL_STATIC_LIBRARIES := libselinux LOCAL_FORCE_STATIC_EXECUTABLE := true include $(BUILD_HOST_EXECUTABLE)
tools/fs_config/fs_config.c +90 −5 Original line number Diff line number Diff line Loading @@ -15,10 +15,16 @@ */ #include <stdio.h> #include <stdlib.h> #include <sys/stat.h> #include <errno.h> #include <unistd.h> #include <string.h> #include <inttypes.h> #include <selinux/selinux.h> #include <selinux/label.h> #include <selinux/android.h> #include "private/android_filesystem_config.h" Loading @@ -27,6 +33,11 @@ // filename along with its desired uid, gid, and mode (in octal). // The leading slash should be stripped from the input. // // After the first 4 columns, optional key=value pairs are emitted // for each file. Currently, the following keys are supported: // * -S: selabel=[selinux_label] // * -C: capabilities=[hex capabilities value] // // Example input: // // system/etc/dbus.conf Loading @@ -37,11 +48,52 @@ // system/etc/dbus.conf 1002 1002 440 // data/app 1000 1000 771 // // or if, for example, -S is used: // // system/etc/dbus.conf 1002 1002 440 selabel=u:object_r:system_file:s0 // data/app 1000 1000 771 selabel=u:object_r:apk_data_file:s0 // // Note that the output will omit the trailing slash from // directories. static struct selabel_handle* get_sehnd(const char* context_file) { struct selinux_opt seopts[] = { { SELABEL_OPT_PATH, context_file } }; struct selabel_handle* sehnd = selabel_open(SELABEL_CTX_FILE, seopts, 1); if (!sehnd) { perror("error running selabel_open"); exit(EXIT_FAILURE); } return sehnd; } static void usage() { fprintf(stderr, "Usage: fs_config [-S context_file] [-C]\n"); } int main(int argc, char** argv) { char buffer[1024]; const char* context_file = NULL; struct selabel_handle* sehnd = NULL; int print_capabilities = 0; int opt; while((opt = getopt(argc, argv, "CS:")) != -1) { switch(opt) { case 'C': print_capabilities = 1; break; case 'S': context_file = optarg; break; default: usage(); exit(EXIT_FAILURE); } } if (context_file != NULL) { sehnd = get_sehnd(context_file); } while (fgets(buffer, 1023, stdin) != NULL) { int is_dir = 0; Loading @@ -64,7 +116,40 @@ int main(int argc, char** argv) { unsigned uid = 0, gid = 0, mode = 0; uint64_t capabilities; fs_config(buffer, is_dir, &uid, &gid, &mode, &capabilities); printf("%s %d %d %o\n", buffer, uid, gid, mode); printf("%s %d %d %o", buffer, uid, gid, mode); if (sehnd != NULL) { size_t buffer_strlen = strnlen(buffer, sizeof(buffer)); if (buffer_strlen >= sizeof(buffer)) { fprintf(stderr, "non null terminated buffer, aborting\n"); exit(EXIT_FAILURE); } size_t full_name_size = buffer_strlen + 2; char* full_name = (char*) malloc(full_name_size); if (full_name == NULL) { perror("malloc"); exit(EXIT_FAILURE); } full_name[0] = '/'; strncpy(full_name + 1, buffer, full_name_size - 1); full_name[full_name_size - 1] = '\0'; char* secontext; if (selabel_lookup(sehnd, &secontext, full_name, ( mode | (is_dir ? S_IFDIR : S_IFREG)))) { secontext = strdup("u:object_r:unlabeled:s0"); } printf(" selabel=%s", secontext); free(full_name); freecon(secontext); } if (print_capabilities) { printf(" capabilities=0x%" PRIx64, capabilities); } printf("\n"); } return 0; }
tools/releasetools/edify_generator.py +25 −6 Original line number Diff line number Diff line Loading @@ -217,14 +217,33 @@ class EdifyGenerator(object): else: raise ValueError("don't know how to write \"%s\" partitions" % (p.fs_type,)) def SetPermissions(self, fn, uid, gid, mode): def SetPermissions(self, fn, uid, gid, mode, selabel, capabilities): """Set file ownership and permissions.""" if not self.info.get("use_set_metadata", False): self.script.append('set_perm(%d, %d, 0%o, "%s");' % (uid, gid, mode, fn)) else: if capabilities is None: capabilities = "0x0" cmd = 'set_metadata("%s", "uid", %d, "gid", %d, "mode", 0%o, ' \ '"capabilities", %s' % (fn, uid, gid, mode, capabilities) if selabel is not None: cmd += ', "selabel", "%s"' % ( selabel ) cmd += ');' self.script.append(cmd) def SetPermissionsRecursive(self, fn, uid, gid, dmode, fmode): def SetPermissionsRecursive(self, fn, uid, gid, dmode, fmode, selabel, capabilities): """Recursively set path ownership and permissions.""" if not self.info.get("use_set_metadata", False): self.script.append('set_perm_recursive(%d, %d, 0%o, 0%o, "%s");' % (uid, gid, dmode, fmode, fn)) else: if capabilities is None: capabilities = "0x0" cmd = 'set_metadata_recursive("%s", "uid", %d, "gid", %d, ' \ '"dmode", 0%o, "fmode", 0%o, "capabilities", %s' \ % (fn, uid, gid, dmode, fmode, capabilities) if selabel is not None: cmd += ', "selabel", "%s"' % ( selabel ) cmd += ');' self.script.append(cmd) def MakeSymlinks(self, symlink_list): """Create symlinks, given a list of (dest, link) pairs.""" Loading
tools/releasetools/ota_from_target_files +51 −39 Original line number Diff line number Diff line Loading @@ -117,6 +117,8 @@ class Item: self.uid = None self.gid = None self.mode = None self.selabel = None self.capabilities = None self.dir = dir if name: Loading Loading @@ -147,82 +149,88 @@ class Item: @classmethod def GetMetadata(cls, input_zip): try: # See if the target_files contains a record of what the uid, # gid, and mode is supposed to be. # The target_files contains a record of what the uid, # gid, and mode are supposed to be. output = input_zip.read("META/filesystem_config.txt") except KeyError: # Run the external 'fs_config' program to determine the desired # uid, gid, and mode for every Item object. Note this uses the # one in the client now, which might not be the same as the one # used when this target_files was built. p = common.Run(["fs_config"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) suffix = { False: "", True: "/" } input = "".join(["%s%s\n" % (i.name, suffix[i.dir]) for i in cls.ITEMS.itervalues() if i.name]) output, error = p.communicate(input) assert not error for line in output.split("\n"): if not line: continue name, uid, gid, mode = line.split() columns = line.split() name, uid, gid, mode = columns[:4] selabel = None capabilities = None # After the first 4 columns, there are a series of key=value # pairs. Extract out the fields we care about. for element in columns[4:]: key, value = element.split("=") if key == "selabel": selabel = value if key == "capabilities": capabilities = value i = cls.ITEMS.get(name, None) if i is not None: i.uid = int(uid) i.gid = int(gid) i.mode = int(mode, 8) i.selabel = selabel i.capabilities = capabilities if i.dir: i.children.sort(key=lambda i: i.name) # set metadata for the files generated by this script. i = cls.ITEMS.get("system/recovery-from-boot.p", None) if i: i.uid, i.gid, i.mode = 0, 0, 0644 if i: i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0644, None, None i = cls.ITEMS.get("system/etc/install-recovery.sh", None) if i: i.uid, i.gid, i.mode = 0, 0, 0544 if i: i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0544, None, None def CountChildMetadata(self): """Count up the (uid, gid, mode) tuples for all children and determine the best strategy for using set_perm_recursive and """Count up the (uid, gid, mode, selabel, capabilities) tuples for all children and determine the best strategy for using set_perm_recursive and set_perm to correctly chown/chmod all the files to their desired values. Recursively calls itself for all descendants. Returns a dict of {(uid, gid, dmode, fmode): count} counting up Returns a dict of {(uid, gid, dmode, fmode, selabel, capabilities): count} counting up all descendants of this node. (dmode or fmode may be None.) Also sets the best_subtree of each directory Item to the (uid, gid, dmode, fmode) tuple that will match the most descendants of that Item. dmode, fmode, selabel, capabilities) tuple that will match the most descendants of that Item. """ assert self.dir d = self.descendants = {(self.uid, self.gid, self.mode, None): 1} d = self.descendants = {(self.uid, self.gid, self.mode, None, self.selabel, self.capabilities): 1} for i in self.children: if i.dir: for k, v in i.CountChildMetadata().iteritems(): d[k] = d.get(k, 0) + v else: k = (i.uid, i.gid, None, i.mode) k = (i.uid, i.gid, None, i.mode, i.selabel, i.capabilities) d[k] = d.get(k, 0) + 1 # Find the (uid, gid, dmode, fmode) tuple that matches the most # descendants. # Find the (uid, gid, dmode, fmode, selabel, capabilities) # tuple that matches the most descendants. # First, find the (uid, gid) pair that matches the most # descendants. ug = {} for (uid, gid, _, _), count in d.iteritems(): for (uid, gid, _, _, _, _), count in d.iteritems(): ug[(uid, gid)] = ug.get((uid, gid), 0) + count ug = MostPopularKey(ug, (0, 0)) # Now find the dmode and fmode that match the most descendants # with that (uid, gid), and choose those. # Now find the dmode, fmode, selabel, and capabilities that match # the most descendants with that (uid, gid), and choose those. best_dmode = (0, 0755) best_fmode = (0, 0644) best_selabel = (0, None) best_capabilities = (0, None) for k, count in d.iteritems(): if k[:2] != ug: continue if k[2] is not None and count >= best_dmode[0]: best_dmode = (count, k[2]) if k[3] is not None and count >= best_fmode[0]: best_fmode = (count, k[3]) self.best_subtree = ug + (best_dmode[1], best_fmode[1]) if k[4] is not None and count >= best_selabel[0]: best_selabel = (count, k[4]) if k[5] is not None and count >= best_capabilities[0]: best_capabilities = (count, k[5]) self.best_subtree = ug + (best_dmode[1], best_fmode[1], best_selabel[1], best_capabilities[1]) return d Loading @@ -234,7 +242,7 @@ class Item: self.CountChildMetadata() def recurse(item, current): # current is the (uid, gid, dmode, fmode) tuple that the current # current is the (uid, gid, dmode, fmode, selabel, capabilities) tuple that the current # item (and all its children) have already been set to. We only # need to issue set_perm/set_perm_recursive commands if we're # supposed to be something different. Loading @@ -244,17 +252,21 @@ class Item: current = item.best_subtree if item.uid != current[0] or item.gid != current[1] or \ item.mode != current[2]: script.SetPermissions("/"+item.name, item.uid, item.gid, item.mode) item.mode != current[2] or item.selabel != current[4] or \ item.capabilities != current[5]: script.SetPermissions("/"+item.name, item.uid, item.gid, item.mode, item.selabel, item.capabilities) for i in item.children: recurse(i, current) else: if item.uid != current[0] or item.gid != current[1] or \ item.mode != current[3]: script.SetPermissions("/"+item.name, item.uid, item.gid, item.mode) item.mode != current[3] or item.selabel != current[4] or \ item.capabilities != current[5]: script.SetPermissions("/"+item.name, item.uid, item.gid, item.mode, item.selabel, item.capabilities) recurse(self, (-1, -1, -1, -1)) recurse(self, (-1, -1, -1, -1, None, None)) def CopySystemFiles(input_zip, output_zip=None, Loading Loading @@ -733,7 +745,7 @@ def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip): for item in deferred_patch_list: fn, tf, sf, size, _ = item script.ApplyPatch("/"+fn, "-", tf.size, tf.sha1, sf.sha1, "patch/"+fn+".p") script.SetPermissions("/system/build.prop", 0, 0, 0644) script.SetPermissions("/system/build.prop", 0, 0, 0644, None, None) script.AddToZip(target_zip, output_zip) WriteMetadata(metadata, output_zip) Loading