Files
podman/pkg/specgen/generate/config_freebsd.go
Paul Holzinger c1b6effac5 add !remote tag to pkg/specgen/generate
These files should never be included on the remote client. There only
there to finalize the spec on the server side.

This makes sure it will not get reimported by accident and bloat the
remote client again.

Signed-off-by: Paul Holzinger <pholzing@redhat.com>
2023-09-14 11:21:00 +02:00

122 lines
3.3 KiB
Go

//go:build !remote
// +build !remote
package generate
import (
"fmt"
"io/fs"
"os"
"path/filepath"
"strings"
"github.com/container-orchestrated-devices/container-device-interface/pkg/cdi"
"github.com/opencontainers/runtime-tools/generate"
"github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
)
// DevicesFromPath computes a list of devices
func DevicesFromPath(g *generate.Generator, devicePath string) error {
if isCDIDevice(devicePath) {
registry := cdi.GetRegistry(
cdi.WithAutoRefresh(false),
)
if err := registry.Refresh(); err != nil {
logrus.Debugf("The following error was triggered when refreshing the CDI registry: %v", err)
}
_, err := registry.InjectDevices(g.Config, devicePath)
if err != nil {
return fmt.Errorf("setting up CDI devices: %w", err)
}
return nil
}
devs := strings.Split(devicePath, ":")
resolvedDevicePath := devs[0]
// check if it is a symbolic link
if src, err := os.Lstat(resolvedDevicePath); err == nil && src.Mode()&os.ModeSymlink == os.ModeSymlink {
if linkedPathOnHost, err := filepath.EvalSymlinks(resolvedDevicePath); err == nil {
resolvedDevicePath = linkedPathOnHost
}
}
st, err := os.Stat(resolvedDevicePath)
if err != nil {
return err
}
if st.IsDir() {
// For devfs, we need to add the directory as well
addDevice(g, resolvedDevicePath)
found := false
src := resolvedDevicePath
dest := src
var devmode string
if len(devs) > 1 {
if len(devs[1]) > 0 && devs[1][0] == '/' {
dest = devs[1]
} else {
devmode = devs[1]
}
}
if len(devs) > 2 {
if devmode != "" {
return fmt.Errorf("invalid device specification %s: %w", devicePath, unix.EINVAL)
}
devmode = devs[2]
}
// mount the internal devices recursively
if err := filepath.WalkDir(resolvedDevicePath, func(dpath string, d fs.DirEntry, e error) error {
if d.Type()&os.ModeDevice == os.ModeDevice {
found = true
device := fmt.Sprintf("%s:%s", dpath, filepath.Join(dest, strings.TrimPrefix(dpath, src)))
if devmode != "" {
device = fmt.Sprintf("%s:%s", device, devmode)
}
if err := addDevice(g, device); err != nil {
return fmt.Errorf("failed to add %s device: %w", dpath, err)
}
}
return nil
}); err != nil {
return err
}
if !found {
return fmt.Errorf("no devices found in %s: %w", devicePath, unix.EINVAL)
}
return nil
}
return addDevice(g, strings.Join(append([]string{resolvedDevicePath}, devs[1:]...), ":"))
}
func addDevice(g *generate.Generator, device string) error {
src, dst, permissions, err := ParseDevice(device)
if err != nil {
return err
}
if src != dst {
return fmt.Errorf("container device must be the same as host device on FreeBSD")
}
mode := 0
if strings.Contains(permissions, "r") {
mode |= unix.S_IRUSR
}
if strings.Contains(permissions, "w") {
mode |= unix.S_IWUSR
}
// Find the devfs mount so that we can add rules to expose the device
for k, m := range g.Config.Mounts {
if m.Type == "devfs" {
if dev, ok := strings.CutPrefix(src, "/dev/"); ok {
m.Options = append(m.Options,
fmt.Sprintf("rule=path %s unhide mode %04o", dev, mode))
} else {
return fmt.Errorf("expected device to start with \"/dev\": %v", dev)
}
g.Config.Mounts[k] = m
return nil
}
}
return fmt.Errorf("devfs not found in generator")
}