From 5c91928bd5cc36d64d9c72f28b53e29e02f20027 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Thu, 9 Nov 2023 13:46:53 -0800 Subject: [PATCH] fix: recognize kernel mount failure when target already mounted. (#539) In a single stacker file that used a squashfs image twice or more, stacker would mount the layers the first time correctly. The image build would fail. The reason was that maybeKernelSquashMount did not detected *why* the mount failed (it was already mounted), but only that it did fail. So the code then attempted to extract the squashfs layer with unsquashfs and an error would occur like: FATAL ERROR: dir_scan: failed to change permissions for directory .../roots/sha256_52068a5d6c1...02caeb3a706cba3a/overlay, because Read-only file system Parallel unsquashfs: Using 32 processors 691 inodes (966 blocks) to write The error only actually occurs if: * user is priveleged (can do a kernel mount) * stacker is building squash images (--layer-type=squashfs) * user does not have squashfuse in their path. This is fixed more correctly upstream in 565b0320651ae243a0c6f3f4a59cf384c92b336a. An example stacker file that would recreate: b1: build_only: true from: type: docker url: oci:my-ocidir:base:latest-squashfs run: | echo "hello world" > f1 b2: from: type: docker url: oci:my-ocidir:base:latest-squashfs run: | echo "goodbye" > f2 The fix here is not great... effectively grepping the output of 'mount' for 'is already mounted'. We set the LANG environment variable to C to avoid failures due to a translations. Signed-off-by: Scott Moser --- pkg/squashfs/squashfs.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pkg/squashfs/squashfs.go b/pkg/squashfs/squashfs.go index aa710d9f..951a5f21 100644 --- a/pkg/squashfs/squashfs.go +++ b/pkg/squashfs/squashfs.go @@ -190,6 +190,7 @@ func maybeKernelSquashMount(squashFile, extractDir string) (bool, error) { ecmd := []string{"mount", "-tsquashfs", "-oloop,ro", squashFile, extractDir} var output bytes.Buffer cmd := exec.Command(ecmd[0], ecmd[1:]...) + cmd.Env = append(cmd.Environ(), "LANG=C") cmd.Stdin = nil cmd.Stdout = &output cmd.Stderr = cmd.Stdout @@ -209,6 +210,10 @@ func maybeKernelSquashMount(squashFile, extractDir string) (bool, error) { return false, errors.Errorf("Unexpected error (no-status) in exec (%v): %v", ecmd, err) } + if status.ExitStatus() == 1 && strings.Contains(output.String(), "is already mounted") { + return true, nil + } + // we can't really tell why the mount failed. mount(8) does not give a lot specific rc exits. log.Debugf("maybeKernelSquashMount(%s) exited %d: %s\n", squashFile, status.ExitStatus(), output.String()) return false, kernelSquashMountFailed