package mod import ( "errors" "fmt" "io" "os" "path/filepath" "strings" "github.com/klauspost/compress/zstd" "github.com/klauspost/pgzip" "github.com/ulikunitz/xz" "golang.org/x/sys/unix" ) var ( ErrModuleInfoNotFound = errors.New("module info not found") ErrCircularDependency = errors.New("circular dependency") ) func initDependencies(path string, modulesInfo map[string]moduleInfo) (err error) { info, ok := modulesInfo[path] if !ok { return fmt.Errorf("%w: %s", ErrModuleInfoNotFound, path) } switch info.state { case unloaded: case loaded, builtin: return nil case loading: return fmt.Errorf("%w: %s is already in the loading state", ErrCircularDependency, path) } info.state = loading modulesInfo[path] = info for _, dependencyPath := range info.dependencyPaths { err = initDependencies(dependencyPath, modulesInfo) if err != nil { return fmt.Errorf("init dependencies for %s: %w", path, err) } } err = initModule(path) if err != nil { return fmt.Errorf("loading module: %w", err) } info.state = loaded modulesInfo[path] = info return nil } func initModule(path string) (err error) { file, err := os.Open(path) if err != nil { return fmt.Errorf("opening module file: %w", err) } defer func() { _ = file.Close() }() var reader io.Reader switch filepath.Ext(file.Name()) { case ".xz": reader, err = xz.NewReader(file) case ".gz": reader, err = pgzip.NewReader(file) case ".zst": reader, err = zstd.NewReader(file) default: const moduleParams = "" const flags = 0 err = unix.FinitModule(int(file.Fd()), moduleParams, flags) switch { case err == nil, err == unix.EEXIST: //nolint:err113 return nil case err != unix.ENOSYS: //nolint:err113 if strings.HasSuffix(err.Error(), "operation not permitted") { err = fmt.Errorf("%w; did you set the SYS_MODULE capability to your container?", err) } return fmt.Errorf("finit module %s: %w", path, err) case flags != 0: return err // unix.ENOSYS error default: // Fall back to init_module(2). reader = file } } if err != nil { return fmt.Errorf("reading from %s: %w", path, err) } image, err := io.ReadAll(reader) if err != nil { return fmt.Errorf("reading module image from %s: %w", path, err) } err = file.Close() if err != nil { return fmt.Errorf("closing module file %s: %w", path, err) } const params = "" err = unix.InitModule(image, params) switch err { case nil, unix.EEXIST: return nil default: return fmt.Errorf("init module read from %s: %w", path, err) } }