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