blob: f3e81b6bc61b386b867395c4f920d0a819a30471 [file] [log] [blame]
Simon Glass1d5006c2022-10-29 19:47:05 -06001# SPDX-License-Identifier: GPL-2.0+
2#
Simon Glass1d5006c2022-10-29 19:47:05 -06003# Copyright (c) 2018, Linaro Limited
4# Author: Takahiro Akashi <takahiro.akashi@linaro.org>
5
Simon Glassfbd95502022-10-29 19:47:06 -06006"""Helper functions for dealing with filesystems"""
7
Simon Glass1d5006c2022-10-29 19:47:05 -06008import re
9import os
10from subprocess import call, check_call, check_output, CalledProcessError
11
Richard Weinberger41eca322024-11-21 15:32:07 -070012def mk_fs(config, fs_type, size, prefix, src_dir=None, size_gran = 0x100000):
Simon Glass1d5006c2022-10-29 19:47:05 -060013 """Create a file system volume
14
15 Args:
Simon Glassfbd95502022-10-29 19:47:06 -060016 config (u_boot_config): U-Boot configuration
Simon Glass1d5006c2022-10-29 19:47:05 -060017 fs_type (str): File system type, e.g. 'ext4'
18 size (int): Size of file system in bytes
19 prefix (str): Prefix string of volume's file name
Richard Weinberger41eca322024-11-21 15:32:07 -070020 src_dir (str): Root directory to use, or None for none
Christian Taedcked6048802023-11-15 13:44:23 +010021 size_gran (int): Size granularity of file system image in bytes
Simon Glassfbd95502022-10-29 19:47:06 -060022
23 Raises:
24 CalledProcessError: if any error occurs when creating the filesystem
Simon Glass1d5006c2022-10-29 19:47:05 -060025 """
Simon Glassfbd95502022-10-29 19:47:06 -060026 fs_img = f'{prefix}.{fs_type}.img'
Simon Glass08709212023-08-24 13:55:38 -060027 fs_img = os.path.join(config.persistent_data_dir, fs_img)
Simon Glass1d5006c2022-10-29 19:47:05 -060028
Christian Taedckeff0ceca2023-11-15 13:44:21 +010029 if fs_type == 'fat12':
30 mkfs_opt = '-F 12'
31 elif fs_type == 'fat16':
Simon Glass1d5006c2022-10-29 19:47:05 -060032 mkfs_opt = '-F 16'
33 elif fs_type == 'fat32':
34 mkfs_opt = '-F 32'
35 else:
36 mkfs_opt = ''
37
38 if re.match('fat', fs_type):
39 fs_lnxtype = 'vfat'
40 else:
41 fs_lnxtype = fs_type
42
Richard Weinberger41eca322024-11-21 15:32:07 -070043 if src_dir:
44 if fs_lnxtype == 'ext4':
45 mkfs_opt = mkfs_opt + ' -d ' + src_dir
46 elif fs_lnxtype != 'vfat':
47 raise ValueError(f'src_dir not implemented for fs {fs_lnxtype}')
48
Christian Taedcked6048802023-11-15 13:44:23 +010049 count = (size + size_gran - 1) // size_gran
Simon Glass1d5006c2022-10-29 19:47:05 -060050
51 # Some distributions do not add /sbin to the default PATH, where mkfs lives
52 if '/sbin' not in os.environ["PATH"].split(os.pathsep):
53 os.environ["PATH"] += os.pathsep + '/sbin'
54
55 try:
Simon Glassfbd95502022-10-29 19:47:06 -060056 check_call(f'rm -f {fs_img}', shell=True)
Christian Taedcked6048802023-11-15 13:44:23 +010057 check_call(f'dd if=/dev/zero of={fs_img} bs={size_gran} count={count}',
Simon Glassfbd95502022-10-29 19:47:06 -060058 shell=True)
59 check_call(f'mkfs.{fs_lnxtype} {mkfs_opt} {fs_img}', shell=True)
Simon Glass1d5006c2022-10-29 19:47:05 -060060 if fs_type == 'ext4':
Simon Glassfbd95502022-10-29 19:47:06 -060061 sb_content = check_output(f'tune2fs -l {fs_img}',
62 shell=True).decode()
Simon Glass1d5006c2022-10-29 19:47:05 -060063 if 'metadata_csum' in sb_content:
Simon Glassfbd95502022-10-29 19:47:06 -060064 check_call(f'tune2fs -O ^metadata_csum {fs_img}', shell=True)
Richard Weinberger41eca322024-11-21 15:32:07 -070065 elif fs_lnxtype == 'vfat' and src_dir:
66 check_call(f'mcopy -i {fs_img} -vsmpQ {src_dir}/* ::/', shell=True)
Simon Glass1d5006c2022-10-29 19:47:05 -060067 return fs_img
68 except CalledProcessError:
Simon Glassfbd95502022-10-29 19:47:06 -060069 call(f'rm -f {fs_img}', shell=True)
Simon Glass1d5006c2022-10-29 19:47:05 -060070 raise
Simon Glassfbd95502022-10-29 19:47:06 -060071
Tom Rini20b09192025-03-20 07:59:24 -060072def setup_image(ubman, devnum, part_type, img_size=20, second_part=False,
73 basename='mmc'):
74 """Create a disk image with a single partition
75
76 Args:
77 ubman (ConsoleBase): Console to use
78 devnum (int): Device number to use, e.g. 1
79 part_type (int): Partition type, e.g. 0xc for FAT32
80 img_size (int): Image size in MiB
81 second_part (bool): True to contain a small second partition
82 basename (str): Base name to use in the filename, e.g. 'mmc'
83
84 Returns:
85 tuple:
86 str: Filename of MMC image
87 str: Directory name of scratch directory
88 """
89 fname = os.path.join(ubman.config.source_dir, f'{basename}{devnum}.img')
90 mnt = os.path.join(ubman.config.persistent_data_dir, 'scratch')
91
92 spec = f'type={part_type:x}, size={img_size - 2}M, start=1M, bootable'
93 if second_part:
94 spec += '\ntype=c'
95
96 try:
97 check_call(f'mkdir -p {mnt}', shell=True)
98 check_call(f'qemu-img create {fname} 20M', shell=True)
99 check_call(f'printf "{spec}" | sfdisk {fname}', shell=True)
100 except CalledProcessError:
101 call(f'rm -f {fname}', shell=True)
102 raise
103
104 return fname, mnt
105
Simon Glassfbd95502022-10-29 19:47:06 -0600106# Just for trying out
107if __name__ == "__main__":
108 import collections
109
110 CNF= collections.namedtuple('config', 'persistent_data_dir')
111
112 mk_fs(CNF('.'), 'ext4', 0x1000000, 'pref')