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