diff --git a/cmd/earlyinit/main.go b/cmd/earlyinit/main.go index b5e8bcde..00c4807a 100644 --- a/cmd/earlyinit/main.go +++ b/cmd/earlyinit/main.go @@ -242,5 +242,6 @@ func main() { []byte("/system/lib/firmware"), 0, )) + go dispatchModprobe(ctx, s) } diff --git a/cmd/earlyinit/modprobe.go b/cmd/earlyinit/modprobe.go new file mode 100644 index 00000000..5a9868d4 --- /dev/null +++ b/cmd/earlyinit/modprobe.go @@ -0,0 +1,73 @@ +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( + "modprobe exit status %d: %s", + e.ExitCode, strings.TrimSpace(e.Stderr), + ) +} + +// 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 + } + + var exitError *exec.ExitError + if !errors.As(err, &exitError) || 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(), + }) + } +}