// w1-therm is a gokrazy helper that loads 1-wire kernel modules on boot.
//
// Example:
//
//	Include the w1-therm package in your gokr-packer command:
//	% gokr-packer -update=yes \
//	  github.com/gokrazy/breakglass \
//	  git.joco.dk/snr/fermentord/cmd/w1-therm
package main

import (
	"bytes"
	"flag"
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strings"

	"golang.org/x/sys/unix"
)

func logic() error {
	flag.Parse()

	for _, mod := range []string{
		"kernel/drivers/w1/wire.ko",
		"kernel/drivers/w1/masters/w1-gpio.ko",
		"kernel/drivers/w1/slaves/w1-therm.ko",
	} {
		if err := loadModule(mod); err != nil && !os.IsNotExist(err) {
			return err
		}
	}

	dev := "w1_bus_master1"
	target, err := checkOneWireInterface(dev)
	if err != nil {
		log.Printf("Bluetooth interface %v not found.", target)
	} else {
		fmt.Printf("Bluetooth device %v: %v\n", dev, target)
	}

	// gokrazy should not supervise this process even when manually started.
	os.Exit(125)
	return nil
}

func checkOneWireInterface(device string) (string, error) {
	name := fmt.Sprintf("/sys/bus/w1/devices/%v", device)
	target, err := os.Readlink(name)
	if err != nil {
		return "", fmt.Errorf("OneWire bus master %v not found", device)
	}
	return target, nil
}

func loadModule(mod string) error {
	f, err := os.Open(filepath.Join("/lib/modules", release, mod))
	if err != nil {
		return err
	}
	defer f.Close()

	if err := unix.FinitModule(int(f.Fd()), "", 0); err != nil {
		if err != unix.EEXIST &&
			err != unix.EBUSY &&
			err != unix.ENODEV &&
			err != unix.ENOENT {
			return fmt.Errorf("FinitModule(%v): %v", mod, err)
		}
	}
	modname := strings.TrimSuffix(filepath.Base(mod), ".ko")
	log.Printf("modprobe %v", modname)
	return nil
}

var release = func() string {
	var uts unix.Utsname
	if err := unix.Uname(&uts); err != nil {
		fmt.Fprintf(os.Stderr, "minitrd: %v\n", err)
		os.Exit(1)
	}
	return string(uts.Release[:bytes.IndexByte(uts.Release[:], 0)])
}()

func main() {
	if err := logic(); err != nil {
		log.Fatal(err)
	}
}
