1 #!/usr/bin/env python 2 # 3 # Copyright (C) 2011 The Android Open Source Project 4 # 5 # Licensed under the Apache License, Version 2.0 (the "License"); 6 # you may not use this file except in compliance with the License. 7 # You may obtain a copy of the License at 8 # 9 # http://www.apache.org/licenses/LICENSE-2.0 10 # 11 # Unless required by applicable law or agreed to in writing, software 12 # distributed under the License is distributed on an "AS IS" BASIS, 13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 # See the License for the specific language governing permissions and 15 # limitations under the License. 16 17 """ 18 Build image output_image_file from input_directory and properties_file. 19 20 Usage: build_image input_directory properties_file output_image_file 21 22 """ 23 import os 24 import os.path 25 import subprocess 26 import sys 27 28 def RunCommand(cmd): 29 """ Echo and run the given command 30 31 Args: 32 cmd: the command represented as a list of strings. 33 Returns: 34 The exit code. 35 """ 36 print "Running: ", " ".join(cmd) 37 p = subprocess.Popen(cmd) 38 p.communicate() 39 return p.returncode 40 41 def BuildImage(in_dir, prop_dict, out_file): 42 """Build an image to out_file from in_dir with property prop_dict. 43 44 Args: 45 in_dir: path of input directory. 46 prop_dict: property dictionary. 47 out_file: path of the output image file. 48 49 Returns: 50 True iff the image is built successfully. 51 """ 52 build_command = [] 53 fs_type = prop_dict.get("fs_type", "") 54 run_fsck = False 55 if fs_type.startswith("ext"): 56 build_command = ["mkuserimg.sh"] 57 if "extfs_sparse_flag" in prop_dict: 58 build_command.append(prop_dict["extfs_sparse_flag"]) 59 run_fsck = True 60 build_command.extend([in_dir, out_file, fs_type, 61 prop_dict["mount_point"]]) 62 if "partition_size" in prop_dict: 63 build_command.append(prop_dict["partition_size"]) 64 if "selinux_fc" in prop_dict: 65 build_command.append(prop_dict["selinux_fc"]) 66 else: 67 build_command = ["mkyaffs2image", "-f"] 68 if prop_dict.get("mkyaffs2_extra_flags", None): 69 build_command.extend(prop_dict["mkyaffs2_extra_flags"].split()) 70 build_command.append(in_dir) 71 build_command.append(out_file) 72 if "selinux_fc" in prop_dict: 73 build_command.append(prop_dict["selinux_fc"]) 74 build_command.append(prop_dict["mount_point"]) 75 76 exit_code = RunCommand(build_command) 77 if exit_code != 0: 78 return False 79 80 if run_fsck and prop_dict.get("skip_fsck") != "true": 81 # Inflate the sparse image 82 unsparse_image = os.path.join( 83 os.path.dirname(out_file), "unsparse_" + os.path.basename(out_file)) 84 inflate_command = ["simg2img", out_file, unsparse_image] 85 exit_code = RunCommand(inflate_command) 86 if exit_code != 0: 87 os.remove(unsparse_image) 88 return False 89 90 # Run e2fsck on the inflated image file 91 e2fsck_command = ["e2fsck", "-f", "-n", unsparse_image] 92 exit_code = RunCommand(e2fsck_command) 93 94 os.remove(unsparse_image) 95 96 return exit_code == 0 97 98 99 def ImagePropFromGlobalDict(glob_dict, mount_point): 100 """Build an image property dictionary from the global dictionary. 101 102 Args: 103 glob_dict: the global dictionary from the build system. 104 mount_point: such as "system", "data" etc. 105 """ 106 d = {} 107 108 def copy_prop(src_p, dest_p): 109 if src_p in glob_dict: 110 d[dest_p] = str(glob_dict[src_p]) 111 112 common_props = ( 113 "extfs_sparse_flag", 114 "mkyaffs2_extra_flags", 115 "selinux_fc", 116 "skip_fsck", 117 ) 118 for p in common_props: 119 copy_prop(p, p) 120 121 d["mount_point"] = mount_point 122 if mount_point == "system": 123 copy_prop("fs_type", "fs_type") 124 copy_prop("system_size", "partition_size") 125 elif mount_point == "data": 126 copy_prop("fs_type", "fs_type") 127 copy_prop("userdata_size", "partition_size") 128 elif mount_point == "cache": 129 copy_prop("cache_fs_type", "fs_type") 130 copy_prop("cache_size", "partition_size") 131 elif mount_point == "vendor": 132 copy_prop("vendor_fs_type", "fs_type") 133 copy_prop("vendor_size", "partition_size") 134 135 return d 136 137 138 def LoadGlobalDict(filename): 139 """Load "name=value" pairs from filename""" 140 d = {} 141 f = open(filename) 142 for line in f: 143 line = line.strip() 144 if not line or line.startswith("#"): 145 continue 146 k, v = line.split("=", 1) 147 d[k] = v 148 f.close() 149 return d 150 151 152 def main(argv): 153 if len(argv) != 3: 154 print __doc__ 155 sys.exit(1) 156 157 in_dir = argv[0] 158 glob_dict_file = argv[1] 159 out_file = argv[2] 160 161 glob_dict = LoadGlobalDict(glob_dict_file) 162 image_filename = os.path.basename(out_file) 163 mount_point = "" 164 if image_filename == "system.img": 165 mount_point = "system" 166 elif image_filename == "userdata.img": 167 mount_point = "data" 168 elif image_filename == "cache.img": 169 mount_point = "cache" 170 elif image_filename == "vendor.img": 171 mount_point = "vendor" 172 else: 173 print >> sys.stderr, "error: unknown image file name ", image_filename 174 exit(1) 175 176 image_properties = ImagePropFromGlobalDict(glob_dict, mount_point) 177 if not BuildImage(in_dir, image_properties, out_file): 178 print >> sys.stderr, "error: failed to build %s from %s" % (out_file, in_dir) 179 exit(1) 180 181 182 if __name__ == '__main__': 183 main(sys.argv[1:]) 184