84 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			84 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			Go
		
	
	
	
| //go:build linux
 | |
| 
 | |
| package binfmt
 | |
| 
 | |
| import (
 | |
| 	"bufio"
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 	"os"
 | |
| 	"path/filepath"
 | |
| 	"strings"
 | |
| 	"syscall"
 | |
| 
 | |
| 	"github.com/sirupsen/logrus"
 | |
| 	"go.podman.io/storage/pkg/unshare"
 | |
| 	"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
 | |
| }
 |