1c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker# Copyright (C) 2009 The Android Open Source Project
2c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker#
3c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker# Licensed under the Apache License, Version 2.0 (the "License");
4c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker# you may not use this file except in compliance with the License.
5c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker# You may obtain a copy of the License at
6c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker#
7c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker#      http://www.apache.org/licenses/LICENSE-2.0
8c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker#
9c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker# Unless required by applicable law or agreed to in writing, software
10c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker# distributed under the License is distributed on an "AS IS" BASIS,
11c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker# See the License for the specific language governing permissions and
13c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker# limitations under the License.
14c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
15c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongkerimport os
16c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongkerimport re
17c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
18c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongkerimport common
19c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
20c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongkerclass EdifyGenerator(object):
21c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  """Class to generate scripts in the 'edify' recovery script language
22c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  used from donut onwards."""
23c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
24b4c7d32cbac0ef36062c4e2f348b47e027610eefDoug Zongker  def __init__(self, version, info):
25c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    self.script = []
26c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    self.mounts = set()
27c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    self.version = version
28b4c7d32cbac0ef36062c4e2f348b47e027610eefDoug Zongker    self.info = info
29c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
30c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def MakeTemporary(self):
31c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Make a temporary script object whose commands can latter be
32c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    appended to the parent script with AppendScript().  Used when the
33c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    caller wants to generate script commands out-of-order."""
3467369983cf23e12724c135c3850c98326558256bDoug Zongker    x = EdifyGenerator(self.version, self.info)
35c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    x.mounts = self.mounts
36c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    return x
37c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
38c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  @staticmethod
39c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def _WordWrap(cmd, linelen=80):
40c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """'cmd' should be a function call with null characters after each
41c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    parameter (eg, "somefun(foo,\0bar,\0baz)").  This function wraps cmd
42c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    to a given line length, replacing nulls with spaces and/or newlines
43c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    to format it nicely."""
44c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    indent = cmd.index("(")+1
45c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    out = []
46c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    first = True
47c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    x = re.compile("^(.{,%d})\0" % (linelen-indent,))
48c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    while True:
49c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker      if not first:
50c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker        out.append(" " * indent)
51c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker      first = False
52c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker      m = x.search(cmd)
53c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker      if not m:
54c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker        parts = cmd.split("\0", 1)
55c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker        out.append(parts[0]+"\n")
56c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker        if len(parts) == 1:
57c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker          break
58c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker        else:
59c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker          cmd = parts[1]
60c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker          continue
61c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker      out.append(m.group(1)+"\n")
62c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker      cmd = cmd[m.end():]
63c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
64c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    return "".join(out).replace("\0", " ").rstrip("\n")
65c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
66c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def AppendScript(self, other):
67c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Append the contents of another script (which should be created
68c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    with temporary=True) to this one."""
69c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    self.script.extend(other.script)
70c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
71c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def AssertSomeFingerprint(self, *fp):
72c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Assert that the current system build fingerprint is one of *fp."""
73c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    if not fp:
74c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker      raise ValueError("must specify some fingerprints")
750d92f1f13ad89bf8ffbb75764bbe83452612792aDoug Zongker    cmd = (
760d92f1f13ad89bf8ffbb75764bbe83452612792aDoug Zongker           ' ||\n    '.join([('file_getprop("/system/build.prop", '
77c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker                         '"ro.build.fingerprint") == "%s"')
78c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker                        % i for i in fp]) +
790d92f1f13ad89bf8ffbb75764bbe83452612792aDoug Zongker           ' ||\n    abort("Package expects build fingerprint of %s; this '
800d92f1f13ad89bf8ffbb75764bbe83452612792aDoug Zongker           'device has " + getprop("ro.build.fingerprint") + ".");'
810d92f1f13ad89bf8ffbb75764bbe83452612792aDoug Zongker           ) % (" or ".join(fp),)
820d92f1f13ad89bf8ffbb75764bbe83452612792aDoug Zongker    self.script.append(cmd)
83c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
840d92f1f13ad89bf8ffbb75764bbe83452612792aDoug Zongker  def AssertOlderBuild(self, timestamp, timestamp_text):
85c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Assert that the build on the device is older (or the same as)
86c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    the given timestamp."""
870d92f1f13ad89bf8ffbb75764bbe83452612792aDoug Zongker    self.script.append(
880d92f1f13ad89bf8ffbb75764bbe83452612792aDoug Zongker        ('(!less_than_int(%s, getprop("ro.build.date.utc"))) || '
890d92f1f13ad89bf8ffbb75764bbe83452612792aDoug Zongker         'abort("Can\'t install this package (%s) over newer '
900d92f1f13ad89bf8ffbb75764bbe83452612792aDoug Zongker         'build (" + getprop("ro.build.date") + ").");'
910d92f1f13ad89bf8ffbb75764bbe83452612792aDoug Zongker         ) % (timestamp, timestamp_text))
92c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
93c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def AssertDevice(self, device):
94c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Assert that the device identifier is the given string."""
950d92f1f13ad89bf8ffbb75764bbe83452612792aDoug Zongker    cmd = ('getprop("ro.product.device") == "%s" || '
960d92f1f13ad89bf8ffbb75764bbe83452612792aDoug Zongker           'abort("This package is for \\"%s\\" devices; '
970d92f1f13ad89bf8ffbb75764bbe83452612792aDoug Zongker           'this is a \\"" + getprop("ro.product.device") + "\\".");'
980d92f1f13ad89bf8ffbb75764bbe83452612792aDoug Zongker           ) % (device, device)
990d92f1f13ad89bf8ffbb75764bbe83452612792aDoug Zongker    self.script.append(cmd)
100c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
101c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def AssertSomeBootloader(self, *bootloaders):
102c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Asert that the bootloader version is one of *bootloaders."""
103c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    cmd = ("assert(" +
104c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker           " ||\0".join(['getprop("ro.bootloader") == "%s"' % (b,)
105c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker                         for b in bootloaders]) +
106c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker           ");")
107c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    self.script.append(self._WordWrap(cmd))
108c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
109c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def ShowProgress(self, frac, dur):
110c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Update the progress bar, advancing it over 'frac' over the next
111881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker    'dur' seconds.  'dur' may be zero to advance it via SetProgress
112881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker    commands instead of by time."""
113c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    self.script.append("show_progress(%f, %d);" % (frac, int(dur)))
114c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
115881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker  def SetProgress(self, frac):
116881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker    """Set the position of the progress bar within the chunk defined
117881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker    by the most recent ShowProgress call.  'frac' should be in
118881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker    [0,1]."""
119881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker    self.script.append("set_progress(%f);" % (frac,))
120881dd40ffb683fed465df955f3fd21812fae59aaDoug Zongker
121c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def PatchCheck(self, filename, *sha1):
122c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Check that the given file (or MTD reference) has one of the
123c8d446bcde877ec94f8e68dd5af68fe34eb1b1f9Doug Zongker    given *sha1 hashes, checking the version saved in cache if the
124c8d446bcde877ec94f8e68dd5af68fe34eb1b1f9Doug Zongker    file does not match."""
1250d92f1f13ad89bf8ffbb75764bbe83452612792aDoug Zongker    self.script.append(
1260d92f1f13ad89bf8ffbb75764bbe83452612792aDoug Zongker        'apply_patch_check("%s"' % (filename,) +
1270d92f1f13ad89bf8ffbb75764bbe83452612792aDoug Zongker        "".join([', "%s"' % (i,) for i in sha1]) +
1280d92f1f13ad89bf8ffbb75764bbe83452612792aDoug Zongker        ') || abort("\\"%s\\" has unexpected contents.");' % (filename,))
129c8d446bcde877ec94f8e68dd5af68fe34eb1b1f9Doug Zongker
130c8d446bcde877ec94f8e68dd5af68fe34eb1b1f9Doug Zongker  def FileCheck(self, filename, *sha1):
131c8d446bcde877ec94f8e68dd5af68fe34eb1b1f9Doug Zongker    """Check that the given file (or MTD reference) has one of the
132c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    given *sha1 hashes."""
1335a48209541d5eed602bfb8e2c4ff51e31443daf2Doug Zongker    self.script.append('assert(sha1_check(read_file("%s")' % (filename,) +
134c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker                       "".join([', "%s"' % (i,) for i in sha1]) +
135c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker                       '));')
136c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
137c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def CacheFreeSpaceCheck(self, amount):
138c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Check that there's at least 'amount' space that can be made
139c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    available on /cache."""
1400d92f1f13ad89bf8ffbb75764bbe83452612792aDoug Zongker    self.script.append(('apply_patch_space(%d) || abort("Not enough free space '
1410d92f1f13ad89bf8ffbb75764bbe83452612792aDoug Zongker                        'on /system to apply patches.");') % (amount,))
142c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
1439ce0fb6e59415669074896cfa01e1f0cf97979b7Doug Zongker  def Mount(self, mount_point):
1449ce0fb6e59415669074896cfa01e1f0cf97979b7Doug Zongker    """Mount the partition with the given mount_point."""
1459ce0fb6e59415669074896cfa01e1f0cf97979b7Doug Zongker    fstab = self.info.get("fstab", None)
1469ce0fb6e59415669074896cfa01e1f0cf97979b7Doug Zongker    if fstab:
1479ce0fb6e59415669074896cfa01e1f0cf97979b7Doug Zongker      p = fstab[mount_point]
1489ce0fb6e59415669074896cfa01e1f0cf97979b7Doug Zongker      self.script.append('mount("%s", "%s", "%s", "%s");' %
14996a57e737707d05333dced5b657c4ef21c44088aDoug Zongker                         (p.fs_type, common.PARTITION_TYPES[p.fs_type],
1509ce0fb6e59415669074896cfa01e1f0cf97979b7Doug Zongker                          p.device, p.mount_point))
1519ce0fb6e59415669074896cfa01e1f0cf97979b7Doug Zongker      self.mounts.add(p.mount_point)
152c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
153c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def UnpackPackageDir(self, src, dst):
154c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Unpack a given directory from the OTA package into the given
155c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    destination directory."""
156c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    self.script.append('package_extract_dir("%s", "%s");' % (src, dst))
157c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
158c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def Comment(self, comment):
159c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Write a comment into the update script."""
160c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    self.script.append("")
161c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    for i in comment.split("\n"):
162c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker      self.script.append("# " + i)
163c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    self.script.append("")
164c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
165c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def Print(self, message):
166c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Log a message to the screen (if the logs are visible)."""
167c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    self.script.append('ui_print("%s");' % (message,))
168c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
169c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def FormatPartition(self, partition):
1709ce0fb6e59415669074896cfa01e1f0cf97979b7Doug Zongker    """Format the given partition, specified by its mount point (eg,
1719ce0fb6e59415669074896cfa01e1f0cf97979b7Doug Zongker    "/system")."""
1729ce0fb6e59415669074896cfa01e1f0cf97979b7Doug Zongker
173a67616acfd436ac0ba224e675dc972c8491901fcKen Sumrall    reserve_size = 0
1749ce0fb6e59415669074896cfa01e1f0cf97979b7Doug Zongker    fstab = self.info.get("fstab", None)
1759ce0fb6e59415669074896cfa01e1f0cf97979b7Doug Zongker    if fstab:
1769ce0fb6e59415669074896cfa01e1f0cf97979b7Doug Zongker      p = fstab[partition]
177df2056e29e557a493ec8057628ca640b98e54823Doug Zongker      self.script.append('format("%s", "%s", "%s", "%s", "%s");' %
178086cbb0acb873603c19101b1fc01d125d8b63b7aDoug Zongker                         (p.fs_type, common.PARTITION_TYPES[p.fs_type],
179df2056e29e557a493ec8057628ca640b98e54823Doug Zongker                          p.device, p.length, p.mount_point))
180c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
181c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def DeleteFiles(self, file_list):
182c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Delete all files in file_list."""
183c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    if not file_list: return
184c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    cmd = "delete(" + ",\0".join(['"%s"' % (i,) for i in file_list]) + ");"
185c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    self.script.append(self._WordWrap(cmd))
186c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
187c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def ApplyPatch(self, srcfile, tgtfile, tgtsize, tgtsha1, *patchpairs):
188c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Apply binary patches (in *patchpairs) to the given srcfile to
189c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    produce tgtfile (which may be "-" to indicate overwriting the
190c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    source file."""
191c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    if len(patchpairs) % 2 != 0 or len(patchpairs) == 0:
192c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker      raise ValueError("bad patches given to ApplyPatch")
193c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    cmd = ['apply_patch("%s",\0"%s",\0%s,\0%d'
194c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker           % (srcfile, tgtfile, tgtsha1, tgtsize)]
195c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    for i in range(0, len(patchpairs), 2):
196c8d446bcde877ec94f8e68dd5af68fe34eb1b1f9Doug Zongker      cmd.append(',\0%s, package_extract_file("%s")' % patchpairs[i:i+2])
197c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    cmd.append(');')
198c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    cmd = "".join(cmd)
199c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    self.script.append(self._WordWrap(cmd))
200c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
2019ce0fb6e59415669074896cfa01e1f0cf97979b7Doug Zongker  def WriteRawImage(self, mount_point, fn):
2029ce0fb6e59415669074896cfa01e1f0cf97979b7Doug Zongker    """Write the given package file into the partition for the given
2039ce0fb6e59415669074896cfa01e1f0cf97979b7Doug Zongker    mount point."""
204b4c7d32cbac0ef36062c4e2f348b47e027610eefDoug Zongker
2059ce0fb6e59415669074896cfa01e1f0cf97979b7Doug Zongker    fstab = self.info["fstab"]
2069ce0fb6e59415669074896cfa01e1f0cf97979b7Doug Zongker    if fstab:
2079ce0fb6e59415669074896cfa01e1f0cf97979b7Doug Zongker      p = fstab[mount_point]
20896a57e737707d05333dced5b657c4ef21c44088aDoug Zongker      partition_type = common.PARTITION_TYPES[p.fs_type]
2099ce0fb6e59415669074896cfa01e1f0cf97979b7Doug Zongker      args = {'device': p.device, 'fn': fn}
2109ce0fb6e59415669074896cfa01e1f0cf97979b7Doug Zongker      if partition_type == "MTD":
2119ce0fb6e59415669074896cfa01e1f0cf97979b7Doug Zongker        self.script.append(
21202da210a5cb4f9cdc7320885484499856236e5a4Doug Zongker            'write_raw_image(package_extract_file("%(fn)s"), "%(device)s");'
21302da210a5cb4f9cdc7320885484499856236e5a4Doug Zongker            % args)
2149ce0fb6e59415669074896cfa01e1f0cf97979b7Doug Zongker      elif partition_type == "EMMC":
2159ce0fb6e59415669074896cfa01e1f0cf97979b7Doug Zongker        self.script.append(
2169ce0fb6e59415669074896cfa01e1f0cf97979b7Doug Zongker            'package_extract_file("%(fn)s", "%(device)s");' % args)
2179ce0fb6e59415669074896cfa01e1f0cf97979b7Doug Zongker      else:
2189ce0fb6e59415669074896cfa01e1f0cf97979b7Doug Zongker        raise ValueError("don't know how to write \"%s\" partitions" % (p.fs_type,))
219c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
2200eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich  def SetPermissions(self, fn, uid, gid, mode, selabel, capabilities):
221c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Set file ownership and permissions."""
2220eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    if not self.info.get("use_set_metadata", False):
2230eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich      self.script.append('set_perm(%d, %d, 0%o, "%s");' % (uid, gid, mode, fn))
2240eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    else:
2250eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich      if capabilities is None: capabilities = "0x0"
2260eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich      cmd = 'set_metadata("%s", "uid", %d, "gid", %d, "mode", 0%o, ' \
2270eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich          '"capabilities", %s' % (fn, uid, gid, mode, capabilities)
2280eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich      if selabel is not None:
2290eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich        cmd += ', "selabel", "%s"' % ( selabel )
2300eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich      cmd += ');'
2310eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich      self.script.append(cmd)
232c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
2330eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich  def SetPermissionsRecursive(self, fn, uid, gid, dmode, fmode, selabel, capabilities):
234c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Recursively set path ownership and permissions."""
2350eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    if not self.info.get("use_set_metadata", False):
2360eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich      self.script.append('set_perm_recursive(%d, %d, 0%o, 0%o, "%s");'
2370eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich                         % (uid, gid, dmode, fmode, fn))
2380eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich    else:
2390eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich      if capabilities is None: capabilities = "0x0"
2400eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich      cmd = 'set_metadata_recursive("%s", "uid", %d, "gid", %d, ' \
2410eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich          '"dmode", 0%o, "fmode", 0%o, "capabilities", %s' \
2420eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich          % (fn, uid, gid, dmode, fmode, capabilities)
2430eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich      if selabel is not None:
2440eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich        cmd += ', "selabel", "%s"' % ( selabel )
2450eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich      cmd += ');'
2460eb17d944704b3eb140bb9dded299d3be3aed77eNick Kralevich      self.script.append(cmd)
247c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
248c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def MakeSymlinks(self, symlink_list):
249c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Create symlinks, given a list of (dest, link) pairs."""
250c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    by_dest = {}
251c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    for d, l in symlink_list:
252c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker      by_dest.setdefault(d, []).append(l)
253c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
254c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    for dest, links in sorted(by_dest.iteritems()):
255c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker      cmd = ('symlink("%s", ' % (dest,) +
256c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker             ",\0".join(['"' + i + '"' for i in sorted(links)]) + ");")
257c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker      self.script.append(self._WordWrap(cmd))
258c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
259c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def AppendExtra(self, extra):
260c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Append text verbatim to the output script."""
261c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    self.script.append(extra)
262c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
26314833605d26bf970cd5335c02af4354b68d93348Doug Zongker  def UnmountAll(self):
26414833605d26bf970cd5335c02af4354b68d93348Doug Zongker    for p in sorted(self.mounts):
26514833605d26bf970cd5335c02af4354b68d93348Doug Zongker      self.script.append('unmount("%s");' % (p,))
26614833605d26bf970cd5335c02af4354b68d93348Doug Zongker    self.mounts = set()
26714833605d26bf970cd5335c02af4354b68d93348Doug Zongker
268c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker  def AddToZip(self, input_zip, output_zip, input_path=None):
269c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    """Write the accumulated script to the output_zip file.  input_zip
270c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    is used as the source for the 'updater' binary needed to run
271c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    script.  If input_path is not None, it will be used as a local
272c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    path for the binary instead of input_zip."""
273c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
27414833605d26bf970cd5335c02af4354b68d93348Doug Zongker    self.UnmountAll()
275c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
276c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    common.ZipWriteStr(output_zip, "META-INF/com/google/android/updater-script",
277c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker                       "\n".join(self.script) + "\n")
278c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker
279c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    if input_path is None:
280c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker      data = input_zip.read("OTA/bin/updater")
281c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    else:
282c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker      data = open(os.path.join(input_path, "updater")).read()
283c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker    common.ZipWriteStr(output_zip, "META-INF/com/google/android/update-binary",
284c494d7cee85d980647ca915ea64355b71fe817ebDoug Zongker                       data, perms=0755)
285