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 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