mirror of
https://github.com/BigfootACA/arch-image-builder.git
synced 2024-09-21 13:20:53 +08:00
Compare commits
4 Commits
c3297b2aa0
...
0d8ef8a67c
Author | SHA1 | Date | |
---|---|---|---|
0d8ef8a67c | |||
8ed06d8f8b | |||
38447f1dd7 | |||
f6a1c73125 |
@ -5,6 +5,7 @@ from builder.lib import utils
|
||||
from builder.component import user
|
||||
from builder.lib.config import ArchBuilderConfigError
|
||||
from builder.lib.context import ArchBuilderContext
|
||||
from builder.lib.cgroup import CGroup
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
@ -14,6 +15,7 @@ def chroot_run(
|
||||
cwd: str = None,
|
||||
env: dict = None,
|
||||
stdin: str | bytes = None,
|
||||
cgroup: CGroup = None,
|
||||
) -> int:
|
||||
"""
|
||||
Chroot into rootfs and run programs
|
||||
@ -24,7 +26,7 @@ def chroot_run(
|
||||
path = ctx.get_rootfs()
|
||||
args = ["chroot", path]
|
||||
args.extend(utils.parse_cmd_args(cmd))
|
||||
return ctx.run_external(args, cwd, env, stdin)
|
||||
return ctx.run_external(args, cwd, env, stdin, cgroup)
|
||||
|
||||
|
||||
def proc_mkdir(ctx: ArchBuilderContext, file: dict, path: str):
|
||||
@ -76,8 +78,17 @@ def check_allowed(path: str, action: str):
|
||||
1. /etc/ is used for administrator configs
|
||||
2. /boot/ is used for system boot up, you can put bootloaders configs into this folder
|
||||
3. /var/ is used for daemons runtime states
|
||||
3. /usr/lib/modules/ is used for kernel modules (custom kernel)
|
||||
3. /usr/lib/firmware/ is used for system firmware (custom firmware)
|
||||
"""
|
||||
if not path.startswith(("/etc/", "/boot/", "/var/")):
|
||||
allow_list = (
|
||||
"/etc/",
|
||||
"/boot/",
|
||||
"/var/",
|
||||
"/usr/lib/modules",
|
||||
"/usr/lib/firmware",
|
||||
)
|
||||
if not path.startswith(allow_list):
|
||||
raise ArchBuilderConfigError(f"{action} {path} is not allowed")
|
||||
|
||||
|
||||
@ -85,8 +96,8 @@ def add_file(ctx: ArchBuilderContext, file: dict):
|
||||
# at least path content
|
||||
if "path" not in file:
|
||||
raise ArchBuilderConfigError("no path set in file")
|
||||
if "content" not in file:
|
||||
raise ArchBuilderConfigError("no content set in file")
|
||||
if "content" not in file and "source" not in file:
|
||||
raise ArchBuilderConfigError("no content or source set in file")
|
||||
root = ctx.get_rootfs()
|
||||
path: str = file["path"]
|
||||
if path.startswith("/"): path = path[1:]
|
||||
@ -98,6 +109,9 @@ def add_file(ctx: ArchBuilderContext, file: dict):
|
||||
# follow symbolic links
|
||||
follow = file["follow"] if "follow" in file else True
|
||||
|
||||
# source is a folder
|
||||
folder = file["folder"] if "folder" in file else False
|
||||
|
||||
# files mode
|
||||
mode = int(file["mode"]) if "mode" in file else 0o0644
|
||||
|
||||
@ -109,6 +123,7 @@ def add_file(ctx: ArchBuilderContext, file: dict):
|
||||
# resolve to rootfs
|
||||
real = os.path.join(root, path)
|
||||
|
||||
if "content" in file:
|
||||
if not follow and os.path.exists(real): os.remove(real)
|
||||
log.debug(f"create file {real}")
|
||||
with open(real, "wb") as f:
|
||||
@ -118,6 +133,17 @@ def add_file(ctx: ArchBuilderContext, file: dict):
|
||||
real, content.strip()
|
||||
)
|
||||
f.write(content.encode(encode))
|
||||
elif "source" in file:
|
||||
src: str = file["source"]
|
||||
if not src.startswith("/"):
|
||||
src = os.path.join(ctx.dir, src)
|
||||
log.debug(f"copy {src} to {real}")
|
||||
if folder:
|
||||
shutil.copytree(src, real, symlinks=follow)
|
||||
else:
|
||||
shutil.copyfile(src, real, follow_symlinks=follow)
|
||||
else:
|
||||
assert False
|
||||
log.debug(f"chmod file {real} to {mode:04o}")
|
||||
os.chmod(real, mode=mode)
|
||||
log.debug(f"chown file {real} to {uid}:{gid}")
|
||||
|
@ -1,7 +1,7 @@
|
||||
import os
|
||||
from logging import getLogger
|
||||
from builder.lib.context import ArchBuilderContext
|
||||
from builder.lib.mount import MountTab, MountPoint
|
||||
from builder.lib.mount import MountTab
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
@ -49,25 +49,6 @@ def undo_mounts(ctx: ArchBuilderContext):
|
||||
raise RuntimeError("mount points not cleanup")
|
||||
|
||||
|
||||
def do_mount(
|
||||
ctx: ArchBuilderContext,
|
||||
source: str,
|
||||
target: str,
|
||||
fstype: str,
|
||||
options: str
|
||||
):
|
||||
"""
|
||||
Add a mount point
|
||||
"""
|
||||
mnt = MountPoint()
|
||||
mnt.source = source
|
||||
mnt.target = target
|
||||
mnt.fstype = fstype
|
||||
mnt.options = options
|
||||
mnt.mount()
|
||||
ctx.mounted.insert(0, mnt)
|
||||
|
||||
|
||||
def init_mount(ctx: ArchBuilderContext):
|
||||
"""
|
||||
Setup mount points for rootfs
|
||||
@ -80,7 +61,7 @@ def init_mount(ctx: ArchBuilderContext):
|
||||
os.symlink(target, real)
|
||||
def root_mount(source, target, fstype, options):
|
||||
real = os.path.realpath(os.path.join(root, target))
|
||||
do_mount(ctx, source, real, fstype, options)
|
||||
ctx.mount(source, real, fstype, options)
|
||||
try:
|
||||
# ensure mount point is clean
|
||||
mnts = MountTab.parse_mounts()
|
||||
|
@ -7,7 +7,7 @@ from builder.lib.cpu import cpu_arch_get
|
||||
from builder.lib.utils import parse_cmd_args
|
||||
from builder.lib.subscript import dict_get
|
||||
from builder.lib.loop import loop_detach
|
||||
from builder.lib.mount import MountTab
|
||||
from builder.lib.mount import MountTab, MountPoint
|
||||
from builder.lib.cgroup import CGroup
|
||||
from builder.lib.subscript import SubScript
|
||||
from builder.lib.shadow import PasswdFile, GroupFile
|
||||
@ -142,7 +142,8 @@ class ArchBuilderContext:
|
||||
/,
|
||||
cwd: str = None,
|
||||
env: dict = None,
|
||||
stdin: str | bytes = None
|
||||
stdin: str | bytes = None,
|
||||
cgroup: CGroup = None,
|
||||
) -> int:
|
||||
"""
|
||||
Run external command
|
||||
@ -153,7 +154,8 @@ class ArchBuilderContext:
|
||||
log.debug(f"running external command {argv}")
|
||||
fstdin = None if stdin is None else PIPE
|
||||
proc = Popen(args, cwd=cwd, env=env, stdin=fstdin)
|
||||
self.cgroup.add_pid(proc.pid)
|
||||
if cgroup is None: cgroup = self.cgroup
|
||||
cgroup.add_pid(proc.pid)
|
||||
if stdin:
|
||||
if type(stdin) is str: stdin = stdin.encode()
|
||||
proc.stdin.write(stdin)
|
||||
@ -187,3 +189,31 @@ class ArchBuilderContext:
|
||||
ss = SubScript()
|
||||
self.config = deepcopy(self.config_orig)
|
||||
ss.parse(self.config)
|
||||
|
||||
def mount(
|
||||
self,
|
||||
source: str,
|
||||
target: str,
|
||||
fstype: str,
|
||||
options: str,
|
||||
) -> MountPoint:
|
||||
"""
|
||||
Add a mount point
|
||||
"""
|
||||
mnt = MountPoint()
|
||||
mnt.source = source
|
||||
mnt.target = os.path.realpath(target)
|
||||
mnt.fstype = fstype
|
||||
mnt.options = options
|
||||
mnt.mount()
|
||||
self.mounted.insert(0, mnt)
|
||||
return mnt
|
||||
|
||||
def umount(self, path: str):
|
||||
"""
|
||||
Remove a mount point
|
||||
"""
|
||||
real = os.path.realpath(path)
|
||||
if not os.path.ismount(real): return
|
||||
for mnt in self.mounted.find_target(real):
|
||||
self.mounted.remove(mnt)
|
||||
|
Loading…
Reference in New Issue
Block a user