forked from rosa/hakurei
This is not a great way to implement cold boot, but I already have the implementation lying around. Signed-off-by: Ophestra <cat@gensokyo.uk>
88 lines
1.7 KiB
Go
88 lines
1.7 KiB
Go
package uevent
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"io/fs"
|
|
"log"
|
|
"path/filepath"
|
|
"unsafe"
|
|
)
|
|
|
|
// Enumerate scans sysfs and emits [Synthetic] events. It returns the first
|
|
// error it encounters.
|
|
//
|
|
// The specified filesystem must present the sysfs root.
|
|
func Enumerate(
|
|
sysfs fs.FS,
|
|
handleWalkErr func(error) error,
|
|
events chan<- *Message,
|
|
) error {
|
|
if handleWalkErr == nil {
|
|
handleWalkErr = func(err error) error {
|
|
if errors.Is(err, fs.ErrNotExist) {
|
|
log.Println("enumerate", err)
|
|
return nil
|
|
}
|
|
return err
|
|
}
|
|
}
|
|
|
|
return fs.WalkDir(sysfs, "devices", func(
|
|
path string,
|
|
d fs.DirEntry,
|
|
err error,
|
|
) error {
|
|
if err != nil {
|
|
return handleWalkErr(err)
|
|
}
|
|
|
|
if d.IsDir() || d.Name() != "uevent" {
|
|
return nil
|
|
}
|
|
|
|
msg := Message{
|
|
Action: Synthetic,
|
|
|
|
// cleans path, appears to be compatible with kernel behaviour
|
|
DevPath: filepath.Dir(path),
|
|
}
|
|
|
|
var target string
|
|
if target, err = fs.ReadLink(
|
|
sysfs,
|
|
filepath.Join(msg.DevPath, "subsystem"),
|
|
); err != nil {
|
|
if err = handleWalkErr(err); err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
msg.Env = append(msg.Env, "SUBSYSTEM="+filepath.Base(target))
|
|
}
|
|
|
|
// read entire file: slicing does not copy
|
|
var env []byte
|
|
if env, err = fs.ReadFile(sysfs, path); err != nil {
|
|
return handleWalkErr(err)
|
|
}
|
|
|
|
for _, s := range bytes.Split(env, []byte{'\n'}) {
|
|
if len(s) == 0 {
|
|
continue
|
|
}
|
|
msg.Env = append(msg.Env, unsafe.String(unsafe.SliceData(s), len(s)))
|
|
}
|
|
|
|
if len(msg.Env) == 0 {
|
|
// this implies absent subsystem, its error is already handled
|
|
return nil
|
|
}
|
|
|
|
if msg.DevPath != "" && msg.DevPath[0] != '/' {
|
|
msg.DevPath = "/" + msg.DevPath
|
|
}
|
|
events <- &msg
|
|
return nil
|
|
})
|
|
}
|