img_from_target_files.py revision c8b4e849f10f3a382694b00453b3f49608c83b48
1#!/usr/bin/env python 2# 3# Copyright (C) 2008 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""" 18Given a target-files zipfile, produces an image zipfile suitable for 19use with 'fastboot update'. 20 21Usage: img_from_target_files [flags] input_target_files output_image_zip 22 23 -b (--board_config) <file> 24 Deprecated. 25 26 -z (--bootable_zip) 27 Include only the bootable images (eg 'boot' and 'recovery') in 28 the output. 29 30""" 31 32import sys 33 34if sys.hexversion < 0x02070000: 35 print >> sys.stderr, "Python 2.7 or newer is required." 36 sys.exit(1) 37 38import errno 39import os 40import re 41import shutil 42import subprocess 43import tempfile 44import zipfile 45 46# missing in Python 2.4 and before 47if not hasattr(os, "SEEK_SET"): 48 os.SEEK_SET = 0 49 50import build_image 51import common 52 53OPTIONS = common.OPTIONS 54 55 56def AddSystem(output_zip, sparse=True): 57 """Turn the contents of SYSTEM into a system image and store it in 58 output_zip.""" 59 data = BuildSystem(OPTIONS.input_tmp, OPTIONS.info_dict, sparse=sparse) 60 common.ZipWriteStr(output_zip, "system.img", data) 61 62def BuildSystem(input_dir, info_dict, sparse=True, map_file=None): 63 return CreateImage(input_dir, info_dict, "system", 64 sparse=sparse, map_file=map_file) 65 66def AddVendor(output_zip, sparse=True): 67 data = BuildVendor(OPTIONS.input_tmp, OPTIONS.info_dict, sparse=sparse) 68 common.ZipWriteStr(output_zip, "vendor.img", data) 69 70def BuildVendor(input_dir, info_dict, sparse=True, map_file=None): 71 return CreateImage(input_dir, info_dict, "vendor", 72 sparse=sparse, map_file=map_file) 73 74 75def CreateImage(input_dir, info_dict, what, sparse=True, map_file=None): 76 print "creating " + what + ".img..." 77 78 img = tempfile.NamedTemporaryFile() 79 80 # The name of the directory it is making an image out of matters to 81 # mkyaffs2image. It wants "system" but we have a directory named 82 # "SYSTEM", so create a symlink. 83 try: 84 os.symlink(os.path.join(input_dir, what.upper()), 85 os.path.join(input_dir, what)) 86 except OSError, e: 87 # bogus error on my mac version? 88 # File "./build/tools/releasetools/img_from_target_files", line 86, in AddSystem 89 # os.path.join(OPTIONS.input_tmp, "system")) 90 # OSError: [Errno 17] File exists 91 if (e.errno == errno.EEXIST): 92 pass 93 94 image_props = build_image.ImagePropFromGlobalDict(info_dict, what) 95 fstab = info_dict["fstab"] 96 if fstab: 97 image_props["fs_type" ] = fstab["/" + what].fs_type 98 99 if what == "system": 100 fs_config_prefix = "" 101 else: 102 fs_config_prefix = what + "_" 103 104 fs_config = os.path.join( 105 input_dir, "META/" + fs_config_prefix + "filesystem_config.txt") 106 if not os.path.exists(fs_config): fs_config = None 107 108 fc_config = os.path.join(input_dir, "BOOT/RAMDISK/file_contexts") 109 if not os.path.exists(fc_config): fc_config = None 110 111 succ = build_image.BuildImage(os.path.join(input_dir, what), 112 image_props, img.name, 113 fs_config=fs_config, 114 fc_config=fc_config) 115 assert succ, "build " + what + ".img image failed" 116 117 mapdata = None 118 119 if sparse: 120 data = open(img.name).read() 121 img.close() 122 else: 123 success, name = build_image.UnsparseImage(img.name, replace=False) 124 if not success: 125 assert False, "unsparsing " + what + ".img failed" 126 127 if map_file: 128 mmap = tempfile.NamedTemporaryFile() 129 mimg = tempfile.NamedTemporaryFile(delete=False) 130 success = build_image.MappedUnsparseImage( 131 img.name, name, mmap.name, mimg.name) 132 if not success: 133 assert False, "creating sparse map failed" 134 os.unlink(name) 135 name = mimg.name 136 137 with open(mmap.name) as f: 138 mapdata = f.read() 139 140 try: 141 with open(name) as f: 142 data = f.read() 143 finally: 144 os.unlink(name) 145 146 if mapdata is None: 147 return data 148 else: 149 return mapdata, data 150 151 152def AddUserdata(output_zip): 153 """Create an empty userdata image and store it in output_zip.""" 154 155 image_props = build_image.ImagePropFromGlobalDict(OPTIONS.info_dict, 156 "data") 157 # If no userdata_size is provided for extfs, skip userdata.img. 158 if (image_props.get("fs_type", "").startswith("ext") and 159 not image_props.get("partition_size")): 160 return 161 162 print "creating userdata.img..." 163 164 # The name of the directory it is making an image out of matters to 165 # mkyaffs2image. So we create a temp dir, and within it we create an 166 # empty dir named "data", and build the image from that. 167 temp_dir = tempfile.mkdtemp() 168 user_dir = os.path.join(temp_dir, "data") 169 os.mkdir(user_dir) 170 img = tempfile.NamedTemporaryFile() 171 172 fstab = OPTIONS.info_dict["fstab"] 173 if fstab: 174 image_props["fs_type" ] = fstab["/data"].fs_type 175 succ = build_image.BuildImage(user_dir, image_props, img.name) 176 assert succ, "build userdata.img image failed" 177 178 common.CheckSize(img.name, "userdata.img", OPTIONS.info_dict) 179 output_zip.write(img.name, "userdata.img") 180 img.close() 181 os.rmdir(user_dir) 182 os.rmdir(temp_dir) 183 184 185def AddCache(output_zip): 186 """Create an empty cache image and store it in output_zip.""" 187 188 image_props = build_image.ImagePropFromGlobalDict(OPTIONS.info_dict, 189 "cache") 190 # The build system has to explicitly request for cache.img. 191 if "fs_type" not in image_props: 192 return 193 194 print "creating cache.img..." 195 196 # The name of the directory it is making an image out of matters to 197 # mkyaffs2image. So we create a temp dir, and within it we create an 198 # empty dir named "cache", and build the image from that. 199 temp_dir = tempfile.mkdtemp() 200 user_dir = os.path.join(temp_dir, "cache") 201 os.mkdir(user_dir) 202 img = tempfile.NamedTemporaryFile() 203 204 fstab = OPTIONS.info_dict["fstab"] 205 if fstab: 206 image_props["fs_type" ] = fstab["/cache"].fs_type 207 succ = build_image.BuildImage(user_dir, image_props, img.name) 208 assert succ, "build cache.img image failed" 209 210 common.CheckSize(img.name, "cache.img", OPTIONS.info_dict) 211 output_zip.write(img.name, "cache.img") 212 img.close() 213 os.rmdir(user_dir) 214 os.rmdir(temp_dir) 215 216 217def CopyInfo(output_zip): 218 """Copy the android-info.txt file from the input to the output.""" 219 output_zip.write(os.path.join(OPTIONS.input_tmp, "OTA", "android-info.txt"), 220 "android-info.txt") 221 222 223def main(argv): 224 bootable_only = [False] 225 226 def option_handler(o, a): 227 if o in ("-b", "--board_config"): 228 pass # deprecated 229 if o in ("-z", "--bootable_zip"): 230 bootable_only[0] = True 231 else: 232 return False 233 return True 234 235 args = common.ParseOptions(argv, __doc__, 236 extra_opts="b:z", 237 extra_long_opts=["board_config=", 238 "bootable_zip"], 239 extra_option_handler=option_handler) 240 241 bootable_only = bootable_only[0] 242 243 if len(args) != 2: 244 common.Usage(__doc__) 245 sys.exit(1) 246 247 OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0]) 248 OPTIONS.info_dict = common.LoadInfoDict(input_zip) 249 250 # If this image was originally labelled with SELinux contexts, make sure we 251 # also apply the labels in our new image. During building, the "file_contexts" 252 # is in the out/ directory tree, but for repacking from target-files.zip it's 253 # in the root directory of the ramdisk. 254 if "selinux_fc" in OPTIONS.info_dict: 255 OPTIONS.info_dict["selinux_fc"] = os.path.join(OPTIONS.input_tmp, "BOOT", "RAMDISK", 256 "file_contexts") 257 258 output_zip = zipfile.ZipFile(args[1], "w", compression=zipfile.ZIP_DEFLATED) 259 260 boot_image = common.GetBootableImage( 261 "boot.img", "boot.img", OPTIONS.input_tmp, "BOOT") 262 if boot_image: 263 boot_image.AddToZip(output_zip) 264 recovery_image = common.GetBootableImage( 265 "recovery.img", "recovery.img", OPTIONS.input_tmp, "RECOVERY") 266 if recovery_image: 267 recovery_image.AddToZip(output_zip) 268 269 def banner(s): 270 print "\n\n++++ " + s + " ++++\n\n" 271 272 if not bootable_only: 273 banner("AddSystem") 274 AddSystem(output_zip) 275 try: 276 input_zip.getinfo("VENDOR/") 277 banner("AddVendor") 278 AddVendor(output_zip) 279 except KeyError: 280 pass # no vendor partition for this device 281 banner("AddUserdata") 282 AddUserdata(output_zip) 283 banner("AddCache") 284 AddCache(output_zip) 285 CopyInfo(output_zip) 286 287 print "cleaning up..." 288 output_zip.close() 289 shutil.rmtree(OPTIONS.input_tmp) 290 291 print "done." 292 293 294if __name__ == '__main__': 295 try: 296 common.CloseInheritedPipes() 297 main(sys.argv[1:]) 298 except common.ExternalError, e: 299 print 300 print " ERROR: %s" % (e,) 301 print 302 sys.exit(1) 303