Add -D/--daemonize to run -r/--run sessions in the background
Single-fork daemonize: the child calls setsid() itself rather than
re-enabling bwrap's own --new-session, which was previously removed
(and stays that way) because it only detaches the deeply-nested
sandboxed command, leaving bwrap/nsenter/slocker-lite itself still
attached to the original session -- not real daemonization. Calling
setsid() in slocker-lite's own forked child, before it execs into
nsenter/bwrap, detaches the whole chain at once, since exec() never
changes session membership -- confirmed via ps -o sid,pgid,tty against
a running daemonized session.
The child also ignores SIGHUP (confirmed to survive exec() into bwrap,
unlike a real handler, which exec() resets) and redirects stdin to
/dev/null and stdout/stderr to a log file under
$XDG_STATE_HOME/slocker-lite/logs/ (session_log_file_path(), new
sibling to the existing session_pid_file_path() in pid_file.{h,cpp}).
The original process blocks briefly on a pipe until the child reports
the real bwrap pid (or exits without doing so), then prints it and
exits -- keeping "pid" meaning the same thing everywhere in this
codebase (the same one --list-processes/-e/--exec already use), rather
than introducing a separate daemon-supervisor pid. run_bwrap() gained
an on_bwrap_pid_known callback (bwrap.{h,cpp}) for this, invoked
alongside the existing session-lock creation at the same instant.
The daemonized child is what runs run_container()'s entire existing
body afterward, including the unmount/cleanup that already ran once
bwrap exits -- no separate watcher/reaper process.
Testing caught a real bug before this was correct: the log file gets
renamed from its initial (daemon-pid-named) filename to the final
<container_name>-<bwrap-pid>.log once the real pid is known, but the
parent had already been told the pre-rename path and was never updated
-- fixed by re-reporting the path over the same pipe after the rename.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gv3s5jckJKzh6JkMoi2Akz
This commit is contained in:
@@ -77,6 +77,7 @@ slocker-lite -V|--version
|
||||
| `-u, --umount <layer-id>` | Unmount a previously mounted layer (the ID printed by `--mount`/`--run`, or from `containers-storage layers`). |
|
||||
| `-c, --cleanup <layer-id>` | Delete a layer and its ancestor chain from local storage (unmount it first). |
|
||||
| `-n, --no-nsenter` | With `--run`, bind the mount directly instead of `nsenter`-ing into `fuse-overlayfs`'s namespace. Automatic when running as root; use this to force it off otherwise. |
|
||||
| `-D, --daemonize` | With `--run`, fork into the background: detaches from the controlling terminal (`setsid()`), ignores `SIGHUP`, and redirects stdin from `/dev/null` and stdout/stderr to a log file under `$XDG_STATE_HOME/slocker-lite/logs/`. Prints the session's pid and log path, then returns — the same pid `--list-processes`/`-e/--exec` use. |
|
||||
| `--user <user>` | With `--run`, run the command as this user (name or numeric uid) instead of the image's own declared user (or root, if it declares none). Resolved against the image's own `/etc/passwd`. Only takes effect when `--run` executes as root. |
|
||||
| `--group <group>` | With `--user`, use this group (name or numeric gid) instead of the user's primary group. |
|
||||
| `--hostname <name>` | With `--run`, set the sandbox's hostname. Only takes effect if the running kernel supports `--unshare-uts`; ignored with a warning otherwise. |
|
||||
@@ -117,6 +118,9 @@ sudo ./buildDir/slocker-lite -r myimage.tar --user git
|
||||
# Run with extra environment variables, from flags and/or a file
|
||||
./buildDir/slocker-lite -r myimage.tar --env FOO=bar --env-file ./app.env
|
||||
|
||||
# Run in the background; prints its pid and log file, then returns
|
||||
./buildDir/slocker-lite -r myimage.tar -D
|
||||
|
||||
# List every OCI image tar in a directory
|
||||
./buildDir/slocker-lite -l ./images
|
||||
|
||||
@@ -208,6 +212,20 @@ rather than joining the outer `bwrap` process's own namespaces, so the joined
|
||||
command sees the container's process tree and hostname too, not just its
|
||||
filesystem.
|
||||
|
||||
`-D/--daemonize` forks and detaches into the background by calling `setsid()`
|
||||
itself, rather than re-enabling `bwrap`'s own `--new-session` — that flag only
|
||||
detaches the deeply-nested sandboxed command, leaving `bwrap`/`nsenter` still
|
||||
attached to the original session. Calling `setsid()` in `slocker-lite`'s own
|
||||
forked child, before it execs into `nsenter`/`bwrap`, detaches the whole chain
|
||||
at once (`exec()` never changes session membership), and correctly scopes
|
||||
`bwrap`'s own `--die-with-parent` to that child. The child ignores `SIGHUP` and
|
||||
redirects output to a log file before doing anything else; the original,
|
||||
still-foreground process waits only long enough to learn the real session pid
|
||||
(the same one `--list-processes`/`-e/--exec` use) before printing it and
|
||||
returning — the detached child is what runs the entire session afterward,
|
||||
including the same unmount/cleanup that always ran once the sandboxed command
|
||||
exits.
|
||||
|
||||
See `CLAUDE.md` for the full architecture writeup (file-by-file breakdown, the
|
||||
reasoning behind each of the above, and known gaps).
|
||||
|
||||
|
||||
Reference in New Issue
Block a user