Home | History | Annotate | Download | only in releasetools
      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 common
     51 
     52 OPTIONS = common.OPTIONS
     53 
     54 def AddUserdata(output_zip):
     55   """Create an empty userdata image and store it in output_zip."""
     56 
     57   print "creating userdata.img..."
     58 
     59   # The name of the directory it is making an image out of matters to
     60   # mkyaffs2image.  So we create a temp dir, and within it we create an
     61   # empty dir named "data", and build the image from that.
     62   temp_dir = tempfile.mkdtemp()
     63   user_dir = os.path.join(temp_dir, "data")
     64   os.mkdir(user_dir)
     65   img = tempfile.NamedTemporaryFile()
     66 
     67   build_command = []
     68   fstab = OPTIONS.info_dict["fstab"]
     69   if fstab and fstab["/data"].fs_type.startswith("ext"):
     70     build_command = ["mkuserimg.sh"]
     71     if "extfs_sparse_flag" in OPTIONS.info_dict:
     72       build_command.append(OPTIONS.info_dict["extfs_sparse_flag"])
     73     build_command.extend([user_dir, img.name,
     74                      fstab["/data"].fs_type, "data"])
     75     if "userdata_size" in OPTIONS.info_dict:
     76       build_command.append(str(OPTIONS.info_dict["userdata_size"]))
     77   else:
     78     build_command = ["mkyaffs2image", "-f"]
     79     extra = OPTIONS.info_dict.get("mkyaffs2_extra_flags", None)
     80     if extra:
     81       build_command.extend(extra.split())
     82     build_command.append(user_dir)
     83     build_command.append(img.name)
     84 
     85   p = common.Run(build_command);
     86   p.communicate()
     87   assert p.returncode == 0, "build userdata.img image failed"
     88 
     89   common.CheckSize(img.name, "userdata.img", OPTIONS.info_dict)
     90   output_zip.write(img.name, "userdata.img")
     91   img.close()
     92   os.rmdir(user_dir)
     93   os.rmdir(temp_dir)
     94 
     95 
     96 def AddSystem(output_zip):
     97   """Turn the contents of SYSTEM into a system image and store it in
     98   output_zip."""
     99 
    100   print "creating system.img..."
    101 
    102   img = tempfile.NamedTemporaryFile()
    103 
    104   # The name of the directory it is making an image out of matters to
    105   # mkyaffs2image.  It wants "system" but we have a directory named
    106   # "SYSTEM", so create a symlink.
    107   try:
    108     os.symlink(os.path.join(OPTIONS.input_tmp, "SYSTEM"),
    109                os.path.join(OPTIONS.input_tmp, "system"))
    110   except OSError, e:
    111       # bogus error on my mac version?
    112       #   File "./build/tools/releasetools/img_from_target_files", line 86, in AddSystem
    113       #     os.path.join(OPTIONS.input_tmp, "system"))
    114       # OSError: [Errno 17] File exists
    115     if (e.errno == errno.EEXIST):
    116       pass
    117 
    118   build_command = []
    119   fstab = OPTIONS.info_dict["fstab"]
    120   if fstab and fstab["/system"].fs_type.startswith("ext"):
    121 
    122     build_command = ["mkuserimg.sh"]
    123     if "extfs_sparse_flag" in OPTIONS.info_dict:
    124       build_command.append(OPTIONS.info_dict["extfs_sparse_flag"])
    125     build_command.extend([os.path.join(OPTIONS.input_tmp, "system"), img.name,
    126                      fstab["/system"].fs_type, "system"])
    127     if "system_size" in OPTIONS.info_dict:
    128       build_command.append(str(OPTIONS.info_dict["system_size"]))
    129   else:
    130     build_command = ["mkyaffs2image", "-f"]
    131     extra = OPTIONS.info_dict.get("mkyaffs2_extra_flags", None)
    132     if extra:
    133       build_command.extend(extra.split())
    134     build_command.append(os.path.join(OPTIONS.input_tmp, "system"))
    135     build_command.append(img.name)
    136 
    137   p = common.Run(build_command)
    138   p.communicate()
    139   assert p.returncode == 0, "build system.img image failed"
    140 
    141   img.seek(os.SEEK_SET, 0)
    142   data = img.read()
    143   img.close()
    144 
    145   common.CheckSize(data, "system.img", OPTIONS.info_dict)
    146   common.ZipWriteStr(output_zip, "system.img", data)
    147 
    148 
    149 def CopyInfo(output_zip):
    150   """Copy the android-info.txt file from the input to the output."""
    151   output_zip.write(os.path.join(OPTIONS.input_tmp, "OTA", "android-info.txt"),
    152                    "android-info.txt")
    153 
    154 
    155 def main(argv):
    156   bootable_only = [False]
    157 
    158   def option_handler(o, a):
    159     if o in ("-b", "--board_config"):
    160       pass       # deprecated
    161     if o in ("-z", "--bootable_zip"):
    162       bootable_only[0] = True
    163     else:
    164       return False
    165     return True
    166 
    167   args = common.ParseOptions(argv, __doc__,
    168                              extra_opts="b:z",
    169                              extra_long_opts=["board_config=",
    170                                               "bootable_zip"],
    171                              extra_option_handler=option_handler)
    172 
    173   bootable_only = bootable_only[0]
    174 
    175   if len(args) != 2:
    176     common.Usage(__doc__)
    177     sys.exit(1)
    178 
    179   OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0])
    180   OPTIONS.info_dict = common.LoadInfoDict(input_zip)
    181 
    182   output_zip = zipfile.ZipFile(args[1], "w", compression=zipfile.ZIP_DEFLATED)
    183 
    184   common.GetBootableImage(
    185       "boot.img", "boot.img", OPTIONS.input_tmp, "BOOT").AddToZip(output_zip)
    186   common.GetBootableImage(
    187       "recovery.img", "recovery.img", OPTIONS.input_tmp,
    188       "RECOVERY").AddToZip(output_zip)
    189 
    190   if not bootable_only:
    191     AddSystem(output_zip)
    192     AddUserdata(output_zip)
    193     CopyInfo(output_zip)
    194 
    195   print "cleaning up..."
    196   output_zip.close()
    197   shutil.rmtree(OPTIONS.input_tmp)
    198 
    199   print "done."
    200 
    201 
    202 if __name__ == '__main__':
    203   try:
    204     common.CloseInheritedPipes()
    205     main(sys.argv[1:])
    206   except common.ExternalError, e:
    207     print
    208     print "   ERROR: %s" % (e,)
    209     print
    210     sys.exit(1)
    211