],
)
- with complete_step("Running build script…"), mount_build_overlay(state):
+ with complete_step("Running build script…"),\
+ mount_build_overlay(state),\
+ mount_passwd(state.name, state.uid, state.gid, state.root):
bwrap(
[state.config.build_script],
network=state.config.with_network,
with complete_step("Building initrd"):
args, [config] = parse_config(cmdline)
unlink_output(args, config)
- build_image(args, config, state.uid, state.gid)
+ build_image(args, config, state.name, state.uid, state.gid)
symlink.symlink_to(config.output_dir / config.output)
os.utime(p, (mtime, mtime), follow_symlinks=False)
-def build_image(args: MkosiArgs, config: MkosiConfig, uid: int, gid: int) -> None:
+def build_image(args: MkosiArgs, config: MkosiConfig, name: str, uid: int, gid: int) -> None:
manifest = Manifest(config) if config.manifest_format else None
workspace = tempfile.TemporaryDirectory(dir=config.workspace_dir, prefix=".mkosi-tmp")
with workspace, scopedenv({"TMPDIR" : workspace.name}):
- state = MkosiState(args, config, Path(workspace.name), uid, gid)
+ state = MkosiState(args, config, Path(workspace.name), name, uid, gid)
install_package_manager_trees(state)
with mount_base_trees(state):
with complete_step(f"Building {config.preset or 'default'} image"),\
mount_tools(config.tools_tree),\
+ mount_passwd(name, uid, gid),\
prepend_to_environ_path(config):
# Create these as the invoking user to make sure they're owned by the user running mkosi.
run(["mkdir", "--parents", p], user=uid, group=gid)
with acl_toggle_build(config, uid):
- build_image(args, config, uid, gid)
+ build_image(args, config, name, uid, gid)
# Make sure all build outputs that are not directories are owned by the user running mkosi.
for p in config.output_dir.iterdir():
@contextlib.contextmanager
-def mount_passwd(name: str, uid: int, gid: int, umount: bool = True) -> Iterator[None]:
+def mount_passwd(name: str, uid: int, gid: int, root: Path = Path("/"), umount: bool = True) -> Iterator[None]:
"""
ssh looks up the running user in /etc/passwd and fails if it can't find the running user. To trick it, we
mount over /etc/passwd with our own file containing our user in the user namespace.
"""
with tempfile.NamedTemporaryFile(prefix="mkosi.passwd", mode="w") as passwd:
- passwd.write(f"{name}:x:{uid}:{gid}:{name}:/bin/sh\n")
+ passwd.write("root:x:0:0:root:/root:/bin/sh\n")
+ if uid != 0:
+ passwd.write(f"{name}:x:{uid}:{gid}:{name}:/home/{name}:/bin/sh\n")
+ passwd.flush()
os.fchown(passwd.file.fileno(), uid, gid)
- with mount(passwd.name, Path("/etc/passwd"), operation="--bind", umount=umount):
- passwd.close() # Don't need the file anymore after it's mounted.
+ with mount(passwd.name, root / "etc/passwd", operation="--bind", umount=umount):
yield