blob: f23329357727cec320a622583dc9fc71c4052c62 [file] [log] [blame]
Ram Chandrasekar613e1f42022-08-25 00:02:12 +00001# Copyright 2022 The ChromiumOS Authors
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5"""Parse and operate based on disk layout files.
6
7For information on the JSON format, see:
8 http://dev.chromium.org/chromium-os/developer-guide/disk-layout-format
9
10The --adjust_part flag takes arguments like:
11 <label>:<op><size>
12Where:
13 <label> is a label name as found in the disk layout file
14 <op> is one of the three: + - =
15 <size> is a number followed by an optional size qualifier:
16 B, KiB, MiB, GiB, TiB: bytes, kibi-, mebi-, gibi-, tebi- (base 1024)
17 B, K, M, G, T: short hand for above
18 B, KB, MB, GB, TB: bytes, kilo-, mega-, giga-, tera- (base 1000)
19
20This will set the ROOT-A partition size to 1 gibibytes (1024 * 1024 * 1024 * 1):
21 --adjust_part ROOT-A:=1GiB
22This will grow the ROOT-A partition size by 500 mebibytes (1024 * 1024 * 500):
23 --adjust_part ROOT-A:+500MiB
24This will shrink the ROOT-A partition size by 10 mebibytes (1024 * 1024 * 10):
25 --adjust_part ROOT-A:-20MiB
26"""
27
28import argparse
Ram Chandrasekar613e1f42022-08-25 00:02:12 +000029import inspect
Ram Chandrasekar613e1f42022-08-25 00:02:12 +000030import sys
31
Ram Chandrasekar633e1bb2022-09-20 20:02:31 +000032from chromite.lib import disk_layout
Ram Chandrasekar613e1f42022-08-25 00:02:12 +000033
34
35def WritePartitionScript(
36 options, image_type, layout_filename, sfilename, vfilename
37):
38 """Writes a shell script with functions for the base and requested layouts.
39
40 Args:
41 options: Flags passed to the script
42 image_type: Type of image eg base/test/dev/factory_install
43 layout_filename: Path to partition configuration file
44 sfilename: Filename to write the finished script to
45 vfilename: Filename to write the partition variables json data to
46 """
Ram Chandrasekar613e1f42022-08-25 00:02:12 +000047
Ram Chandrasekar633e1bb2022-09-20 20:02:31 +000048 return disk_layout.WritePartitionScript(
49 options, image_type, layout_filename, sfilename, vfilename
50 )
Ram Chandrasekar613e1f42022-08-25 00:02:12 +000051
52
53def GetBlockSize(_options, layout_filename):
54 """Returns the partition table block size.
55
56 Args:
57 options: Flags passed to the script
58 layout_filename: Path to partition configuration file
59
60 Returns:
61 Block size of all partitions in the layout
62 """
63
Ram Chandrasekar633e1bb2022-09-20 20:02:31 +000064 return disk_layout.GetBlockSize(_options, layout_filename)
Ram Chandrasekar613e1f42022-08-25 00:02:12 +000065
66
67def GetFilesystemBlockSize(_options, layout_filename):
68 """Returns the filesystem block size.
69
70 This is used for all partitions in the table that have filesystems.
71
72 Args:
73 options: Flags passed to the script
74 layout_filename: Path to partition configuration file
75
76 Returns:
77 Block size of all filesystems in the layout
78 """
79
Ram Chandrasekar633e1bb2022-09-20 20:02:31 +000080 return disk_layout.GetFilesystemBlockSize(_options, layout_filename)
Ram Chandrasekar613e1f42022-08-25 00:02:12 +000081
82
83def GetPartitionSize(options, image_type, layout_filename, num):
84 """Returns the partition size of a given partition for a given layout type.
85
86 Args:
87 options: Flags passed to the script
88 image_type: Type of image eg base/test/dev/factory_install
89 layout_filename: Path to partition configuration file
90 num: Number of the partition you want to read from
91
92 Returns:
93 Size of selected partition in bytes
94 """
95
Ram Chandrasekar633e1bb2022-09-20 20:02:31 +000096 return disk_layout.GetPartitionSize(
97 options, image_type, layout_filename, num
Ram Chandrasekar613e1f42022-08-25 00:02:12 +000098 )
Ram Chandrasekar613e1f42022-08-25 00:02:12 +000099
100
101def GetFormat(options, image_type, layout_filename, num):
102 """Returns the format of a given partition for a given layout type.
103
104 Args:
105 options: Flags passed to the script
106 image_type: Type of image eg base/test/dev/factory_install
107 layout_filename: Path to partition configuration file
108 num: Number of the partition you want to read from
109
110 Returns:
111 Format of the selected partition's filesystem
112 """
113
Ram Chandrasekar633e1bb2022-09-20 20:02:31 +0000114 return disk_layout.GetFormat(options, image_type, layout_filename, num)
Ram Chandrasekar613e1f42022-08-25 00:02:12 +0000115
116
Ram Chandrasekar633e1bb2022-09-20 20:02:31 +0000117def GetFilesystemFormat(options, image_type, layout_filename, num):
118 """Returns the filesystem format of a partition for a given layout type.
Ram Chandrasekar613e1f42022-08-25 00:02:12 +0000119
120 Args:
121 options: Flags passed to the script
122 image_type: Type of image eg base/test/dev/factory_install
123 layout_filename: Path to partition configuration file
124 num: Number of the partition you want to read from
125
126 Returns:
Ram Chandrasekar633e1bb2022-09-20 20:02:31 +0000127 Format of the selected partition's filesystem
Ram Chandrasekar613e1f42022-08-25 00:02:12 +0000128 """
129
Ram Chandrasekar633e1bb2022-09-20 20:02:31 +0000130 return disk_layout.GetFilesystemFormat(
131 options, image_type, layout_filename, num
Ram Chandrasekar613e1f42022-08-25 00:02:12 +0000132 )
Ram Chandrasekar613e1f42022-08-25 00:02:12 +0000133
134
135def GetFilesystemSize(options, image_type, layout_filename, num):
136 """Returns the filesystem size of a given partition for a given layout type.
137
138 If no filesystem size is specified, returns the partition size.
139
140 Args:
141 options: Flags passed to the script
142 image_type: Type of image eg base/test/dev/factory_install
143 layout_filename: Path to partition configuration file
144 num: Number of the partition you want to read from
145
146 Returns:
147 Size of selected partition filesystem in bytes
148 """
149
Ram Chandrasekar633e1bb2022-09-20 20:02:31 +0000150 return disk_layout.GetFilesystemSize(
151 options, image_type, layout_filename, num
Ram Chandrasekar613e1f42022-08-25 00:02:12 +0000152 )
Ram Chandrasekar613e1f42022-08-25 00:02:12 +0000153
Ram Chandrasekar633e1bb2022-09-20 20:02:31 +0000154
155def GetImageTypes(_options, layout_filename):
156 """Returns a list of all the image types in the layout.
157
158 Args:
159 options: Flags passed to the script
160 layout_filename: Path to partition configuration file
161
162 Returns:
163 List of all image types
164 """
165
166 return disk_layout.GetImageTypes(_options, layout_filename)
167
168
169def GetFilesystemOptions(options, image_type, layout_filename, num):
170 """Returns the filesystem options of a given partition and layout type.
171
172 Args:
173 options: Flags passed to the script
174 image_type: Type of image eg base/test/dev/factory_install
175 layout_filename: Path to partition configuration file
176 num: Number of the partition you want to read from
177
178 Returns:
179 The selected partition's filesystem options
180 """
181
182 return disk_layout.GetFilesystemOptions(
183 options, image_type, layout_filename, num
184 )
Ram Chandrasekar613e1f42022-08-25 00:02:12 +0000185
186
187def GetLabel(options, image_type, layout_filename, num):
188 """Returns the label for a given partition.
189
190 Args:
191 options: Flags passed to the script
192 image_type: Type of image eg base/test/dev/factory_install
193 layout_filename: Path to partition configuration file
194 num: Number of the partition you want to read from
195
196 Returns:
197 Label of selected partition, or 'UNTITLED' if none specified
198 """
199
Ram Chandrasekar633e1bb2022-09-20 20:02:31 +0000200 return disk_layout.GetLabel(options, image_type, layout_filename, num)
Ram Chandrasekar613e1f42022-08-25 00:02:12 +0000201
202
203def GetNumber(options, image_type, layout_filename, label):
204 """Returns the partition number of a given label.
205
206 Args:
207 options: Flags passed to the script
208 image_type: Type of image eg base/test/dev/factory_install
209 layout_filename: Path to partition configuration file
210 label: Number of the partition you want to read from
211
212 Returns:
213 The number of the partition corresponding to the label.
214 """
215
Ram Chandrasekar633e1bb2022-09-20 20:02:31 +0000216 return disk_layout.GetNumber(options, image_type, layout_filename, label)
Ram Chandrasekar613e1f42022-08-25 00:02:12 +0000217
218
219def GetReservedEraseBlocks(options, image_type, layout_filename, num):
220 """Returns the number of erase blocks reserved in the partition.
221
222 Args:
223 options: Flags passed to the script
224 image_type: Type of image eg base/test/dev/factory_install
225 layout_filename: Path to partition configuration file
226 num: Number of the partition you want to read from
227
228 Returns:
229 Number of reserved erase blocks
230 """
Ram Chandrasekar633e1bb2022-09-20 20:02:31 +0000231
232 return disk_layout.GetReservedEraseBlocks(
233 options, image_type, layout_filename, num
Ram Chandrasekar613e1f42022-08-25 00:02:12 +0000234 )
Ram Chandrasekar613e1f42022-08-25 00:02:12 +0000235
236
Ram Chandrasekar633e1bb2022-09-20 20:02:31 +0000237def GetType(options, image_type, layout_filename, num):
238 """Returns the type of a given partition for a given layout.
Ram Chandrasekar613e1f42022-08-25 00:02:12 +0000239
240 Args:
Ram Chandrasekar633e1bb2022-09-20 20:02:31 +0000241 options: Flags passed to the script
242 image_type: Type of image eg base/test/dev/factory_install
243 layout_filename: Path to partition configuration file
244 num: Number of the partition you want to read from
245
246 Returns:
247 Type of the specified partition.
Ram Chandrasekar613e1f42022-08-25 00:02:12 +0000248 """
Ram Chandrasekar613e1f42022-08-25 00:02:12 +0000249
Ram Chandrasekar633e1bb2022-09-20 20:02:31 +0000250 return disk_layout.GetType(options, image_type, layout_filename, num)
Ram Chandrasekar613e1f42022-08-25 00:02:12 +0000251
Ram Chandrasekar613e1f42022-08-25 00:02:12 +0000252
Ram Chandrasekar633e1bb2022-09-20 20:02:31 +0000253def GetPartitions(options, image_type, layout_filename):
254 """Returns the partition numbers for the image_type.
Ram Chandrasekar613e1f42022-08-25 00:02:12 +0000255
Ram Chandrasekar633e1bb2022-09-20 20:02:31 +0000256 Args:
257 options: Flags passed to the script
258 image_type: Type of image eg base/test/dev/factory_install
259 layout_filename: Path to partition configuration file
Ram Chandrasekar613e1f42022-08-25 00:02:12 +0000260
Ram Chandrasekar633e1bb2022-09-20 20:02:31 +0000261 Returns:
262 A space delimited string of partition numbers.
263 """
264
265 return disk_layout.GetPartitions(options, image_type, layout_filename)
266
267
268def GetUUID(options, image_type, layout_filename, num):
269 """Returns the filesystem UUID of a given partition for a given layout type.
270
271 Args:
272 options: Flags passed to the script
273 image_type: Type of image eg base/test/dev/factory_install
274 layout_filename: Path to partition configuration file
275 num: Number of the partition you want to read from
276
277 Returns:
278 UUID of specified partition. Defaults to random if not set.
279 """
280
281 return disk_layout.GetUUID(options, image_type, layout_filename, num)
Ram Chandrasekar613e1f42022-08-25 00:02:12 +0000282
283
284def DoDebugOutput(options, layout_filename, image_type):
285 """Prints out a human readable disk layout in on-disk order.
286
287 Args:
288 options: Flags passed to the script
289 layout_filename: Path to partition configuration file
290 image_type: Type of image e.g. ALL/LIST/base/test/dev/factory_install
291 """
Ram Chandrasekar613e1f42022-08-25 00:02:12 +0000292
Ram Chandrasekar633e1bb2022-09-20 20:02:31 +0000293 return disk_layout.DoDebugOutput(options, layout_filename, image_type)
Ram Chandrasekar613e1f42022-08-25 00:02:12 +0000294
295
296def Validate(options, image_type, layout_filename):
297 """Validates a layout file, used before reading sizes to check for errors.
298
299 Args:
300 options: Flags passed to the script
301 image_type: Type of image eg base/test/dev/factory_install
302 layout_filename: Path to partition configuration file
303 """
Ram Chandrasekar633e1bb2022-09-20 20:02:31 +0000304
305 return disk_layout.Validate(options, image_type, layout_filename)
Ram Chandrasekar613e1f42022-08-25 00:02:12 +0000306
307
308class ArgsAction(argparse.Action): # pylint: disable=no-init
309 """Helper to add all arguments to an args array.
310
311 ArgumentParser does not let you specify the same dest for multiple args.
312 We take care of appending to the 'args' array ourselves here.
313 """
314
315 def __call__(self, parser, namespace, values, option_string=None):
316 args = getattr(namespace, "args", [])
317 args.append(values)
318 setattr(namespace, "args", args)
319
320
321class HelpAllAction(argparse.Action):
322 """Display all subcommands help in one go."""
323
324 def __init__(self, *args, **kwargs):
325 if "nargs" in kwargs:
326 raise ValueError("nargs not allowed")
327 kwargs["nargs"] = 0
328 argparse.Action.__init__(self, *args, **kwargs)
329
330 def __call__(self, parser, namespace, values, option_string=None):
331 print("%s\nCommands:" % (parser.description,), end="")
332 subparser = getattr(namespace, "help_all")
333 for key, subparser in namespace.help_all.choices.items():
334 # Should we include the desc of each arg too ?
335 print(
336 "\n %s %s\n %s"
337 % (
338 key,
339 subparser.get_default("help_all"),
340 subparser.description,
341 )
342 )
343 sys.exit(0)
344
345
346def GetParser():
Ram Chandrasekar633e1bb2022-09-20 20:02:31 +0000347 """Return a parser for the CLI.
348
349 We use the function docstring to build the cli argument, help text
350 and their arguments.
351 """
Ram Chandrasekar613e1f42022-08-25 00:02:12 +0000352 parser = argparse.ArgumentParser(
353 description=__doc__,
354 formatter_class=argparse.RawDescriptionHelpFormatter,
355 )
356 parser.add_argument(
357 "--adjust_part",
358 metavar="SPEC",
359 default="",
360 help="adjust partition sizes",
361 )
362
363 action_map = {
364 "write": WritePartitionScript,
365 "readblocksize": GetBlockSize,
366 "readfsblocksize": GetFilesystemBlockSize,
367 "readpartsize": GetPartitionSize,
368 "readformat": GetFormat,
369 "readfsformat": GetFilesystemFormat,
370 "readfssize": GetFilesystemSize,
371 "readimagetypes": GetImageTypes,
372 "readfsoptions": GetFilesystemOptions,
373 "readlabel": GetLabel,
374 "readnumber": GetNumber,
375 "readreservederaseblocks": GetReservedEraseBlocks,
376 "readtype": GetType,
377 "readpartitionnums": GetPartitions,
378 "readuuid": GetUUID,
379 "debug": DoDebugOutput,
380 "validate": Validate,
381 }
382
383 # Subparsers are required by default under Python 2. Python 3 changed to
384 # not required, but didn't include a required option until 3.7. Setting
385 # the required member works in all versions (and setting dest name).
386 subparsers = parser.add_subparsers(title="Commands", dest="command")
387 subparsers.required = True
388
389 for name, func in sorted(action_map.items()):
390 # Turn the func's docstring into something we can show the user.
391 desc, doc = func.__doc__.split("\n", 1)
392 # Extract the help for each argument.
393 args_help = {}
394 for line in doc.splitlines():
395 if ":" in line:
396 arg, text = line.split(":", 1)
397 args_help[arg.strip()] = text.strip()
398
399 argspec = inspect.getfullargspec(func)
400 # Skip the first argument as that'll be the options field.
401 args = argspec.args[1:]
402
403 subparser = subparsers.add_parser(name, description=desc, help=desc)
404 subparser.set_defaults(
405 callback=func, help_all=" ".join("<%s>" % x for x in args)
406 )
407 for arg in args:
408 subparser.add_argument(arg, action=ArgsAction, help=args_help[arg])
409
410 parser.add_argument(
411 "--help-all",
412 action=HelpAllAction,
413 default=subparsers,
414 help="show all commands and their help in one screen",
415 )
416
417 return parser
418
419
420def main(argv):
421 parser = GetParser()
422 opts = parser.parse_args(argv)
423
424 ret = opts.callback(opts, *opts.args)
425 if ret is not None:
426 print(ret)
427
428
429if __name__ == "__main__":
430 sys.exit(main(sys.argv[1:]))