aboutsummaryrefslogtreecommitdiffhomepage
path: root/cmd/earlyinit/modprobe.go
blob: 8194c150231b4805ccd472927245716ae2bd1e3e (plain)
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
package main

import (
	"context"
	"errors"
	"fmt"
	"log"
	"os/exec"
	"strings"

	"hakurei.app/internal/kobject"
	"hakurei.app/internal/report"
	"hakurei.app/internal/uevent"
)

// ModprobeError describes an unsuccessful modprobe invocation.
type ModprobeError struct {
	ModAlias string `json:"modalias"`
	Stdout   string `json:"stdout"`
	Stderr   string `json:"stderr"`
	ExitCode int    `json:"exit_code"`
}

var _ report.RepresentableError = ModprobeError{}

func (ModprobeError) Representable() {}
func (e ModprobeError) Error() string {
	return fmt.Sprintf(
		"%s (exit status %d)",
		strings.TrimPrefix(strings.TrimSpace(e.Stderr), "modprobe: "),
		e.ExitCode,
	)
}

// dispatchModprobe invokes modprobe for [uevent.KOBJ_ADD] events raising new
// MODALIAS strings.
func dispatchModprobe(
	ctx context.Context,
	s *kobject.State,
) {
	aliases := make(chan string, 1<<8)
	go func() {
		defer close(aliases)
		s.Range(ctx, func(o *kobject.Object, act uevent.KobjectAction) bool {
			if act == uevent.KOBJ_ADD && o.Driver == "" && o.ModAlias != "" {
				aliases <- o.ModAlias
			}
			return true
		})
	}()

	for alias := range aliases {
		stdout, err := exec.Command("/system/sbin/modprobe", alias).Output()
		if err == nil {
			if len(stdout) > 0 {
				log.Println(string(stdout))
			}
			continue
		}

		exitError, ok := errors.AsType[*exec.ExitError](err)
		if !ok || exitError == nil {
			r.Dispatch(report.Degraded, "invoke modprobe", err)
			continue
		}

		r.Dispatch(report.Trivial, "load device driver", ModprobeError{
			ModAlias: alias,
			Stdout:   string(stdout),
			Stderr:   string(exitError.Stderr),
			ExitCode: exitError.ExitCode(),
		})
	}
}