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 """ 18 Given a target-files zipfile, produces an image zipfile suitable for 19 use with 'fastboot update'. 20 21 Usage: 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 32 import sys 33 34 if sys.hexversion < 0x02040000: 35 print >> sys.stderr, "Python 2.4 or newer is required." 36 sys.exit(1) 37 38 import errno 39 import os 40 import re 41 import shutil 42 import subprocess 43 import tempfile 44 import zipfile 45 46 # missing in Python 2.4 and before 47 if not hasattr(os, "SEEK_SET"): 48 os.SEEK_SET = 0 49 50 import build_image 51 import common 52 53 OPTIONS = common.OPTIONS 54 55 def AddUserdata(output_zip): 56 """Create an empty userdata image and store it in output_zip.""" 57 58 print "creating userdata.img..." 59 60 # The name of the directory it is making an image out of matters to 61 # mkyaffs2image. So we create a temp dir, and within it we create an 62 # empty dir named "data", and build the image from that. 63 temp_dir = tempfile.mkdtemp() 64 user_dir = os.path.join(temp_dir, "data") 65 os.mkdir(user_dir) 66 img = tempfile.NamedTemporaryFile() 67 68 image_props = build_image.ImagePropFromGlobalDict(OPTIONS.info_dict, 69 "data") 70 fstab = OPTIONS.info_dict["fstab"] 71 if fstab: 72 image_props["fs_type" ] = fstab["/data"].fs_type 73 succ = build_image.BuildImage(user_dir, image_props, img.name) 74 assert succ, "build userdata.img image failed" 75 76 common.CheckSize(img.name, "userdata.img", OPTIONS.info_dict) 77 output_zip.write(img.name, "userdata.img") 78 img.close() 79 os.rmdir(user_dir) 80 os.rmdir(temp_dir) 81 82 83 def AddCache(output_zip): 84 """Create an empty cache image and store it in output_zip.""" 85 86 image_props = build_image.ImagePropFromGlobalDict(OPTIONS.info_dict, 87 "cache") 88 # The build system has to explicitly request for cache.img. 89 if "fs_type" not in image_props: 90 return 91 92 print "creating cache.img..." 93 94 # The name of the directory it is making an image out of matters to 95 # mkyaffs2image. So we create a temp dir, and within it we create an 96 # empty dir named "cache", and build the image from that. 97 temp_dir = tempfile.mkdtemp() 98 user_dir = os.path.join(temp_dir, "cache") 99 os.mkdir(user_dir) 100 img = tempfile.NamedTemporaryFile() 101 102 fstab = OPTIONS.info_dict["fstab"] 103 if fstab: 104 image_props["fs_type" ] = fstab["/cache"].fs_type 105 succ = build_image.BuildImage(user_dir, image_props, img.name) 106 assert succ, "build cache.img image failed" 107 108 common.CheckSize(img.name, "cache.img", OPTIONS.info_dict) 109 output_zip.write(img.name, "cache.img") 110 img.close() 111 os.rmdir(user_dir) 112 os.rmdir(temp_dir) 113 114 115 def AddSystem(output_zip): 116 """Turn the contents of SYSTEM into a system image and store it in 117 output_zip.""" 118 119 print "creating system.img..." 120 121 img = tempfile.NamedTemporaryFile() 122 123 # The name of the directory it is making an image out of matters to 124 # mkyaffs2image. It wants "system" but we have a directory named 125 # "SYSTEM", so create a symlink. 126 try: 127 os.symlink(os.path.join(OPTIONS.input_tmp, "SYSTEM"), 128 os.path.join(OPTIONS.input_tmp, "system")) 129 except OSError, e: 130 # bogus error on my mac version? 131 # File "./build/tools/releasetools/img_from_target_files", line 86, in AddSystem 132 # os.path.join(OPTIONS.input_tmp, "system")) 133 # OSError: [Errno 17] File exists 134 if (e.errno == errno.EEXIST): 135 pass 136 137 image_props = build_image.ImagePropFromGlobalDict(OPTIONS.info_dict, 138 "system") 139 fstab = OPTIONS.info_dict["fstab"] 140 if fstab: 141 image_props["fs_type" ] = fstab["/system"].fs_type 142 succ = build_image.BuildImage(os.path.join(OPTIONS.input_tmp, "system"), 143 image_props, img.name) 144 assert succ, "build system.img image failed" 145 146 img.seek(os.SEEK_SET, 0) 147 data = img.read() 148 img.close() 149 150 common.CheckSize(data, "system.img", OPTIONS.info_dict) 151 common.ZipWriteStr(output_zip, "system.img", data) 152 153 154 def CopyInfo(output_zip): 155 """Copy the android-info.txt file from the input to the output.""" 156 output_zip.write(os.path.join(OPTIONS.input_tmp, "OTA", "android-info.txt"), 157 "android-info.txt") 158 159 160 def main(argv): 161 bootable_only = [False] 162 163 def option_handler(o, a): 164 if o in ("-b", "--board_config"): 165 pass # deprecated 166 if o in ("-z", "--bootable_zip"): 167 bootable_only[0] = True 168 else: 169 return False 170 return True 171 172 args = common.ParseOptions(argv, __doc__, 173 extra_opts="b:z", 174 extra_long_opts=["board_config=", 175 "bootable_zip"], 176 extra_option_handler=option_handler) 177 178 bootable_only = bootable_only[0] 179 180 if len(args) != 2: 181 common.Usage(__doc__) 182 sys.exit(1) 183 184 OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0]) 185 OPTIONS.info_dict = common.LoadInfoDict(input_zip) 186 187 output_zip = zipfile.ZipFile(args[1], "w", compression=zipfile.ZIP_DEFLATED) 188 189 common.GetBootableImage( 190 "boot.img", "boot.img", OPTIONS.input_tmp, "BOOT").AddToZip(output_zip) 191 common.GetBootableImage( 192 "recovery.img", "recovery.img", OPTIONS.input_tmp, 193 "RECOVERY").AddToZip(output_zip) 194 195 if not bootable_only: 196 AddSystem(output_zip) 197 AddUserdata(output_zip) 198 AddCache(output_zip) 199 CopyInfo(output_zip) 200 201 print "cleaning up..." 202 output_zip.close() 203 shutil.rmtree(OPTIONS.input_tmp) 204 205 print "done." 206 207 208 if __name__ == '__main__': 209 try: 210 common.CloseInheritedPipes() 211 main(sys.argv[1:]) 212 except common.ExternalError, e: 213 print 214 print " ERROR: %s" % (e,) 215 print 216 sys.exit(1) 217