From ba45152b4b8305f409ad8426783e24e232de8032 Mon Sep 17 00:00:00 2001 From: Michael Marineau Date: Fri, 20 Dec 2013 22:03:44 -0800 Subject: [PATCH] feat(disk_util): Add 'format' command to create filesystems in an image. This will replace the less flexible code in base_image_util.sh --- build_library/disk_util | 122 +++++++++++++++++++++++++- build_library/legacy_disk_layout.json | 12 ++- 2 files changed, 127 insertions(+), 7 deletions(-) diff --git a/build_library/disk_util b/build_library/disk_util index 510c04bff0..c0aa1fc84f 100755 --- a/build_library/disk_util +++ b/build_library/disk_util @@ -35,7 +35,7 @@ def LoadPartitionConfig(options): valid_keys = set(('_comment', 'metadata', 'layouts')) valid_layout_keys = set(( '_comment', 'type', 'num', 'label', 'blocks', 'block_size', 'fs_blocks', - 'fs_block_size', 'features', 'uuid', 'alignment')) + 'fs_block_size', 'fs_type', 'features', 'uuid', 'alignment')) integer_layout_keys = set(( 'blocks', 'block_size', 'fs_blocks', 'fs_block_size', 'alignment')) required_layout_keys = set(('type', 'num', 'label', 'blocks')) @@ -94,6 +94,10 @@ def LoadPartitionConfig(options): except ValueError as e: raise InvalidLayout('Invalid uuid %r: %s' % (part['uuid'], e)) + if 'fs_type' in part: + if part['fs_type'] not in ('ext2', 'ext4', 'vfat'): + raise InvalidLayout('Invalid fs_type: %r' % part['fs_type']) + def Align(count, alignment): offset = count % alignment @@ -131,6 +135,7 @@ def LoadPartitionConfig(options): disk_block_count = Align(disk_block_count, part['alignment']) part['first_block'] = disk_block_count + part['first_byte'] = disk_block_count * metadata['block_size'] disk_block_count += part['blocks'] part.setdefault('uuid', str(uuid.uuid4())) @@ -171,17 +176,20 @@ def GetPartitionTableFromConfig(options): return partitions -def WritePartitionTable(options): +def WritePartitionTable(options, config=None, partitions=None): """Writes the given partition table to a disk image or device. Args: options: Flags passed to the script + config: Complete layout configuration file object + partitions: Selected layout configuration object """ def Cgpt(*args): subprocess.check_call(['cgpt'] + [str(a) for a in args]) - config, partitions = LoadPartitionConfig(options) + if not (config and partitions): + config, partitions = LoadPartitionConfig(options) Cgpt('create', '-c', '-s', config['metadata']['blocks'], options.disk_image) @@ -211,6 +219,108 @@ def WritePartitionTable(options): Cgpt('show', options.disk_image) +def Sudo(cmd, stdout_null=False): + """Little wrapper around sudo with support for redirecting to /dev/null + + Some tools like tune2fs don't have a quiet mode which just adds + useless noise to our build output, drowning out what may be more + interesting news. + + Args: + cmd: a command and arguments to run. + stdout_null: bool to enable redirecting stdout to /dev/null. + """ + + null = None + if stdout_null: + null = open('/dev/null', 'w') + + try: + subprocess.check_call(['sudo'] + [str(c) for c in cmd], stdout=null) + finally: + if null: + null.close() + + +def FormatExt(part, device): + """Format an ext2 or ext4 filesystem. + + Args: + part: dict defining the partition + device: name of the block device to format + """ + Sudo(['mke2fs', '-q', + '-t', part['fs_type'], + '-b', part['fs_block_size'], + device, + part['fs_blocks']]) + + # TODO(marineam): Make more of these fs options configurable. + Sudo(['tune2fs', '-L', part['label'], + '-U', 'clear', + '-T', '20091119110000', + '-c', '0', '-i', '0', # Disable auto fsck + '-m', '0', '-r', '0', # Disable reserve blocks + '-e', 'remount-ro', + device], + stdout_null=True) + + +def FormatFat(part, device): + """Format a FAT filesystem. + + Args: + part: dict defining the partition + device: name of the block device to format + """ + # The block-count argument to mkfs.vfat is in units of 1k + vfat_block_size = 1024 + vfat_blocks = part['bytes'] // vfat_block_size + + Sudo(['mkfs.vfat', '-n', part['label'], + device, + vfat_blocks], + stdout_null=True) + + +def Format(options): + """Writes the given partition table and initialize fresh filesystems. + + Args: + options: Flags passed to the script + """ + + # Note on using sudo: We don't really need to do this stuff as root + # but mke2fs and friends doesn't have an option to make filesystems at + # arbitrary offsets but using loop devices makes that possible. + + config, partitions = LoadPartitionConfig(options) + WritePartitionTable(options, config, partitions) + + for part in partitions.itervalues(): + if 'fs_type' not in part: + continue + + print "Formatting partition %s (%s) as %s" % ( + part['num'], part['label'], part['fs_type']) + + loop_dev = subprocess.check_output(['sudo', 'losetup', + '--offset', str(part['first_byte']), + '--sizelimit', str(part['bytes']), + '--find', '--show', options.disk_image]) + loop_dev = loop_dev.strip() + + try: + if part['fs_type'] in ('ext2', 'ext4'): + FormatExt(part, loop_dev) + elif part['fs_type'] == 'vfat': + FormatFat(part, loop_dev) + else: + raise Exception("Unhandled fs type %s" % part['fs_type']) + finally: + Sudo(['losetup', '--detach', loop_dev]) + + def GetPartitionByNumber(partitions, num): """Given a partition table and number returns the partition object. @@ -403,6 +513,12 @@ def main(argv): a.add_argument('disk_image', help='path to disk image file') a.set_defaults(func=WritePartitionTable) + a = actions.add_parser('format', help='write gpt and filesystems to image') + a.add_argument('--mbr_boot_code', + help='path to mbr boot block, such as syslinux/gptmbr.bin') + a.add_argument('disk_image', help='path to disk image file') + a.set_defaults(func=Format) + a = actions.add_parser('readblocksize', help='get device block size') a.set_defaults(func=GetBlockSize) diff --git a/build_library/legacy_disk_layout.json b/build_library/legacy_disk_layout.json index 87395e2adf..b427d0c65d 100644 --- a/build_library/legacy_disk_layout.json +++ b/build_library/legacy_disk_layout.json @@ -10,7 +10,8 @@ "1":{ "label":"EFI-SYSTEM", "type":"efi", - "blocks":"262144" + "blocks":"262144", + "fs_type":"vfat" }, "2":{ "label":"BOOT-B", @@ -22,7 +23,8 @@ "uuid":"7130c94a-213a-4e5a-8e26-6cce9662f132", "type":"coreos-rootfs", "blocks":"2097152", - "fs_blocks":"262144" + "fs_blocks":"262144", + "fs_type":"ext2" }, "4":{ "label":"ROOT-B", @@ -40,7 +42,8 @@ "6":{ "label":"OEM", "type":"data", - "blocks":"262144" + "blocks":"262144", + "fs_type":"ext4" }, "7":{ "type":"blank", @@ -55,7 +58,8 @@ "9":{ "label":"STATE", "type":"data", - "blocks":"1048576" + "blocks":"1048576", + "fs_type":"ext4" } }, "vm":{