scripts: Convert the build-efi script to avoid sudo
Make use of the mk_fs() function to avoid needing to use sudo to mount the loopback partition. This makes the script a little more friendly for those nervous about sudo in their tools. Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
@@ -1127,6 +1127,7 @@ W: https://docs.u-boot.org/en/latest/board/emulation/script.html
|
||||
F: configs/qemu_x86*
|
||||
F: doc/board/emulation/script.rst
|
||||
F: scripts/build-qemu.sh
|
||||
F: scripts/build_helper.py
|
||||
|
||||
ENVIRONMENT
|
||||
M: Joe Hershberger <joe.hershberger@ni.com>
|
||||
|
||||
@@ -17,21 +17,10 @@ Use ~/.build-efi to configure the various paths used by this script.
|
||||
|
||||
from argparse import ArgumentParser
|
||||
import configparser
|
||||
import glob
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
import time
|
||||
|
||||
|
||||
OUR_PATH = os.path.dirname(os.path.realpath(__file__))
|
||||
OUR1_PATH = os.path.dirname(OUR_PATH)
|
||||
|
||||
# Bring in the patman and dtoc libraries (but don't override the first path
|
||||
# in PYTHONPATH)
|
||||
sys.path.insert(2, os.path.join(OUR1_PATH, 'tools'))
|
||||
|
||||
from build_helper import Helper
|
||||
|
||||
# pylint: disable=C0413
|
||||
from u_boot_pylib import command
|
||||
@@ -108,11 +97,10 @@ efi_dir = .
|
||||
class BuildEfi:
|
||||
"""Class to collect together the various bits of state while running"""
|
||||
def __init__(self, settings, args):
|
||||
self.helper = Helper()
|
||||
self.settings = settings
|
||||
self.img = self.get_setting('image_file', 'try.img')
|
||||
self.build_dir = self.get_setting("build_dir", '/tmp')
|
||||
self.mnt = self.get_setting("mount_point", '/mnt/test-efi')
|
||||
self.tmp = None
|
||||
self.args = args
|
||||
|
||||
def get_setting(self, name, fallback=None):
|
||||
@@ -174,83 +162,18 @@ class BuildEfi:
|
||||
cmd += extra
|
||||
command.run(*cmd)
|
||||
|
||||
def setup_files(self, build, build_type):
|
||||
def setup_files(self, build, build_type, dst):
|
||||
"""Set up files in the staging area
|
||||
|
||||
Args:
|
||||
build (str): Name of build being packaged, e.g. 'efi-x86_app32'
|
||||
build_type (str): Build type ('app' or 'payload')
|
||||
dst (str): Destination directory
|
||||
"""
|
||||
print(f'Packaging {build}')
|
||||
if not os.path.exists(self.tmp):
|
||||
os.mkdir(self.tmp)
|
||||
fname = f'u-boot-{build_type}.efi'
|
||||
tools.write_file(f'{self.tmp}/startup.nsh', f'fs0:{fname}',
|
||||
binary=False)
|
||||
shutil.copy(f'{self.build_dir}/{build}/{fname}', self.tmp)
|
||||
|
||||
def copy_files(self):
|
||||
"""Copy files into the filesystem"""
|
||||
command.run('sudo', 'cp', *glob.glob(f'{self.tmp}/*'), self.mnt)
|
||||
if self.args.kernel:
|
||||
bzimage = self.get_setting('bzimage_file', 'bzImage')
|
||||
command.run('sudo', 'cp', bzimage, f'{self.mnt}/vmlinuz')
|
||||
|
||||
def setup_raw(self):
|
||||
"""Create a filesystem on a raw device and copy in the files"""
|
||||
command.output('mkfs.vfat', self.img)
|
||||
command.run('sudo', 'mkdir', '-p', self.mnt)
|
||||
command.run('sudo', 'mount', '-o', 'loop', self.img, self.mnt)
|
||||
self.copy_files()
|
||||
command.run('sudo', 'umount', self.mnt)
|
||||
|
||||
def setup_part(self):
|
||||
"""Set up a partition table
|
||||
|
||||
Create a partition table and put the filesystem in the first partition
|
||||
then copy in the files
|
||||
"""
|
||||
|
||||
# Create a gpt partition table with one partition
|
||||
command.run('parted', self.img, 'mklabel', 'gpt', capture_stderr=True)
|
||||
|
||||
# This doesn't work correctly. It creates:
|
||||
# Number Start End Size File system Name Flags
|
||||
# 1 1049kB 24.1MB 23.1MB boot msftdata
|
||||
# Odd if the same is entered interactively it does set the FS type
|
||||
command.run('parted', '-s', '-a', 'optimal', '--',
|
||||
self.img, 'mkpart', 'boot', 'fat32', '1MiB', '23MiB')
|
||||
|
||||
# Map this partition to a loop device. Output is something like:
|
||||
# add map loop48p1 (252:3): 0 45056 linear 7:48 2048
|
||||
out = command.output('sudo', 'kpartx', '-av', self.img)
|
||||
m = re.search(r'(loop.*p.)', out)
|
||||
if not m:
|
||||
raise ValueError(f'Invalid output from kpartx: {out}')
|
||||
|
||||
boot_dev = m.group(1)
|
||||
dev = f'/dev/mapper/{boot_dev}'
|
||||
|
||||
command.output('mkfs.vfat', dev)
|
||||
|
||||
command.run('sudo', 'mount', '-o', 'loop', dev, self.mnt)
|
||||
|
||||
try:
|
||||
self.copy_files()
|
||||
finally:
|
||||
# Sync here since this makes kpartx more likely to work the first time
|
||||
command.run('sync')
|
||||
command.run('sudo', 'umount', self.mnt)
|
||||
|
||||
# For some reason this needs a sleep or it sometimes fails, if it was
|
||||
# run recently (in the last few seconds)
|
||||
try:
|
||||
cmd = 'sudo', 'kpartx', '-d', self.img
|
||||
command.output(*cmd)
|
||||
except command.CommandExc:
|
||||
time.sleep(0.5)
|
||||
cmd = 'sudo', 'kpartx', '-d', self.img
|
||||
command.output(*cmd)
|
||||
tools.write_file(f'{dst}/startup.nsh', f'fs0:{fname}', binary=False)
|
||||
shutil.copy(f'{self.build_dir}/{build}/{fname}', dst)
|
||||
|
||||
def do_build(self, build):
|
||||
"""Build U-Boot for the selected board"""
|
||||
@@ -267,7 +190,6 @@ class BuildEfi:
|
||||
bitness = 32 if args.word else 64
|
||||
arch = 'arm' if args.arm else 'x86'
|
||||
build_type = 'payload' if args.payload else 'app'
|
||||
self.tmp = f'{self.build_dir}/efi{bitness}{build_type}'
|
||||
build = f'efi-{arch}_{build_type}{bitness}'
|
||||
|
||||
if not args.no_build:
|
||||
@@ -276,14 +198,12 @@ class BuildEfi:
|
||||
if args.old and bitness == 32:
|
||||
build = f'efi-{arch}_{build_type}'
|
||||
|
||||
self.setup_files(build, build_type)
|
||||
|
||||
command.output('qemu-img', 'create', self.img, '24M')
|
||||
|
||||
if args.partition:
|
||||
self.setup_part()
|
||||
else:
|
||||
self.setup_raw()
|
||||
with self.helper.make_disk(self.img, fs_type='vfat',
|
||||
use_part=args.partition) as dirpath:
|
||||
self.setup_files(build, build_type, dirpath)
|
||||
if self.args.kernel:
|
||||
bzimage = self.helper.get_setting('bzimage_file', 'bzImage')
|
||||
command.run('cp', bzimage, f'{dirpath}/vmlinuz')
|
||||
|
||||
if args.run:
|
||||
self.run_qemu(bitness, args.serial)
|
||||
|
||||
64
scripts/build_helper.py
Normal file
64
scripts/build_helper.py
Normal file
@@ -0,0 +1,64 @@
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
"""Common script for build- scripts
|
||||
|
||||
"""
|
||||
|
||||
import contextlib
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
OUR_PATH = os.path.dirname(os.path.realpath(__file__))
|
||||
OUR1_PATH = os.path.dirname(OUR_PATH)
|
||||
|
||||
# Bring in the patman and test libraries (but don't override the first path in
|
||||
# PYTHONPATH)
|
||||
sys.path.insert(2, os.path.join(OUR1_PATH, 'tools'))
|
||||
sys.path.insert(2, os.path.join(OUR1_PATH, 'test/py/tests'))
|
||||
|
||||
from u_boot_pylib import command
|
||||
from u_boot_pylib import tools
|
||||
import fs_helper
|
||||
|
||||
|
||||
class Helper:
|
||||
def __init__(self):
|
||||
self.settings = None
|
||||
|
||||
@contextlib.contextmanager
|
||||
def make_disk(self, fname, size_mb=20, fs_type='ext4', use_part=False):
|
||||
"""Create a raw disk image with files on it
|
||||
|
||||
Args:
|
||||
fname (str): Filename to write the images to
|
||||
fs_type (str): Filesystem type to create (ext4 or vfat)
|
||||
size_mb (int): Size in MiB
|
||||
use_part (bool): True to create a partition table, False to use a
|
||||
raw disk image
|
||||
|
||||
Yields:
|
||||
str: Directory to write the files into
|
||||
"""
|
||||
with tempfile.NamedTemporaryFile() as tmp:
|
||||
with tempfile.TemporaryDirectory(prefix='build_helper.') as dirname:
|
||||
try:
|
||||
yield dirname
|
||||
fs_helper.mk_fs(None, fs_type, size_mb << 20, None, dirname,
|
||||
fs_img=tmp.name, quiet=True)
|
||||
finally:
|
||||
pass
|
||||
|
||||
if use_part:
|
||||
with open(fname, 'wb') as img:
|
||||
img.truncate(size_mb << 20)
|
||||
img.seek(1 << 20, 0)
|
||||
img.write(tools.read_file(tmp.name))
|
||||
subprocess.run(
|
||||
['sfdisk', fname], text=True, check=True,
|
||||
capture_output=True,
|
||||
input=f'type=c, size={size_mb-1}M, start=1M,bootable')
|
||||
else:
|
||||
shutil.copy2(tmp.name, fname)
|
||||
Reference in New Issue
Block a user