File: binfmt.go

package info (click to toggle)
golang-github-containers-buildah 1.39.3%2Bds1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 7,724 kB
  • sloc: sh: 2,398; makefile: 236; perl: 187; asm: 16; awk: 12; ansic: 1
file content (83 lines) | stat: -rw-r--r-- 2,705 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
//go:build linux

package binfmt

import (
	"bufio"
	"errors"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"syscall"

	"github.com/containers/storage/pkg/unshare"
	"github.com/sirupsen/logrus"
	"golang.org/x/sys/unix"
)

// MaybeRegister() calls Register() if the current context is a rootless one,
// or if the "container" environment variable suggests that we're in a
// container.
func MaybeRegister(configurationSearchDirectories []string) error {
	if unshare.IsRootless() || os.Getenv("container") != "" { // we _also_ own our own mount namespace
		return Register(configurationSearchDirectories)
	}
	return nil
}

// Register() registers binfmt.d emulators described by configuration files in
// the passed-in slice of directories, or in the union of /etc/binfmt.d,
// /run/binfmt.d, and /usr/lib/binfmt.d if the slice has no items.  If any
// emulators are configured, it will attempt to mount a binfmt_misc filesystem
// in the current mount namespace first, ignoring only EPERM and EACCES errors.
func Register(configurationSearchDirectories []string) error {
	if len(configurationSearchDirectories) == 0 {
		configurationSearchDirectories = []string{"/etc/binfmt.d", "/run/binfmt.d", "/usr/lib/binfmt.d"}
	}
	mounted := false
	for _, searchDir := range configurationSearchDirectories {
		globs, err := filepath.Glob(filepath.Join(searchDir, "*.conf"))
		if err != nil {
			return fmt.Errorf("looking for binfmt.d configuration in %q: %w", searchDir, err)
		}
		for _, conf := range globs {
			f, err := os.Open(conf)
			if err != nil {
				return fmt.Errorf("reading binfmt.d configuration: %w", err)
			}
			scanner := bufio.NewScanner(f)
			for scanner.Scan() {
				line := strings.TrimSpace(scanner.Text())
				if len(line) == 0 || line[0] == ';' || line[0] == '#' {
					continue
				}
				if !mounted {
					if err = unix.Mount("none", "/proc/sys/fs/binfmt_misc", "binfmt_misc", 0, ""); err != nil {
						if errors.Is(err, syscall.EPERM) || errors.Is(err, syscall.EACCES) {
							// well, we tried. no need to make a stink about it
							return nil
						}
						return fmt.Errorf("mounting binfmt_misc: %w", err)
					}
					mounted = true
				}
				reg, err := os.Create("/proc/sys/fs/binfmt_misc/register")
				if err != nil {
					return fmt.Errorf("registering(open): %w", err)
				}
				if _, err = fmt.Fprintf(reg, "%s\n", line); err != nil {
					return fmt.Errorf("registering(write): %w", err)
				}
				logrus.Tracef("registered binfmt %q", line)
				if err = reg.Close(); err != nil {
					return fmt.Errorf("registering(close): %w", err)
				}
			}
			if err := f.Close(); err != nil {
				return fmt.Errorf("reading binfmt.d configuration: %w", err)
			}
		}
	}
	return nil
}