Skip to content

Commit 34e4bf9

Browse files
authored
Merge pull request #381 from eduardosm/disk-images-without-root
Create disk images without root
2 parents 04f6a2d + 5243d3b commit 34e4bf9

4 files changed

Lines changed: 35 additions & 68 deletions

File tree

lib/generator.py

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ def __init__(self, arch, external_sources, early_preseed, repo_path):
2929
self.external_sources = external_sources
3030
self.repo_path = repo_path
3131
self.source_manifest = self.get_source_manifest(not self.external_sources)
32+
self.early_source_manifest = self.get_source_manifest(True)
3233
self.target_dir = None
3334
self.external_dir = None
3435

@@ -59,26 +60,16 @@ def prepare(self, target, using_kernel=False, kernel_bootstrap=False, target_siz
5960
# argument matrix ... or we could just use ext3 instead which
6061
# is effectively universally the same
6162
if kernel_bootstrap:
62-
init_path = os.path.join(self.target_dir, 'init')
63+
self.target_dir = os.path.join(self.target_dir, 'init')
64+
os.mkdir(self.target_dir)
6365

64-
os.mkdir(init_path)
65-
self.target_dir = init_path
66-
67-
if self.repo_path or self.external_sources:
68-
target.add_disk("external", filesystem="ext3")
69-
target.mount_disk("external", "external")
70-
else:
66+
if not self.repo_path and not self.external_sources:
7167
self.external_dir = os.path.join(self.target_dir, 'external')
7268
elif using_kernel:
7369
self.target_dir = os.path.join(self.target_dir, 'disk')
74-
target.add_disk("disk",
75-
filesystem="ext3",
76-
size=(str(target_size) + "M") if target_size else "16G",
77-
bootable=True)
78-
target.mount_disk("disk", "disk")
7970
self.external_dir = os.path.join(self.target_dir, 'external')
8071

81-
os.makedirs(self.external_dir, exist_ok=True)
72+
os.makedirs(self.external_dir)
8273

8374
if self.early_preseed:
8475
# Extract tar containing preseed
@@ -103,10 +94,16 @@ def prepare(self, target, using_kernel=False, kernel_bootstrap=False, target_siz
10394
if kernel_bootstrap:
10495
self.create_builder_hex0_disk_image(self.target_dir + '.img', target_size)
10596

106-
if kernel_bootstrap and (self.external_sources or self.repo_path):
107-
target.umount_disk('external')
97+
if self.repo_path or self.external_sources:
98+
mkfs_args = ['-d', os.path.join(target.path, 'external')]
99+
target.add_disk("external", filesystem="ext3", mkfs_args=mkfs_args)
108100
elif using_kernel:
109-
target.umount_disk('disk')
101+
mkfs_args = ['-d', os.path.join(target.path, 'disk')]
102+
target.add_disk("disk",
103+
filesystem="ext3",
104+
size=(str(target_size) + "M") if target_size else "16G",
105+
bootable=True,
106+
mkfs_args=mkfs_args)
110107

111108
def steps(self):
112109
"""Copy in steps."""
@@ -163,9 +160,10 @@ def create_fiwix_file_list(self):
163160

164161
def distfiles(self):
165162
"""Copy in distfiles"""
166-
def copy_no_network_distfiles(out):
163+
def copy_no_network_distfiles(out, early):
167164
# Note that "no disk" implies "no network" for kernel bootstrap mode
168-
for file in self.source_manifest:
165+
manifest = self.early_source_manifest if early else self.source_manifest
166+
for file in manifest:
169167
file = file[3].strip()
170168
shutil.copy2(os.path.join(self.distfiles_dir, file),
171169
os.path.join(out, file))
@@ -175,13 +173,13 @@ def copy_no_network_distfiles(out):
175173

176174
if early_distfile_dir != main_distfile_dir:
177175
os.makedirs(early_distfile_dir, exist_ok=True)
178-
copy_no_network_distfiles(early_distfile_dir)
176+
copy_no_network_distfiles(early_distfile_dir, True)
179177

180178
if self.external_sources:
181179
shutil.copytree(self.distfiles_dir, main_distfile_dir, dirs_exist_ok=True)
182180
else:
183181
os.mkdir(main_distfile_dir)
184-
copy_no_network_distfiles(main_distfile_dir)
182+
copy_no_network_distfiles(main_distfile_dir, False)
185183

186184
@staticmethod
187185
def output_dir(srcfs_file, dirpath):

lib/target.py

Lines changed: 8 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,9 @@
88
"""
99

1010
import enum
11-
import getpass
1211
import os
1312

14-
from lib.utils import mount, umount, create_disk, run_as_root
13+
from lib.utils import mount, create_disk
1514

1615
class TargetType(enum.Enum):
1716
"""Different types of target dirs we can have"""
@@ -24,7 +23,6 @@ class Target:
2423
"""
2524

2625
_disks = {}
27-
_disk_filesystems = {}
2826
_mountpoints = {}
2927

3028
def __init__(self, path="target"):
@@ -34,15 +32,6 @@ def __init__(self, path="target"):
3432
if not os.path.exists(self.path):
3533
os.mkdir(self.path)
3634

37-
def __del__(self):
38-
for path in self._mountpoints:
39-
print(f"Unmounting {path}")
40-
umount(path)
41-
42-
for disk in self._disks.values():
43-
print(f"Detaching {disk}")
44-
run_as_root("losetup", "-d", disk)
45-
4635
def tmpfs(self, size="8G"):
4736
"""Mount a tmpfs"""
4837
print(f"Mounting tmpfs on {self.path}")
@@ -59,32 +48,13 @@ def add_disk(self,
5948
mkfs_args=None):
6049
"""Add a disk"""
6150
disk_path = os.path.join(self.path, f"{name}.img")
62-
self._disks[name] = create_disk(disk_path,
63-
tabletype,
64-
filesystem,
65-
size,
66-
bootable,
67-
mkfs_args)
68-
self._disk_filesystems[name] = filesystem
69-
# Allow executing user to access it
70-
run_as_root("chown", getpass.getuser(), self._disks[name])
71-
72-
def mount_disk(self, name, mountpoint=None):
73-
"""Mount the disk"""
74-
if mountpoint is None:
75-
mountpoint = f"{name}_mnt"
76-
mountpoint = os.path.join(self.path, mountpoint)
77-
os.mkdir(mountpoint)
78-
mount(self._disks[name] + "p1", mountpoint, self._disk_filesystems[name])
79-
# Allow executing user to access it
80-
run_as_root("chown", getpass.getuser(), mountpoint)
81-
self._mountpoints[name] = mountpoint
82-
return mountpoint
83-
84-
def umount_disk(self, name):
85-
"""Unmount a disk"""
86-
umount(self._mountpoints[name])
87-
del self._mountpoints[name]
51+
create_disk(disk_path,
52+
tabletype,
53+
filesystem,
54+
size,
55+
bootable,
56+
mkfs_args)
57+
self._disks[name] = disk_path
8858

8959
def get_disk(self, name):
9060
"""Get the path to a device of a disk"""

lib/utils.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,13 @@ def create_disk(image, disk_type, fs_type, size, bootable=False, mkfs_args=None)
3737
if mkfs_args is None:
3838
mkfs_args = []
3939
run('truncate', '-s', size, image)
40-
# First find the device we will use, then actually use it
41-
loop_dev = run_as_root('losetup', '-f', capture_output=True).stdout.decode().strip()
42-
run_as_root('losetup', '-P', loop_dev, image)
4340
# Create the partition
4441
if disk_type != "none":
45-
run_as_root('parted', '--script', image, 'mklabel', disk_type, 'mkpart',
46-
'primary', fs_type, '1GiB' if bootable else '1MiB', '100%')
47-
run_as_root('partprobe', loop_dev)
48-
run_as_root('mkfs.' + fs_type, loop_dev + "p1", *mkfs_args)
49-
return loop_dev
42+
# 1 GiB if bootable, 1 MiB otherwise
43+
offset = str(1024 * 1024 * (1024 if bootable else 1))
44+
run('parted', '--script', image, 'mklabel', disk_type, 'mkpart',
45+
'primary', fs_type, offset + 'B', '100%')
46+
run('mkfs.' + fs_type, image, '-E', 'offset=' + offset, *mkfs_args)
5047

5148
def mount(source, target, fs_type, options='', **kwargs):
5249
"""Mount filesystem"""

steps/jump/move_disk.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ while ! dd if=/dev/${DISK} of=/dev/null bs=512 count=1; do
2222
done
2323

2424
# Create partition if it doesn't exist
25-
if [ $(($(stat -c "%Lr" "/dev/${DISK}") % 8)) -eq 0 ]; then
25+
# 'stat -c "%T"' prints the minor device type in hexadecimal.
26+
# The decimal version (with "%Lr") is not available in this version of stat.
27+
if [ $((0x$(stat -c "%T" "/dev/${DISK}") % 8)) -eq 0 ]; then
2628
echo "Creating partition table..."
2729
# Start at 1GiB, use -S32 -H64 to align to MiB rather than cylinder boundary
2830
echo "2097152;" | sfdisk -uS -S32 -H64 --force "/dev/${DISK}"

0 commit comments

Comments
 (0)