Skip to Content.
Sympa Menu

sm-commit - [[SM-Commit] ] GIT changes to master grimoire by Ismael Luceno (c1ebe7e232b4310ec6ec875c1e6f00501473d8e3)

sm-commit AT lists.ibiblio.org

Subject: Source Mage code commit list

List archive

Chronological Thread  
  • From: Ismael Luceno <scm AT sourcemage.org>
  • To: sm-commit AT lists.ibiblio.org, sm-commit AT lists.sourcemage.org
  • Subject: [[SM-Commit] ] GIT changes to master grimoire by Ismael Luceno (c1ebe7e232b4310ec6ec875c1e6f00501473d8e3)
  • Date: Tue, 22 Sep 2026 22:16:56 +0000

GIT changes to master grimoire by Ismael Luceno <ismael AT sourcemage.org>:

containers/lilipod/DETAILS
| 1
containers/lilipod/HISTORY
| 16
containers/lilipod/patches/0001-Fix-parallel-builds.patch
| 6

containers/lilipod/patches/0002-Report-container-setup-failures-instead-of-discardin.patch
| 278 ++++++++++

containers/lilipod/patches/0003-Explain-cgroup-and-mqueue-setup-failures.patch
| 112 ++++
containers/lilipod/patches/0004-cmd-rm-accept-volumes-v-flag.patch
| 53 +

containers/lilipod/patches/0005-logs-don-t-truncate-the-log-file-before-reading-it.patch
| 58 ++
7 files changed, 521 insertions(+), 3 deletions(-)

New commits:
commit c1ebe7e232b4310ec6ec875c1e6f00501473d8e3
Author: Ismael Luceno <ismael AT sourcemage.org>
Commit: Ismael Luceno <ismael AT sourcemage.org>

lilipod: Fix error reporting during startup

commit e634a767c3cd5f7afc23ab04017220f104f70f11
Author: Ismael Luceno <ismael AT sourcemage.org>
Commit: Ismael Luceno <ismael AT sourcemage.org>

lilipod: Add rm --volumes implementation

commit bd920995f5cb8986ba830f77d83b7df122bbe2cb
Author: Ismael Luceno <ismael AT sourcemage.org>
Commit: Ismael Luceno <ismael AT sourcemage.org>

lilipod: Improve error reporting

diff --git a/containers/lilipod/DETAILS b/containers/lilipod/DETAILS
index 551f6be..f75fc7c 100755
--- a/containers/lilipod/DETAILS
+++ b/containers/lilipod/DETAILS
@@ -1,5 +1,6 @@
SPELL=lilipod
VERSION=0.0.3
+ PATCHLEVEL=1
SOURCE=$SPELL-$VERSION.tar.gz

SOURCE_URL[0]=https://github.com/89luca89/lilipod/archive/v${VERSION}.tar.gz

SOURCE_HASH=sha512:8f24507f46068cf201880f2131d80f446fa72e82b7426e8763799489e96a548c4400d79576c84a13a39d72b044453198b0f03684ffebbaf916b4debdd098cb43
diff --git a/containers/lilipod/HISTORY b/containers/lilipod/HISTORY
new file mode 100644
index 0000000..948fa82
--- /dev/null
+++ b/containers/lilipod/HISTORY
@@ -0,0 +1,16 @@
+2026-09-23 Ismael Luceno <ismael AT sourcemage.org>
+ * DETAILS: PATCHLEVEL++
+ *
patches/0002-Report-container-setup-failures-instead-of-discardin.patch,
+ patches/0003-Explain-cgroup-and-mqueue-setup-failures.patch:
+ improved error reporting
+ * patches/0004-cmd-rm-accept-volumes-v-flag.patch:
+ implemented --volumes in the rm command
+ *
patches/0005-logs-don-t-truncate-the-log-file-before-reading-it.patch:
+ fixed error reporting during startup
+
+2026-08-16 Ismael Luceno <ismael AT sourcemage.org>
+ * WATCH: added
+
+2025-11-16 Ismael Luceno <ismael AT sourcemage.org>
+ * BUILD, DEPENDS, DETAILS, INSTALL, PRE_BUILD,
+ patches/0001-Fix-parallel-builds.patch: spell created
diff --git a/containers/lilipod/patches/0001-Fix-parallel-builds.patch
b/containers/lilipod/patches/0001-Fix-parallel-builds.patch
index 2e0b609..112960f 100644
--- a/containers/lilipod/patches/0001-Fix-parallel-builds.patch
+++ b/containers/lilipod/patches/0001-Fix-parallel-builds.patch
@@ -1,13 +1,13 @@
-From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From 75d9d5117e8a628ef7541f8513f10feb965258bd Mon Sep 17 00:00:00 2001
From: Ismael Luceno <ismael AT sourcemage.org>
Date: Sun, 16 Nov 2025 06:09:11 +0100
-Subject: [PATCH] Fix parallel builds
+Subject: [PATCH 1/5] Fix parallel builds

Upstream-Status: Pending
Origin: Source Mage
Signed-off-by: Ismael Luceno <ismael AT sourcemage.org>
---
- Makefile | 11 +++++------
+ Makefile | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/Makefile b/Makefile
diff --git
a/containers/lilipod/patches/0002-Report-container-setup-failures-instead-of-discardin.patch

b/containers/lilipod/patches/0002-Report-container-setup-failures-instead-of-discardin.patch
new file mode 100644
index 0000000..6f0c351
--- /dev/null
+++
b/containers/lilipod/patches/0002-Report-container-setup-failures-instead-of-discardin.patch
@@ -0,0 +1,278 @@
+From 9227e822c258084729fb98d7c61e88a629c6651e Mon Sep 17 00:00:00 2001
+From: Ismael Luceno <ismael AT sourcemage.org>
+Date: Sat, 15 Aug 2026 04:00:00 +0100
+Subject: [PATCH 2/5] Report container setup failures instead of discarding
+ them
+
+Three places turned a diagnosable failure into a bare "exit status 1":
+
+- EnsureFakeRoot() left Stdout/Stderr unset on the detached child, sending
+ everything the setup wrote to /dev/null, and returned success even when
+ the child had already died.
+- RunDetached()'s watchdog called os.Exit(0) once the child was gone, so a
+ container that failed to start was indistinguishable from one that ran
+ successfully. Close the log pipes instead and let cmd.Wait() report the
+ real status, along with the tail of the container log.
+- GetSubIDRanges() propagated getsubids' exit status verbatim and then
+ sliced its output unconditionally. Report why it failed, include its
+ stderr, and say how to add the missing subordinate ID ranges.
+
+Upstream-Status: Pending
+Origin: Source Mage
+Signed-off-by: Ismael Luceno <ismael AT sourcemage.org>
+---
+ pkg/procutils/proc_utils.go | 168 +++++++++++++++++++++++++++++++++---
+ 1 file changed, 155 insertions(+), 13 deletions(-)
+
+diff --git a/pkg/procutils/proc_utils.go b/pkg/procutils/proc_utils.go
+index 1236709fef6c..3075b8cb58b0 100644
+--- a/pkg/procutils/proc_utils.go
++++ b/pkg/procutils/proc_utils.go
+@@ -3,6 +3,7 @@ package procutils
+
+ import (
+ "bufio"
++ "errors"
+ "fmt"
+ "io"
+ "os"
+@@ -80,6 +81,19 @@ func EnsureFakeRoot(interactive bool) (bool, error) {
+ Setsid: true,
+ }
+
++ // Without this the detached child's output goes to /dev/null, so the
++ // reason a container failed to set up is lost and the caller only
ever
++ // sees "exit status 1".
++ startLog, logErr := os.Create(GetStartLogPath())
++ if logErr != nil {
++ logging.LogDebug("could not create start log: %v", logErr)
++ } else {
++ defer startLog.Close()
++
++ cmd.Stdout = startLog
++ cmd.Stderr = startLog
++ }
++
+ logging.LogDebug("tty not specified, using cmd.Start")
+
+ err := cmd.Start()
+@@ -92,6 +106,18 @@ func EnsureFakeRoot(interactive bool) (bool, error) {
+ logging.LogDebug("tty not specified, waiting for child to start")
+ time.Sleep(time.Millisecond * 250)
+
++ // A child that is already gone died during setup. Report what it
wrote
++ // instead of returning success and leaving a stopped container
behind.
++ if !IsPidRunning(cmd.Process.Pid) {
++ _ = cmd.Wait()
++
++ if reason := strings.TrimSpace(ReadStartLog()); reason != "" {
++ return false, errors.New("container setup failed:\n"
+ reason)
++ }
++
++ return false, fmt.Errorf("container setup failed, see %s",
GetStartLogPath())
++ }
++
+ logging.LogDebug("tty not specified, releasing child")
+
+ err = cmd.Process.Release()
+@@ -104,6 +130,37 @@ func EnsureFakeRoot(interactive bool) (bool, error) {
+ return true, nil
+ }
+
++// GetStartLogPath returns the file a detached container start writes its
++// output to, so setup failures can be reported instead of discarded.
++func GetStartLogPath() string {
++ dir := os.Getenv("XDG_DATA_HOME")
++ if dir == "" {
++ if home, err := os.UserHomeDir(); err == nil {
++ dir = filepath.Join(home, ".local", "share")
++ }
++ }
++
++ if dir == "" {
++ dir = os.TempDir()
++ } else {
++ dir = filepath.Join(dir, "lilipod")
++ }
++
++ _ = os.MkdirAll(dir, 0o755)
++
++ return filepath.Join(dir, "last-start.log")
++}
++
++// ReadStartLog returns the contents of the last detached start log.
++func ReadStartLog() string {
++ out, err := os.ReadFile(GetStartLogPath())
++ if err != nil {
++ return ""
++ }
++
++ return string(out)
++}
++
+ // GetUIDGID will return a couple of uid/gid integers for input user.
+ // Input user can be in the form of username:group, or uid:gid or a mix of
that.
+ func GetUIDGID(username string) (int, int) {
+@@ -178,6 +235,53 @@ func GetUIDGID(username string) (int, int) {
+ return 0, 0
+ }
+
++// subIDHelp is the actionable part of the error shown when a user has no
++// subordinate ID ranges. Rootless containers cannot work without them.
++const subIDHelp = "rootless containers need subordinate UID/GID ranges for
user %q.\n" +
++ "Add them with:\n" +
++ " sudo usermod --add-subuids 100000-165535 --add-subgids
100000-165535 %s\n" +
++ "or create /etc/subuid and /etc/subgid containing:\n" +
++ " %s:100000:65536"
++
++// runGetSubIDs runs getsubids and returns the first range found for
username.
++// Any failure is reported with the reason and how to fix it, because a bare
++// exit status here is indistinguishable from every other startup failure.
++func runGetSubIDs(username string, args ...string) ([]string, error) {
++ out, err := exec.Command("getsubids", args...).Output()
++ if err != nil {
++ var execErr *exec.Error
++ if errors.As(err, &execErr) {
++ return nil, fmt.Errorf(
++ "cannot run getsubids: %w\n"+
++ "It is part of shadow-utils built
with subordinate ID support, "+
++ "and is required to set up a rootless
container",
++ err)
++ }
++
++ var exitErr *exec.ExitError
++ if errors.As(err, &exitErr) {
++ reason := strings.TrimSpace(string(exitErr.Stderr))
++ if reason == "" {
++ reason = "no ranges configured"
++ }
++
++ return nil, fmt.Errorf("getsubids %s failed:
%s\n"+subIDHelp,
++ strings.Join(args, " "), reason, username,
username, username)
++ }
++
++ return nil, err
++ }
++
++ // expected output: "0: <username> <start> <count>"
++ fields := strings.Fields(string(out))
++ if len(fields) < 4 {
++ return nil, fmt.Errorf("unexpected getsubids output
%q\n"+subIDHelp,
++ string(out), username, username, username)
++ }
++
++ return fields[2:4], nil
++}
++
+ // GetSubIDRanges will return a slice of subUIDs and subGIDs for
+ // running user.
+ // This function will use the "getsubids" program to discover them.
+@@ -189,28 +293,20 @@ func GetSubIDRanges() ([]string, []string, error) {
+ return nil, nil, err
+ }
+
+- subUIDout, err := exec.Command("getsubids", user.Username).Output()
++ subUIDSlice, err := runGetSubIDs(user.Username, user.Username)
+ if err != nil {
+ logging.LogError("%v", err)
+
+ return nil, nil, err
+ }
+
+- subUIDSlice := strings.Split(
+- strings.Trim(string(subUIDout), "\n"),
+- " ")[2:]
+-
+- subGIDout, err := exec.Command("getsubids", "-g",
user.Username).Output()
++ subGIDSlice, err := runGetSubIDs(user.Username, "-g", user.Username)
+ if err != nil {
+ logging.LogError("%v", err)
+
+ return nil, nil, err
+ }
+
+- subGIDSlice := strings.Split(
+- strings.Trim(string(subGIDout), "\n"),
+- " ")[2:]
+-
+ subUIDSlice = append([]string{user.Uid}, subUIDSlice...)
+ subGIDSlice = append([]string{user.Gid}, subGIDSlice...)
+
+@@ -353,6 +449,35 @@ func RunInteractive(cmd *exec.Cmd) error {
+ return cmd.Wait()
+ }
+
++// tailLog returns the last max lines of a container log file, with the
++// "<timestamp>:out:"/"<timestamp>:err:" prefixes stripped, so a failure
can be
++// reported with the container's own output instead of just an exit status.
++func tailLog(logfile string, max int) string {
++ content, err := os.ReadFile(logfile)
++ if err != nil {
++ return ""
++ }
++
++ lines := []string{}
++
++ for _, line := range strings.Split(strings.TrimRight(string(content),
"\n"), "\n") {
++ if parts := strings.SplitN(line, ":", 3); len(parts) == 3 &&
++ (parts[1] == "out" || parts[1] == "err") {
++ line = parts[2]
++ }
++
++ if strings.TrimSpace(line) != "" {
++ lines = append(lines, line)
++ }
++ }
++
++ if len(lines) > max {
++ lines = lines[len(lines)-max:]
++ }
++
++ return strings.Join(lines, "\n")
++}
++
+ // RunDetached will run input cmd and redurect all outputs to logfile.
+ // No stdin is set up.
+ func RunDetached(cmd *exec.Cmd, logfile string) error {
+@@ -435,7 +560,9 @@ func RunDetached(cmd *exec.Cmd, logfile string) error {
+ }
+ }()
+
+- // keep an eye on the child process, and exit if dead
++ // Keep an eye on the child process: when it is gone, close the log
pipes
++ // so the readers below can finish. Exiting 0 here instead would
discard
++ // the child's exit status and make a failed start look like a
success.
+ go func() {
+ defer wg.Done()
+
+@@ -443,7 +570,13 @@ func RunDetached(cmd *exec.Cmd, logfile string) error {
+ time.Sleep(time.Second * 5)
+
+ if !IsPidRunning(cmd.Process.Pid) {
+- os.Exit(0)
++ // let the output copiers drain before
tearing the pipes down
++ time.Sleep(time.Second)
++
++ _ = outW.Close()
++ _ = errW.Close()
++
++ return
+ }
+ }
+ }()
+@@ -457,5 +590,14 @@ func RunDetached(cmd *exec.Cmd, logfile string) error {
+
+ wg.Wait()
+
+- return cmd.Wait()
++ err = cmd.Wait()
++ if err != nil {
++ if out := tailLog(logfile, 20); out != "" {
++ return fmt.Errorf("container exited: %w\n%s\n(full
log: %s)", err, out, logfile)
++ }
++
++ return fmt.Errorf("container exited: %w (output logged to
%s)", err, logfile)
++ }
++
++ return nil
+ }
diff --git
a/containers/lilipod/patches/0003-Explain-cgroup-and-mqueue-setup-failures.patch

b/containers/lilipod/patches/0003-Explain-cgroup-and-mqueue-setup-failures.patch
new file mode 100644
index 0000000..e93c5e9
--- /dev/null
+++
b/containers/lilipod/patches/0003-Explain-cgroup-and-mqueue-setup-failures.patch
@@ -0,0 +1,112 @@
+From 2a4df0c08245fd837f798fb3f8a0cee7ef5ecdb3 Mon Sep 17 00:00:00 2001
+From: Ismael Luceno <ismael AT sourcemage.org>
+Date: Sat, 15 Aug 2026 04:00:00 +0100
+Subject: [PATCH 3/5] Explain cgroup and mqueue setup failures
+
+Both of these fail on hosts that are otherwise fine, and the errno alone
+does not say what to do about it:
+
+- A host still running a cgroup v1 hierarchy cannot mount cgroup2, and a
+ user with no delegated cgroup v2 subtree gets EACCES creating its own
+ scope. Name the requirement and point at --cgroupns host.
+- A missing /dev/mqueue mountpoint on the host breaks both the private and
+ the shared IPC paths. Give the mount command and the fstab line.
+
+Upstream-Status: Pending
+Origin: Source Mage
+Signed-off-by: Ismael Luceno <ismael AT sourcemage.org>
+---
+ pkg/containerutils/rootfs_utils.go | 54 +++++++++++++++++++++++++-----
+ 1 file changed, 46 insertions(+), 8 deletions(-)
+
+diff --git a/pkg/containerutils/rootfs_utils.go
b/pkg/containerutils/rootfs_utils.go
+index 0400c2feda0c..2def3c58bb70 100644
+--- a/pkg/containerutils/rootfs_utils.go
++++ b/pkg/containerutils/rootfs_utils.go
+@@ -78,24 +78,52 @@ func setupCgroupfs(conf utils.Config) error {
+ if err != nil {
+ logging.LogDebug("error: %+v", err)
+
+- return fmt.Errorf("error setting cgroups %w", err)
++ return fmt.Errorf(
++ "cannot mount a cgroup2 filesystem: %w\n"+
++ "A unified (cgroup v2) hierarchy is required.
If this host still "+
++ "uses cgroup v1, either switch it to cgroup
v2 or run with "+
++ "--cgroupns host to skip cgroup setup",
++ err)
+ }
+
+ // move our process to a dedicated scope, so that eventual init
systems
+ // won't encour problems with unknown PIDs
+- err = os.MkdirAll("/sys/fs/cgroup/container-"+conf.Names+".scope",
0o755)
++ scope := "/sys/fs/cgroup/container-" + conf.Names + ".scope"
++
++ err = os.MkdirAll(scope, 0o755)
+ if err != nil {
+- return err
++ if os.IsPermission(err) {
++ return fmt.Errorf(
++ "cannot create cgroup %s: %w\n"+
++ "This user cannot write to its own
cgroup, so a rootless "+
++ "container cannot be placed in a
scope of its own.\n"+
++ "Delegate a writable cgroup v2
subtree to the user (see the "+
++ "\"Delegation\" section of the kernel
cgroup-v2 documentation), "+
++ "or run with --cgroupns host to skip
cgroup setup entirely",
++ scope, err)
++ }
++
++ return fmt.Errorf("cannot create cgroup %s: %w", scope, err)
+ }
+
+- file, err := os.Create("/sys/fs/cgroup/container-" + conf.Names +
".scope/cgroup.procs")
++ file, err := os.Create(scope + "/cgroup.procs")
+ if err != nil {
+- return err
++ return fmt.Errorf("cannot open %s/cgroup.procs: %w", scope,
err)
+ }
+
++ defer file.Close()
++
+ _, err = fmt.Fprint(file, 0)
++ if err != nil {
++ return fmt.Errorf(
++ "cannot move the container process into %s: %w\n"+
++ "Writing to cgroup.procs also needs write
access to the "+
++ "cgroup.procs of the common ancestor cgroup;
a properly "+
++ "delegated subtree provides this",
++ scope, err)
++ }
+
+- return err
++ return nil
+ }
+
+ // we need to setup the /dev/pts mountpoint, by mounting a new devpts
filesystem
+@@ -249,7 +277,12 @@ func setupMounts(path string, conf utils.Config) error {
+ if err != nil {
+ logging.LogDebug("error: %+v", err)
+
+- return fmt.Errorf("error setting IPC private
namespace - /dev/mqueue: %w", err)
++ return fmt.Errorf(
++ "cannot mount mqueue on %s: %w\n"+
++ "The host has no /dev/mqueue
mountpoint. Create it with:\n"+
++ " sudo mkdir -p /dev/mqueue &&
sudo mount -t mqueue mqueue /dev/mqueue\n"+
++ "and add \"mqueue /dev/mqueue mqueue
defaults\" to /etc/fstab to persist it",
++ filepath.Join(path, "/dev/mqueue"), err)
+ }
+ } else {
+ logging.LogDebug("setting up shared IPC namespace")
+@@ -268,7 +301,12 @@ func setupMounts(path string, conf utils.Config) error {
+ if err != nil {
+ logging.LogDebug("error: %+v", err)
+
+- return fmt.Errorf("error setting IPC namespace -
/dev/mqueue: %w", err)
++ return fmt.Errorf(
++ "cannot bind-mount the host's /dev/mqueue:
%w\n"+
++ "The host has no /dev/mqueue
mountpoint. Create it with:\n"+
++ " sudo mkdir -p /dev/mqueue &&
sudo mount -t mqueue mqueue /dev/mqueue\n"+
++ "and add \"mqueue /dev/mqueue mqueue
defaults\" to /etc/fstab to persist it",
++ err)
+ }
+ }
+
diff --git
a/containers/lilipod/patches/0004-cmd-rm-accept-volumes-v-flag.patch
b/containers/lilipod/patches/0004-cmd-rm-accept-volumes-v-flag.patch
new file mode 100644
index 0000000..06f907b
--- /dev/null
+++ b/containers/lilipod/patches/0004-cmd-rm-accept-volumes-v-flag.patch
@@ -0,0 +1,53 @@
+From d5a92a02ff42db6fdb4f5accbae9713174e44dc3 Mon Sep 17 00:00:00 2001
+From: Ismael Luceno <ismael AT sourcemage.org>
+Date: Tue, 22 Sep 2026 00:00:00 +0000
+Subject: [PATCH 4/5] cmd/rm: accept --volumes/-v flag
+
+Distrobox (and other podman/docker-CLI-compatible tooling) invokes
+container-manager teardown as:
+
+ <manager> rm --volumes <container>
+
+lilipod's `rm` command did not declare this flag, so cobra rejected
+the call outright with "unknown flag: --volumes", breaking distrobox
+integration (see 89luca89/distrobox issue #1710 and discussion #2199).
+
+lilipod already unconditionally removes a container's private volume
+directory ($LILIPOD_HOME/volumes/<id>) on `rm`, so this patch only
+needs to accept and parse the flag for CLI compatibility; no change
+to the removal behavior itself is required. The flag is intentionally
+not force-required to be true, matching podman/docker where `-v` is
+optional and `rm` without it still works.
+
+Upstream-Status: Pending
+Origin: Source Mage
+Signed-off-by: Ismael Luceno <ismael AT sourcemage.org>
+---
+ cmd/rm.go | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/cmd/rm.go b/cmd/rm.go
+index ae85fef4972f..a328f92a33e6 100644
+--- a/cmd/rm.go
++++ b/cmd/rm.go
+@@ -31,6 +31,7 @@ func NewRmCommand() *cobra.Command {
+ rmCommand.Flags().BoolP("force", "f", false, "force remove container")
+ rmCommand.Flags().BoolP("all", "a", false, "remove all containers")
+ rmCommand.Flags().BoolP("help", "h", false, "show help")
++ rmCommand.Flags().BoolP("volumes", "v", false, "remove anonymous
volumes associated with the container")
+
+ return rmCommand
+ }
+@@ -41,6 +42,12 @@ func rm(cmd *cobra.Command, arguments []string) error {
+ return err
+ }
+
++ // accepted for compatibility with podman/docker/distrobox; no-op
++ _, err = cmd.Flags().GetBool("volumes")
++ if err != nil {
++ return err
++ }
++
+ if force {
+ err := exec.Command(os.Args[0], append([]string{"stop",
"-f"}, arguments...)...).Run()
+ if err != nil {
diff --git
a/containers/lilipod/patches/0005-logs-don-t-truncate-the-log-file-before-reading-it.patch

b/containers/lilipod/patches/0005-logs-don-t-truncate-the-log-file-before-reading-it.patch
new file mode 100644
index 0000000..b412b1a
--- /dev/null
+++
b/containers/lilipod/patches/0005-logs-don-t-truncate-the-log-file-before-reading-it.patch
@@ -0,0 +1,58 @@
+From c2fce66fc2bf20f7ceca18b964b7722e1cf88e34 Mon Sep 17 00:00:00 2001
+From: Ismael Luceno <ismael AT iodev.co.uk>
+Date: Tue, 22 Sep 2026 20:38:22 +0000
+Subject: [PATCH 5/5] logs: don't truncate the log file before reading it
+
+logs() opened the container's current-logs file with os.Create(),
+which truncates any existing content before opening it. That file is
+the same one start (via procutils.RunDetached) already created and
+has been writing the container's stdout/stderr into, so calling
+"lilipod logs <container>" wipes it to zero bytes an instant before
+reading it back -- every invocation of "logs" destroys the very
+output it's supposed to show, and returns nothing.
+
+This is especially harmful when a container fails during rootfs
+setup, before the entrypoint process starts: that failure is the
+only diagnostic ever written for the container, and "logs" erases
+it on the first read. Front-ends like distrobox, which call "logs"
+right after a failed "start" specifically to explain what went
+wrong to the user, end up printing nothing instead.
+
+Only create the file if it doesn't exist yet, mirroring what "logs"
+already does two lines above when checking the container exists.
+
+Upstream-Status: Pending
+Signed-off-by: Ismael Luceno <ismael AT sourcemage.org>
+---
+ cmd/logs.go | 16 +++++++++++++---
+ 1 file changed, 13 insertions(+), 3 deletions(-)
+
+diff --git a/cmd/logs.go b/cmd/logs.go
+index a356919..3c9e795 100644
+--- a/cmd/logs.go
++++ b/cmd/logs.go
+@@ -65,9 +65,19 @@ func logs(cmd *cobra.Command, arguments []string) error {
+ return err
+ }
+
+- _, err = os.Create(containerutils.GetDir(container) + "/current-logs")
+- if err != nil {
+- return err
++ // Ensure the log file exists, but do not truncate it if it's already
++ // there. "start" (via procutils.RunDetached) already created this
++ // file and wrote the container's stdout/stderr into it; blindly
++ // os.Create()-ing it here truncates that content to zero bytes right
++ // before we open it for reading, so every "logs" call -- including
++ // the one distrobox makes right after a failed "start" to explain
++ // what went wrong -- silently returns nothing, destroying the very
++ // diagnostic it was trying to show.
++ if !fileutils.Exist(containerutils.GetDir(container) +
"/current-logs") {
++ _, err = os.Create(containerutils.GetDir(container) +
"/current-logs")
++ if err != nil {
++ return err
++ }
+ }
+
+ file, err := os.Open(containerutils.GetDir(container) +
"/current-logs")
+--
+2.43.0


  • [[SM-Commit] ] GIT changes to master grimoire by Ismael Luceno (c1ebe7e232b4310ec6ec875c1e6f00501473d8e3), Ismael Luceno, 09/22/2026

Archive powered by MHonArc 2.6.24.

Top of Page