blob: bbb157da873e68eb8ab839a6e9bbd51a8f5d759a [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glass1f1864b2016-07-25 18:59:08 -06002#
3# Copyright (c) 2016 Google, Inc
4#
Simon Glass1f1864b2016-07-25 18:59:08 -06005
Simon Glass0a98b282018-09-14 04:57:28 -06006import glob
Simon Glass1f1864b2016-07-25 18:59:08 -06007import os
8import shutil
Simon Glasseb0f4a42019-07-20 12:24:06 -06009import struct
Simon Glasse6d85ff2019-05-14 15:53:47 -060010import sys
Simon Glass1f1864b2016-07-25 18:59:08 -060011import tempfile
12
Simon Glassbf776672020-04-17 18:09:04 -060013from patman import command
14from patman import tout
Simon Glass1f1864b2016-07-25 18:59:08 -060015
Simon Glassaeffc5e2018-07-17 13:25:43 -060016# Output directly (generally this is temporary)
Simon Glass1f1864b2016-07-25 18:59:08 -060017outdir = None
Simon Glassaeffc5e2018-07-17 13:25:43 -060018
19# True to keep the output directory around after exiting
Simon Glass1f1864b2016-07-25 18:59:08 -060020preserve_outdir = False
21
Simon Glassaeffc5e2018-07-17 13:25:43 -060022# Path to the Chrome OS chroot, if we know it
23chroot_path = None
24
25# Search paths to use for Filename(), used to find files
26search_paths = []
27
Simon Glassc22b8cf2019-07-08 13:18:27 -060028tool_search_paths = []
29
Simon Glass04187a82018-09-14 04:57:25 -060030# Tools and the packages that contain them, on debian
31packages = {
32 'lz4': 'liblz4-tool',
33 }
Simon Glassaeffc5e2018-07-17 13:25:43 -060034
Simon Glass1fda1822018-10-01 21:12:44 -060035# List of paths to use when looking for an input file
36indir = []
37
Simon Glass1f1864b2016-07-25 18:59:08 -060038def PrepareOutputDir(dirname, preserve=False):
39 """Select an output directory, ensuring it exists.
40
41 This either creates a temporary directory or checks that the one supplied
42 by the user is valid. For a temporary directory, it makes a note to
43 remove it later if required.
44
45 Args:
46 dirname: a string, name of the output directory to use to store
47 intermediate and output files. If is None - create a temporary
48 directory.
49 preserve: a Boolean. If outdir above is None and preserve is False, the
50 created temporary directory will be destroyed on exit.
51
52 Raises:
53 OSError: If it cannot create the output directory.
54 """
55 global outdir, preserve_outdir
56
57 preserve_outdir = dirname or preserve
58 if dirname:
59 outdir = dirname
60 if not os.path.isdir(outdir):
61 try:
62 os.makedirs(outdir)
63 except OSError as err:
64 raise CmdError("Cannot make output directory '%s': '%s'" %
65 (outdir, err.strerror))
66 tout.Debug("Using output directory '%s'" % outdir)
67 else:
68 outdir = tempfile.mkdtemp(prefix='binman.')
69 tout.Debug("Using temporary directory '%s'" % outdir)
70
71def _RemoveOutputDir():
72 global outdir
73
74 shutil.rmtree(outdir)
75 tout.Debug("Deleted temporary directory '%s'" % outdir)
76 outdir = None
77
78def FinaliseOutputDir():
79 global outdir, preserve_outdir
80
81 """Tidy up: delete output directory if temporary and not preserved."""
82 if outdir and not preserve_outdir:
83 _RemoveOutputDir()
Simon Glass31353302019-07-20 12:24:07 -060084 outdir = None
Simon Glass1f1864b2016-07-25 18:59:08 -060085
86def GetOutputFilename(fname):
87 """Return a filename within the output directory.
88
89 Args:
90 fname: Filename to use for new file
91
92 Returns:
93 The full path of the filename, within the output directory
94 """
95 return os.path.join(outdir, fname)
96
97def _FinaliseForTest():
98 """Remove the output directory (for use by tests)"""
99 global outdir
100
101 if outdir:
102 _RemoveOutputDir()
Simon Glass31353302019-07-20 12:24:07 -0600103 outdir = None
Simon Glass1f1864b2016-07-25 18:59:08 -0600104
105def SetInputDirs(dirname):
106 """Add a list of input directories, where input files are kept.
107
108 Args:
109 dirname: a list of paths to input directories to use for obtaining
110 files needed by binman to place in the image.
111 """
112 global indir
113
114 indir = dirname
115 tout.Debug("Using input directories %s" % indir)
116
Simon Glass4f9f1052020-07-09 18:39:38 -0600117def GetInputFilename(fname, allow_missing=False):
Simon Glass1f1864b2016-07-25 18:59:08 -0600118 """Return a filename for use as input.
119
120 Args:
121 fname: Filename to use for new file
Simon Glass4f9f1052020-07-09 18:39:38 -0600122 allow_missing: True if the filename can be missing
Simon Glass1f1864b2016-07-25 18:59:08 -0600123
124 Returns:
Simon Glass4f9f1052020-07-09 18:39:38 -0600125 The full path of the filename, within the input directory, or
126 None on error
Simon Glass1f1864b2016-07-25 18:59:08 -0600127 """
Simon Glassf514d8f2019-08-24 07:22:54 -0600128 if not indir or fname[:1] == '/':
Simon Glass1f1864b2016-07-25 18:59:08 -0600129 return fname
130 for dirname in indir:
131 pathname = os.path.join(dirname, fname)
132 if os.path.exists(pathname):
133 return pathname
134
Simon Glass4f9f1052020-07-09 18:39:38 -0600135 if allow_missing:
136 return None
Simon Glass4f5dea42018-07-17 13:25:45 -0600137 raise ValueError("Filename '%s' not found in input path (%s) (cwd='%s')" %
138 (fname, ','.join(indir), os.getcwd()))
Simon Glass1f1864b2016-07-25 18:59:08 -0600139
Simon Glass0a98b282018-09-14 04:57:28 -0600140def GetInputFilenameGlob(pattern):
141 """Return a list of filenames for use as input.
142
143 Args:
144 pattern: Filename pattern to search for
145
146 Returns:
147 A list of matching files in all input directories
148 """
149 if not indir:
150 return glob.glob(fname)
151 files = []
152 for dirname in indir:
153 pathname = os.path.join(dirname, pattern)
154 files += glob.glob(pathname)
155 return sorted(files)
156
Simon Glass1f1864b2016-07-25 18:59:08 -0600157def Align(pos, align):
158 if align:
159 mask = align - 1
160 pos = (pos + mask) & ~mask
161 return pos
162
163def NotPowerOfTwo(num):
164 return num and (num & (num - 1))
Simon Glassaeffc5e2018-07-17 13:25:43 -0600165
Simon Glassc22b8cf2019-07-08 13:18:27 -0600166def SetToolPaths(toolpaths):
167 """Set the path to search for tools
168
169 Args:
170 toolpaths: List of paths to search for tools executed by Run()
171 """
172 global tool_search_paths
173
174 tool_search_paths = toolpaths
175
176def PathHasFile(path_spec, fname):
Simon Glass04187a82018-09-14 04:57:25 -0600177 """Check if a given filename is in the PATH
178
179 Args:
Simon Glassc22b8cf2019-07-08 13:18:27 -0600180 path_spec: Value of PATH variable to check
Simon Glass04187a82018-09-14 04:57:25 -0600181 fname: Filename to check
182
183 Returns:
184 True if found, False if not
185 """
Simon Glassc22b8cf2019-07-08 13:18:27 -0600186 for dir in path_spec.split(':'):
Simon Glass04187a82018-09-14 04:57:25 -0600187 if os.path.exists(os.path.join(dir, fname)):
188 return True
189 return False
190
Alper Nebi Yasak29cc0912020-09-06 14:46:06 +0300191def GetHostCompileTool(name):
192 """Get the host-specific version for a compile tool
193
194 This checks the environment variables that specify which version of
195 the tool should be used (e.g. ${HOSTCC}).
196
197 The following table lists the host-specific versions of the tools
198 this function resolves to:
199
200 Compile Tool | Host version
201 --------------+----------------
202 as | ${HOSTAS}
203 ld | ${HOSTLD}
204 cc | ${HOSTCC}
205 cpp | ${HOSTCPP}
206 c++ | ${HOSTCXX}
207 ar | ${HOSTAR}
208 nm | ${HOSTNM}
209 ldr | ${HOSTLDR}
210 strip | ${HOSTSTRIP}
211 objcopy | ${HOSTOBJCOPY}
212 objdump | ${HOSTOBJDUMP}
213 dtc | ${HOSTDTC}
214
215 Args:
216 name: Command name to run
217
218 Returns:
219 host_name: Exact command name to run instead
220 extra_args: List of extra arguments to pass
221 """
222 host_name = None
223 extra_args = []
224 if name in ('as', 'ld', 'cc', 'cpp', 'ar', 'nm', 'ldr', 'strip',
225 'objcopy', 'objdump', 'dtc'):
226 host_name, *host_args = env.get('HOST' + name.upper(), '').split(' ')
227 elif name == 'c++':
228 host_name, *host_args = env.get('HOSTCXX', '').split(' ')
229
230 if host_name:
231 return host_name, extra_args
232 return name, []
233
Alper Nebi Yasak1e4687a2020-09-06 14:46:05 +0300234def GetTargetCompileTool(name, cross_compile=None):
235 """Get the target-specific version for a compile tool
236
237 This first checks the environment variables that specify which
238 version of the tool should be used (e.g. ${CC}). If those aren't
239 specified, it checks the CROSS_COMPILE variable as a prefix for the
240 tool with some substitutions (e.g. "${CROSS_COMPILE}gcc" for cc).
241
242 The following table lists the target-specific versions of the tools
243 this function resolves to:
244
245 Compile Tool | First choice | Second choice
246 --------------+----------------+----------------------------
247 as | ${AS} | ${CROSS_COMPILE}as
248 ld | ${LD} | ${CROSS_COMPILE}ld.bfd
249 | | or ${CROSS_COMPILE}ld
250 cc | ${CC} | ${CROSS_COMPILE}gcc
251 cpp | ${CPP} | ${CROSS_COMPILE}gcc -E
252 c++ | ${CXX} | ${CROSS_COMPILE}g++
253 ar | ${AR} | ${CROSS_COMPILE}ar
254 nm | ${NM} | ${CROSS_COMPILE}nm
255 ldr | ${LDR} | ${CROSS_COMPILE}ldr
256 strip | ${STRIP} | ${CROSS_COMPILE}strip
257 objcopy | ${OBJCOPY} | ${CROSS_COMPILE}objcopy
258 objdump | ${OBJDUMP} | ${CROSS_COMPILE}objdump
259 dtc | ${DTC} | (no CROSS_COMPILE version)
260
261 Args:
262 name: Command name to run
263
264 Returns:
265 target_name: Exact command name to run instead
266 extra_args: List of extra arguments to pass
267 """
268 env = dict(os.environ)
269
270 target_name = None
271 extra_args = []
272 if name in ('as', 'ld', 'cc', 'cpp', 'ar', 'nm', 'ldr', 'strip',
273 'objcopy', 'objdump', 'dtc'):
274 target_name, *extra_args = env.get(name.upper(), '').split(' ')
275 elif name == 'c++':
276 target_name, *extra_args = env.get('CXX', '').split(' ')
277
278 if target_name:
279 return target_name, extra_args
280
281 if cross_compile is None:
282 cross_compile = env.get('CROSS_COMPILE', '')
283 if not cross_compile:
284 return name, []
285
286 if name in ('as', 'ar', 'nm', 'ldr', 'strip', 'objcopy', 'objdump'):
287 target_name = cross_compile + name
288 elif name == 'ld':
289 try:
290 if Run(cross_compile + 'ld.bfd', '-v'):
291 target_name = cross_compile + 'ld.bfd'
292 except:
293 target_name = cross_compile + 'ld'
294 elif name == 'cc':
295 target_name = cross_compile + 'gcc'
296 elif name == 'cpp':
297 target_name = cross_compile + 'gcc'
298 extra_args = ['-E']
299 elif name == 'c++':
300 target_name = cross_compile + 'g++'
301 else:
302 target_name = name
303 return target_name, extra_args
304
Simon Glass3b3e3c02019-10-31 07:42:50 -0600305def Run(name, *args, **kwargs):
Simon Glassc22b8cf2019-07-08 13:18:27 -0600306 """Run a tool with some arguments
307
308 This runs a 'tool', which is a program used by binman to process files and
309 perhaps produce some output. Tools can be located on the PATH or in a
310 search path.
311
312 Args:
313 name: Command name to run
314 args: Arguments to the tool
Alper Nebi Yasak29cc0912020-09-06 14:46:06 +0300315 for_host: True to resolve the command to the version for the host
Alper Nebi Yasak1e4687a2020-09-06 14:46:05 +0300316 for_target: False to run the command as-is, without resolving it
317 to the version for the compile target
Simon Glassc22b8cf2019-07-08 13:18:27 -0600318
319 Returns:
320 CommandResult object
321 """
Simon Glass04187a82018-09-14 04:57:25 -0600322 try:
Simon Glass3b3e3c02019-10-31 07:42:50 -0600323 binary = kwargs.get('binary')
Alper Nebi Yasak29cc0912020-09-06 14:46:06 +0300324 for_host = kwargs.get('for_host', False)
325 for_target = kwargs.get('for_target', not for_host)
Simon Glassc22b8cf2019-07-08 13:18:27 -0600326 env = None
327 if tool_search_paths:
328 env = dict(os.environ)
329 env['PATH'] = ':'.join(tool_search_paths) + ':' + env['PATH']
Alper Nebi Yasak1e4687a2020-09-06 14:46:05 +0300330 if for_target:
331 name, extra_args = GetTargetCompileTool(name)
332 args = tuple(extra_args) + args
Alper Nebi Yasak29cc0912020-09-06 14:46:06 +0300333 elif for_host:
334 name, extra_args = GetHostCompileTool(name)
335 args = tuple(extra_args) + args
Simon Glass6eace392019-08-24 07:22:42 -0600336 all_args = (name,) + args
337 result = command.RunPipe([all_args], capture=True, capture_stderr=True,
Simon Glass3b3e3c02019-10-31 07:42:50 -0600338 env=env, raise_on_error=False, binary=binary)
Simon Glass6eace392019-08-24 07:22:42 -0600339 if result.return_code:
340 raise Exception("Error %d running '%s': %s" %
341 (result.return_code,' '.join(all_args),
342 result.stderr))
343 return result.stdout
Simon Glass04187a82018-09-14 04:57:25 -0600344 except:
Simon Glassc22b8cf2019-07-08 13:18:27 -0600345 if env and not PathHasFile(env['PATH'], name):
346 msg = "Please install tool '%s'" % name
Simon Glass04187a82018-09-14 04:57:25 -0600347 package = packages.get(name)
348 if package:
349 msg += " (e.g. from package '%s')" % package
350 raise ValueError(msg)
351 raise
Simon Glassaeffc5e2018-07-17 13:25:43 -0600352
353def Filename(fname):
354 """Resolve a file path to an absolute path.
355
356 If fname starts with ##/ and chroot is available, ##/ gets replaced with
357 the chroot path. If chroot is not available, this file name can not be
358 resolved, `None' is returned.
359
360 If fname is not prepended with the above prefix, and is not an existing
361 file, the actual file name is retrieved from the passed in string and the
362 search_paths directories (if any) are searched to for the file. If found -
363 the path to the found file is returned, `None' is returned otherwise.
364
365 Args:
366 fname: a string, the path to resolve.
367
368 Returns:
369 Absolute path to the file or None if not found.
370 """
371 if fname.startswith('##/'):
372 if chroot_path:
373 fname = os.path.join(chroot_path, fname[3:])
374 else:
375 return None
376
377 # Search for a pathname that exists, and return it if found
378 if fname and not os.path.exists(fname):
379 for path in search_paths:
380 pathname = os.path.join(path, os.path.basename(fname))
381 if os.path.exists(pathname):
382 return pathname
383
384 # If not found, just return the standard, unchanged path
385 return fname
386
Simon Glass3c47e412019-05-17 22:00:44 -0600387def ReadFile(fname, binary=True):
Simon Glassaeffc5e2018-07-17 13:25:43 -0600388 """Read and return the contents of a file.
389
390 Args:
391 fname: path to filename to read, where ## signifiies the chroot.
392
393 Returns:
394 data read from file, as a string.
395 """
Simon Glass3c47e412019-05-17 22:00:44 -0600396 with open(Filename(fname), binary and 'rb' or 'r') as fd:
Simon Glassaeffc5e2018-07-17 13:25:43 -0600397 data = fd.read()
398 #self._out.Info("Read file '%s' size %d (%#0x)" %
399 #(fname, len(data), len(data)))
400 return data
401
Simon Glassfd709862020-07-05 21:41:50 -0600402def WriteFile(fname, data, binary=True):
Simon Glassaeffc5e2018-07-17 13:25:43 -0600403 """Write data into a file.
404
405 Args:
406 fname: path to filename to write
407 data: data to write to file, as a string
408 """
409 #self._out.Info("Write file '%s' size %d (%#0x)" %
410 #(fname, len(data), len(data)))
Simon Glassfd709862020-07-05 21:41:50 -0600411 with open(Filename(fname), binary and 'wb' or 'w') as fd:
Simon Glassaeffc5e2018-07-17 13:25:43 -0600412 fd.write(data)
Simon Glasse6d85ff2019-05-14 15:53:47 -0600413
414def GetBytes(byte, size):
415 """Get a string of bytes of a given size
416
417 This handles the unfortunate different between Python 2 and Python 2.
418
419 Args:
420 byte: Numeric byte value to use
421 size: Size of bytes/string to return
422
423 Returns:
424 A bytes type with 'byte' repeated 'size' times
425 """
426 if sys.version_info[0] >= 3:
427 data = bytes([byte]) * size
428 else:
429 data = chr(byte) * size
430 return data
Simon Glass513eace2019-05-14 15:53:50 -0600431
432def ToUnicode(val):
433 """Make sure a value is a unicode string
434
435 This allows some amount of compatibility between Python 2 and Python3. For
436 the former, it returns a unicode object.
437
438 Args:
439 val: string or unicode object
440
441 Returns:
442 unicode version of val
443 """
444 if sys.version_info[0] >= 3:
445 return val
446 return val if isinstance(val, unicode) else val.decode('utf-8')
447
448def FromUnicode(val):
449 """Make sure a value is a non-unicode string
450
451 This allows some amount of compatibility between Python 2 and Python3. For
452 the former, it converts a unicode object to a string.
453
454 Args:
455 val: string or unicode object
456
457 Returns:
458 non-unicode version of val
459 """
460 if sys.version_info[0] >= 3:
461 return val
462 return val if isinstance(val, str) else val.encode('utf-8')
Simon Glass2b6ed5e2019-05-17 22:00:35 -0600463
464def ToByte(ch):
465 """Convert a character to an ASCII value
466
467 This is useful because in Python 2 bytes is an alias for str, but in
468 Python 3 they are separate types. This function converts the argument to
469 an ASCII value in either case.
470
471 Args:
472 ch: A string (Python 2) or byte (Python 3) value
473
474 Returns:
475 integer ASCII value for ch
476 """
477 return ord(ch) if type(ch) == str else ch
478
479def ToChar(byte):
480 """Convert a byte to a character
481
482 This is useful because in Python 2 bytes is an alias for str, but in
483 Python 3 they are separate types. This function converts an ASCII value to
484 a value with the appropriate type in either case.
485
486 Args:
487 byte: A byte or str value
488 """
489 return chr(byte) if type(byte) != str else byte
Simon Glassf6b64812019-05-17 22:00:36 -0600490
491def ToChars(byte_list):
492 """Convert a list of bytes to a str/bytes type
493
494 Args:
495 byte_list: List of ASCII values representing the string
496
497 Returns:
498 string made by concatenating all the ASCII values
499 """
500 return ''.join([chr(byte) for byte in byte_list])
501
502def ToBytes(string):
503 """Convert a str type into a bytes type
504
505 Args:
Simon Glass3b3e3c02019-10-31 07:42:50 -0600506 string: string to convert
Simon Glassf6b64812019-05-17 22:00:36 -0600507
508 Returns:
509 Python 3: A bytes type
510 Python 2: A string type
511 """
512 if sys.version_info[0] >= 3:
513 return string.encode('utf-8')
514 return string
Simon Glass07d9e702019-07-08 13:18:41 -0600515
Simon Glass3b3e3c02019-10-31 07:42:50 -0600516def ToString(bval):
517 """Convert a bytes type into a str type
518
519 Args:
520 bval: bytes value to convert
521
522 Returns:
523 Python 3: A bytes type
524 Python 2: A string type
525 """
526 return bval.decode('utf-8')
527
Simon Glasseb0f4a42019-07-20 12:24:06 -0600528def Compress(indata, algo, with_header=True):
Simon Glass07d9e702019-07-08 13:18:41 -0600529 """Compress some data using a given algorithm
530
531 Note that for lzma this uses an old version of the algorithm, not that
532 provided by xz.
533
534 This requires 'lz4' and 'lzma_alone' tools. It also requires an output
535 directory to be previously set up, by calling PrepareOutputDir().
536
537 Args:
538 indata: Input data to compress
539 algo: Algorithm to use ('none', 'gzip', 'lz4' or 'lzma')
540
541 Returns:
542 Compressed data
543 """
544 if algo == 'none':
545 return indata
546 fname = GetOutputFilename('%s.comp.tmp' % algo)
547 WriteFile(fname, indata)
548 if algo == 'lz4':
Simon Glass3b3e3c02019-10-31 07:42:50 -0600549 data = Run('lz4', '--no-frame-crc', '-c', fname, binary=True)
Simon Glass07d9e702019-07-08 13:18:41 -0600550 # cbfstool uses a very old version of lzma
551 elif algo == 'lzma':
552 outfname = GetOutputFilename('%s.comp.otmp' % algo)
553 Run('lzma_alone', 'e', fname, outfname, '-lc1', '-lp0', '-pb0', '-d8')
554 data = ReadFile(outfname)
555 elif algo == 'gzip':
Simon Glass3b3e3c02019-10-31 07:42:50 -0600556 data = Run('gzip', '-c', fname, binary=True)
Simon Glass07d9e702019-07-08 13:18:41 -0600557 else:
558 raise ValueError("Unknown algorithm '%s'" % algo)
Simon Glasseb0f4a42019-07-20 12:24:06 -0600559 if with_header:
560 hdr = struct.pack('<I', len(data))
561 data = hdr + data
Simon Glass07d9e702019-07-08 13:18:41 -0600562 return data
563
Simon Glasseb0f4a42019-07-20 12:24:06 -0600564def Decompress(indata, algo, with_header=True):
Simon Glass07d9e702019-07-08 13:18:41 -0600565 """Decompress some data using a given algorithm
566
567 Note that for lzma this uses an old version of the algorithm, not that
568 provided by xz.
569
570 This requires 'lz4' and 'lzma_alone' tools. It also requires an output
571 directory to be previously set up, by calling PrepareOutputDir().
572
573 Args:
574 indata: Input data to decompress
575 algo: Algorithm to use ('none', 'gzip', 'lz4' or 'lzma')
576
577 Returns:
578 Compressed data
579 """
580 if algo == 'none':
581 return indata
Simon Glasseb0f4a42019-07-20 12:24:06 -0600582 if with_header:
583 data_len = struct.unpack('<I', indata[:4])[0]
584 indata = indata[4:4 + data_len]
Simon Glass07d9e702019-07-08 13:18:41 -0600585 fname = GetOutputFilename('%s.decomp.tmp' % algo)
586 with open(fname, 'wb') as fd:
587 fd.write(indata)
588 if algo == 'lz4':
Simon Glass3b3e3c02019-10-31 07:42:50 -0600589 data = Run('lz4', '-dc', fname, binary=True)
Simon Glass07d9e702019-07-08 13:18:41 -0600590 elif algo == 'lzma':
591 outfname = GetOutputFilename('%s.decomp.otmp' % algo)
592 Run('lzma_alone', 'd', fname, outfname)
Simon Glass3b3e3c02019-10-31 07:42:50 -0600593 data = ReadFile(outfname, binary=True)
Simon Glass07d9e702019-07-08 13:18:41 -0600594 elif algo == 'gzip':
Simon Glass3b3e3c02019-10-31 07:42:50 -0600595 data = Run('gzip', '-cd', fname, binary=True)
Simon Glass07d9e702019-07-08 13:18:41 -0600596 else:
597 raise ValueError("Unknown algorithm '%s'" % algo)
598 return data
Simon Glass1cfdfc02019-07-08 13:18:51 -0600599
600CMD_CREATE, CMD_DELETE, CMD_ADD, CMD_REPLACE, CMD_EXTRACT = range(5)
601
602IFWITOOL_CMDS = {
603 CMD_CREATE: 'create',
604 CMD_DELETE: 'delete',
605 CMD_ADD: 'add',
606 CMD_REPLACE: 'replace',
607 CMD_EXTRACT: 'extract',
608 }
609
610def RunIfwiTool(ifwi_file, cmd, fname=None, subpart=None, entry_name=None):
611 """Run ifwitool with the given arguments:
612
613 Args:
614 ifwi_file: IFWI file to operation on
615 cmd: Command to execute (CMD_...)
616 fname: Filename of file to add/replace/extract/create (None for
617 CMD_DELETE)
618 subpart: Name of sub-partition to operation on (None for CMD_CREATE)
619 entry_name: Name of directory entry to operate on, or None if none
620 """
621 args = ['ifwitool', ifwi_file]
622 args.append(IFWITOOL_CMDS[cmd])
623 if fname:
624 args += ['-f', fname]
625 if subpart:
626 args += ['-n', subpart]
627 if entry_name:
628 args += ['-d', '-e', entry_name]
629 Run(*args)
Simon Glass9f297b02019-07-20 12:23:36 -0600630
631def ToHex(val):
632 """Convert an integer value (or None) to a string
633
634 Returns:
635 hex value, or 'None' if the value is None
636 """
637 return 'None' if val is None else '%#x' % val
638
639def ToHexSize(val):
640 """Return the size of an object in hex
641
642 Returns:
643 hex value of size, or 'None' if the value is None
644 """
645 return 'None' if val is None else '%#x' % len(val)