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