diff --git a/build_library/disk_util b/build_library/disk_util index c0aa1fc84f..6ea07fa57d 100755 --- a/build_library/disk_util +++ b/build_library/disk_util @@ -35,7 +35,8 @@ 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', 'fs_type', 'features', 'uuid', 'alignment')) + 'fs_block_size', 'fs_type', 'features', 'uuid', 'alignment', 'mount', + 'binds')) integer_layout_keys = set(( 'blocks', 'block_size', 'fs_blocks', 'fs_block_size', 'alignment')) required_layout_keys = set(('type', 'num', 'label', 'blocks')) @@ -321,6 +322,81 @@ def Format(options): Sudo(['losetup', '--detach', loop_dev]) +def Mount(options): + """Mount the given disk image. + + The existing partition table is used to determine what exists but the + disk layout config is used to look up mount points and binds. + + Args: + options: Flags passed to the script + """ + + config, partitions = LoadPartitionConfig(options) + mounts = {} + + cgpt_show = subprocess.check_output( + ['cgpt', 'show', '-q', options.disk_image]) + for line in cgpt_show.split('\n'): + if not line.strip(): + continue + fields = line.split(None, 3) + if len(fields) != 4 or not all(f.isdigit() for f in fields[:3]): + raise Exception('Invalid output from cgpt show -q: %r' % line) + + first_block = int(fields[0]) + blocks = int(fields[1]) + part_num = fields[2] + part = partitions.get(part_num, {}) + path = part.get('mount', None) + if not path or not path.startswith('/'): + continue + + mounts[path] = {'path': path, + 'offset': first_block * config['metadata']['block_size'], + 'size': blocks * config['metadata']['block_size'], + 'type': part.get('fs_type', 'auto'), + 'binds': part.get('binds', {})} + + rootfs = mounts.pop('/', None) + if not rootfs: + raise InvalidLayout('No partition defined to mount on /') + + def DoMount(mount): + full_path = os.path.realpath(options.mount_dir + mount['path']) + mount_opts = ['loop', + 'offset=%d' % mount['offset'], + 'sizelimit=%d' % mount['size']] + if options.read_only: + mount_opts.append('ro') + else: + Sudo(['mkdir', '-p', full_path]) + + Sudo(['mount', '-t', mount['type'], + '-o', ','.join(mount_opts), + options.disk_image, full_path]) + + for src, dst in mount['binds'].iteritems(): + # src may be relative or absolute, os.path.join handles this. + full_src = os.path.realpath( + options.mount_dir + os.path.join(mount['path'], src)) + full_dst = os.path.realpath(options.mount_dir + dst) + Sudo(['mkdir', '-p', full_src, full_dst]) + Sudo(['mount', '--bind', full_src, full_dst]) + + DoMount(rootfs) + for mount in mounts.itervalues(): + DoMount(mount) + +def Umount(options): + """Unmount the given path. + + Args: + options: Flags passed to the script + """ + Sudo(['umount', '--recursive', '--detach-loop', options.mount_dir]) + + def GetPartitionByNumber(partitions, num): """Given a partition table and number returns the partition object. @@ -519,6 +595,16 @@ def main(argv): a.add_argument('disk_image', help='path to disk image file') a.set_defaults(func=Format) + a = actions.add_parser('mount', help='mount filesystems in image') + a.add_argument('--read_only', '-r', help='mount filesystems read-only') + a.add_argument('disk_image', help='path to disk image file') + a.add_argument('mount_dir', help='path to root filesystem mount point') + a.set_defaults(func=Mount) + + a = actions.add_parser('umount', help='unmount a image mount point') + a.add_argument('mount_dir', help='path to root filesystem mount point') + a.set_defaults(func=Umount) + 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 b427d0c65d..dbe1628d9b 100644 --- a/build_library/legacy_disk_layout.json +++ b/build_library/legacy_disk_layout.json @@ -11,7 +11,8 @@ "label":"EFI-SYSTEM", "type":"efi", "blocks":"262144", - "fs_type":"vfat" + "fs_type":"vfat", + "mount":"/boot/efi" }, "2":{ "label":"BOOT-B", @@ -24,7 +25,8 @@ "type":"coreos-rootfs", "blocks":"2097152", "fs_blocks":"262144", - "fs_type":"ext2" + "fs_type":"ext2", + "mount":"/" }, "4":{ "label":"ROOT-B", @@ -43,7 +45,8 @@ "label":"OEM", "type":"data", "blocks":"262144", - "fs_type":"ext4" + "fs_type":"ext4", + "mount":"/usr/share/oem" }, "7":{ "type":"blank", @@ -59,7 +62,15 @@ "label":"STATE", "type":"data", "blocks":"1048576", - "fs_type":"ext4" + "fs_type":"ext4", + "mount":"/media/state", + "binds":{ + "overlays/home":"/home", + "overlays/opt":"/opt", + "overlays/srv":"/srv", + "overlays/usr/local":"/usr/local", + "overlays/var":"/var" + } } }, "vm":{