157 lines
3.8 KiB
Go
157 lines
3.8 KiB
Go
// Binary podman is a gokrazy wrapper program that runs the bundled podman
|
|
// executable in /usr/local/bin/podman after doing any necessary runtime system
|
|
// setup.
|
|
package main
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io/fs"
|
|
"io/ioutil"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"syscall"
|
|
|
|
"slices"
|
|
)
|
|
|
|
func isMounted(mountpoint string) (bool, error) {
|
|
b, err := ioutil.ReadFile("/proc/self/mountinfo")
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
return false, nil // platform does not have /proc/self/mountinfo, fall back to not verifying
|
|
}
|
|
return false, err
|
|
}
|
|
|
|
for _, line := range strings.Split(strings.TrimSpace(string(b)), "\n") {
|
|
parts := strings.Fields(line)
|
|
if len(parts) < 5 {
|
|
continue
|
|
}
|
|
if filepath.Clean(parts[4]) == filepath.Clean(mountpoint) {
|
|
return true, nil
|
|
}
|
|
}
|
|
|
|
return false, nil
|
|
}
|
|
|
|
func makeWritable(dir string) error {
|
|
mounted, err := isMounted(dir)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if mounted {
|
|
// Nothing to do, directory is already mounted.
|
|
return nil
|
|
}
|
|
|
|
// Read all regular files in this directory.
|
|
regularFiles := make(map[string]string)
|
|
fis, err := os.ReadDir(dir)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, fi := range fis {
|
|
b, err := os.ReadFile(filepath.Join(dir, fi.Name()))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
regularFiles[fi.Name()] = string(b)
|
|
}
|
|
|
|
if err := mount_tmpfs(dir); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Write all regular files from memory back to new tmpfs.
|
|
for name, contents := range regularFiles {
|
|
if err := os.WriteFile(filepath.Join(dir, name), []byte(contents), 0644); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func mount_tmpfs(dest string) error {
|
|
if mounted, err := isMounted(dest); err == nil && mounted {
|
|
return nil
|
|
}
|
|
if err := syscall.Mount("tmpfs", dest, "tmpfs", syscall.MS_NOSUID|syscall.MS_RELATIME, "size=5G"); err != nil {
|
|
return fmt.Errorf("mounting tmpfs to %s: %v", dest, err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// expandPath returns env, but with PATH= modified or added
|
|
// such that both /user and /usr/local/bin are included, which podman needs.
|
|
func expandPath(env []string) []string {
|
|
extra := []string{"/user", "/perm/bin", "/usr/local/bin"}
|
|
found := false
|
|
for idx, val := range env {
|
|
val, IsPATH := strings.CutPrefix(val, "PATH=")
|
|
if !IsPATH {
|
|
continue
|
|
}
|
|
paths := filepath.SplitList(val)
|
|
for i, path := range paths {
|
|
paths[i] = filepath.Clean(path)
|
|
}
|
|
for _, path := range extra {
|
|
if !slices.Contains(paths, path) {
|
|
paths = append(paths, path)
|
|
}
|
|
}
|
|
val = strings.Join(paths, ":")
|
|
env[idx] = "PATH=" + val
|
|
found = true
|
|
}
|
|
if !found {
|
|
const busyboxDefaultPATH = "/usr/local/sbin:/sbin:/usr/sbin:/bin:/usr/bin"
|
|
env = append(env, fmt.Sprintf("PATH=%s:%s", busyboxDefaultPATH, strings.Join(extra, ":")))
|
|
}
|
|
return env
|
|
}
|
|
|
|
func makeSymlinks() error {
|
|
if err := os.Symlink("/proc/self/fd/0", "/dev/stdin"); err != nil && !errors.Is(err, fs.ErrExist) {
|
|
return err
|
|
}
|
|
if err := os.Symlink("/proc/self/fd/1", "/dev/stdout"); err != nil && !errors.Is(err, fs.ErrExist) {
|
|
return err
|
|
}
|
|
if err := os.Symlink("/proc/self/fd/2", "/dev/stderr"); err != nil && !errors.Is(err, fs.ErrExist) {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func main() {
|
|
// podman fails without these directories
|
|
if err := makeWritable("/etc/containers/networks/"); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
if err := os.MkdirAll("/var/lib/containers/storage/volumes", 0o777); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
// catatonit needs /var/tmp for the pause container
|
|
if err := os.MkdirAll("/var/tmp", 0o777); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
// podman default socket location is /run/podman/podman.sock
|
|
if err := os.MkdirAll("/run/podman/", 0o770); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
if err := makeSymlinks(); err != nil {
|
|
return
|
|
}
|
|
|
|
if err := syscall.Exec("/usr/local/bin/podman", os.Args, expandPath(os.Environ())); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|