mirror of
https://github.com/BigfootACA/arch-image-builder.git
synced 2024-09-21 15: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.component import user
|
||||||
from builder.lib.config import ArchBuilderConfigError
|
from builder.lib.config import ArchBuilderConfigError
|
||||||
from builder.lib.context import ArchBuilderContext
|
from builder.lib.context import ArchBuilderContext
|
||||||
|
from builder.lib.cgroup import CGroup
|
||||||
log = getLogger(__name__)
|
log = getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@ -14,6 +15,7 @@ def chroot_run(
|
|||||||
cwd: str = None,
|
cwd: str = None,
|
||||||
env: dict = None,
|
env: dict = None,
|
||||||
stdin: str | bytes = None,
|
stdin: str | bytes = None,
|
||||||
|
cgroup: CGroup = None,
|
||||||
) -> int:
|
) -> int:
|
||||||
"""
|
"""
|
||||||
Chroot into rootfs and run programs
|
Chroot into rootfs and run programs
|
||||||
@ -24,7 +26,7 @@ def chroot_run(
|
|||||||
path = ctx.get_rootfs()
|
path = ctx.get_rootfs()
|
||||||
args = ["chroot", path]
|
args = ["chroot", path]
|
||||||
args.extend(utils.parse_cmd_args(cmd))
|
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):
|
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
|
1. /etc/ is used for administrator configs
|
||||||
2. /boot/ is used for system boot up, you can put bootloaders configs into this folder
|
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. /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")
|
raise ArchBuilderConfigError(f"{action} {path} is not allowed")
|
||||||
|
|
||||||
|
|
||||||
@ -85,8 +96,8 @@ def add_file(ctx: ArchBuilderContext, file: dict):
|
|||||||
# at least path content
|
# at least path content
|
||||||
if "path" not in file:
|
if "path" not in file:
|
||||||
raise ArchBuilderConfigError("no path set in file")
|
raise ArchBuilderConfigError("no path set in file")
|
||||||
if "content" not in file:
|
if "content" not in file and "source" not in file:
|
||||||
raise ArchBuilderConfigError("no content set in file")
|
raise ArchBuilderConfigError("no content or source set in file")
|
||||||
root = ctx.get_rootfs()
|
root = ctx.get_rootfs()
|
||||||
path: str = file["path"]
|
path: str = file["path"]
|
||||||
if path.startswith("/"): path = path[1:]
|
if path.startswith("/"): path = path[1:]
|
||||||
@ -98,6 +109,9 @@ def add_file(ctx: ArchBuilderContext, file: dict):
|
|||||||
# follow symbolic links
|
# follow symbolic links
|
||||||
follow = file["follow"] if "follow" in file else True
|
follow = file["follow"] if "follow" in file else True
|
||||||
|
|
||||||
|
# source is a folder
|
||||||
|
folder = file["folder"] if "folder" in file else False
|
||||||
|
|
||||||
# files mode
|
# files mode
|
||||||
mode = int(file["mode"]) if "mode" in file else 0o0644
|
mode = int(file["mode"]) if "mode" in file else 0o0644
|
||||||
|
|
||||||
@ -109,15 +123,27 @@ def add_file(ctx: ArchBuilderContext, file: dict):
|
|||||||
# resolve to rootfs
|
# resolve to rootfs
|
||||||
real = os.path.join(root, path)
|
real = os.path.join(root, path)
|
||||||
|
|
||||||
if not follow and os.path.exists(real): os.remove(real)
|
if "content" in file:
|
||||||
log.debug(f"create file {real}")
|
if not follow and os.path.exists(real): os.remove(real)
|
||||||
with open(real, "wb") as f:
|
log.debug(f"create file {real}")
|
||||||
content: str = file["content"]
|
with open(real, "wb") as f:
|
||||||
log.debug(
|
content: str = file["content"]
|
||||||
"write to %s with %s",
|
log.debug(
|
||||||
real, content.strip()
|
"write to %s with %s",
|
||||||
)
|
real, content.strip()
|
||||||
f.write(content.encode(encode))
|
)
|
||||||
|
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}")
|
log.debug(f"chmod file {real} to {mode:04o}")
|
||||||
os.chmod(real, mode=mode)
|
os.chmod(real, mode=mode)
|
||||||
log.debug(f"chown file {real} to {uid}:{gid}")
|
log.debug(f"chown file {real} to {uid}:{gid}")
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import os
|
import os
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
from builder.lib.context import ArchBuilderContext
|
from builder.lib.context import ArchBuilderContext
|
||||||
from builder.lib.mount import MountTab, MountPoint
|
from builder.lib.mount import MountTab
|
||||||
log = getLogger(__name__)
|
log = getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@ -49,25 +49,6 @@ def undo_mounts(ctx: ArchBuilderContext):
|
|||||||
raise RuntimeError("mount points not cleanup")
|
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):
|
def init_mount(ctx: ArchBuilderContext):
|
||||||
"""
|
"""
|
||||||
Setup mount points for rootfs
|
Setup mount points for rootfs
|
||||||
@ -80,7 +61,7 @@ def init_mount(ctx: ArchBuilderContext):
|
|||||||
os.symlink(target, real)
|
os.symlink(target, real)
|
||||||
def root_mount(source, target, fstype, options):
|
def root_mount(source, target, fstype, options):
|
||||||
real = os.path.realpath(os.path.join(root, target))
|
real = os.path.realpath(os.path.join(root, target))
|
||||||
do_mount(ctx, source, real, fstype, options)
|
ctx.mount(source, real, fstype, options)
|
||||||
try:
|
try:
|
||||||
# ensure mount point is clean
|
# ensure mount point is clean
|
||||||
mnts = MountTab.parse_mounts()
|
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.utils import parse_cmd_args
|
||||||
from builder.lib.subscript import dict_get
|
from builder.lib.subscript import dict_get
|
||||||
from builder.lib.loop import loop_detach
|
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.cgroup import CGroup
|
||||||
from builder.lib.subscript import SubScript
|
from builder.lib.subscript import SubScript
|
||||||
from builder.lib.shadow import PasswdFile, GroupFile
|
from builder.lib.shadow import PasswdFile, GroupFile
|
||||||
@ -142,7 +142,8 @@ class ArchBuilderContext:
|
|||||||
/,
|
/,
|
||||||
cwd: str = None,
|
cwd: str = None,
|
||||||
env: dict = None,
|
env: dict = None,
|
||||||
stdin: str | bytes = None
|
stdin: str | bytes = None,
|
||||||
|
cgroup: CGroup = None,
|
||||||
) -> int:
|
) -> int:
|
||||||
"""
|
"""
|
||||||
Run external command
|
Run external command
|
||||||
@ -153,7 +154,8 @@ class ArchBuilderContext:
|
|||||||
log.debug(f"running external command {argv}")
|
log.debug(f"running external command {argv}")
|
||||||
fstdin = None if stdin is None else PIPE
|
fstdin = None if stdin is None else PIPE
|
||||||
proc = Popen(args, cwd=cwd, env=env, stdin=fstdin)
|
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 stdin:
|
||||||
if type(stdin) is str: stdin = stdin.encode()
|
if type(stdin) is str: stdin = stdin.encode()
|
||||||
proc.stdin.write(stdin)
|
proc.stdin.write(stdin)
|
||||||
@ -187,3 +189,31 @@ class ArchBuilderContext:
|
|||||||
ss = SubScript()
|
ss = SubScript()
|
||||||
self.config = deepcopy(self.config_orig)
|
self.config = deepcopy(self.config_orig)
|
||||||
ss.parse(self.config)
|
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