--- /dev/null
+// go:build openbsd
+
+package hostname
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "net"
+ "os"
+ "strings"
+ "time"
+
+ "go.fuhry.dev/runtime/constants"
+ "go.fuhry.dev/runtime/utils/log"
+)
+
+var defaultDomainName = constants.DefaultHostDomain
+var cachedFqdn string
+
+func Hostname() string {
+ fqdn := Fqdn()
+ return strings.Split(fqdn, ".")[0]
+}
+
+func DomainName() string {
+ fqdn := strings.Split(Fqdn(), ".")
+ if len(fqdn) > 1 {
+ return strings.Join(fqdn[1:], ".")
+ }
+ return defaultDomainName
+}
+
+func RegionName() string {
+ return strings.Split(DomainName(), ".")[0]
+}
+
+func Fqdn() string {
+ if cachedFqdn != "" {
+ return cachedFqdn
+ }
+ cachedFqdn = fqdn()
+ return cachedFqdn
+}
+
+func fqdn() string {
+ myName, myNameErr := os.ReadFile("/etc/myname")
+ if myNameErr == nil {
+ return maybeAppendDefaultDomainName(strings.Trim(string(myName), " \r\n"))
+ }
+
+ dnsFqdn, dnsErr := fqdnFromDns()
+ if dnsErr == nil {
+ return maybeAppendDefaultDomainName(dnsFqdn)
+ }
+
+ log.Panicf("failed to get fqdn: myname failed because %q, and dns failed because %q", myNameErr.Error(), dnsErr.Error())
+ return ""
+}
+
+func maybeAppendDefaultDomainName(name string) string {
+ parts := strings.Split(name, ".")
+ if len(parts) < 2 {
+ name = fmt.Sprintf("%s.%s", parts[0], defaultDomainName)
+ }
+
+ log.Default().V(1).Noticef("detected system hostname: %q", name)
+
+ return name
+}
+
+func fqdnFromDns() (string, error) {
+ resolver := &net.Resolver{}
+
+ ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
+ defer cancel()
+
+ result, err := resolver.LookupAddr(ctx, "127.0.0.1")
+ if err != nil {
+ return "", fmt.Errorf("failed to lookup hostname for 127.0.0.1: %v", err)
+ }
+
+ for _, name := range result {
+ parts := strings.Split(name, ".")
+ if parts[0] != "localhost" {
+ return parts[0], nil
+ }
+ }
+
+ return "", errors.New("failed to lookup any hostname for 127.0.0.1 that does not resolve to just \"localhost\"")
+}