git.sr.ht/~pingoo/stdx@v0.0.0-20240218134121-094174641f6e/sysinfo/node.go (about) 1 // Copyright © 2016 Zlatko Čalušić 2 // 3 // Use of this source code is governed by an MIT-style license that can be found in the LICENSE file. 4 5 package sysinfo 6 7 import ( 8 "bufio" 9 "crypto/rand" 10 "fmt" 11 "os" 12 "strings" 13 "time" 14 ) 15 16 // Node information. 17 type Node struct { 18 Hostname string `json:"hostname,omitempty"` 19 MachineID string `json:"machineid,omitempty"` 20 Hypervisor string `json:"hypervisor,omitempty"` 21 Timezone string `json:"timezone,omitempty"` 22 } 23 24 func (si *SysInfo) getHostname() { 25 si.Node.Hostname = slurpFile("/proc/sys/kernel/hostname") 26 } 27 28 func (si *SysInfo) getSetMachineID() { 29 const pathSystemdMachineID = "/etc/machine-id" 30 const pathDbusMachineID = "/var/lib/dbus/machine-id" 31 32 systemdMachineID := slurpFile(pathSystemdMachineID) 33 dbusMachineID := slurpFile(pathDbusMachineID) 34 35 if systemdMachineID != "" && dbusMachineID != "" { 36 // All OK, just return the machine id. 37 if systemdMachineID == dbusMachineID { 38 si.Node.MachineID = systemdMachineID 39 return 40 } 41 42 // They both exist, but they don't match! Copy systemd machine id to DBUS machine id. 43 spewFile(pathDbusMachineID, systemdMachineID, 0444) 44 si.Node.MachineID = systemdMachineID 45 return 46 } 47 48 // Copy DBUS machine id to non-existent systemd machine id. 49 if systemdMachineID == "" && dbusMachineID != "" { 50 spewFile(pathSystemdMachineID, dbusMachineID, 0444) 51 si.Node.MachineID = dbusMachineID 52 return 53 } 54 55 // Copy systemd machine id to non-existent DBUS machine id. 56 if systemdMachineID != "" && dbusMachineID == "" { 57 spewFile(pathDbusMachineID, systemdMachineID, 0444) 58 si.Node.MachineID = systemdMachineID 59 return 60 } 61 62 // Generate and write fresh new machine ID to both locations, conforming to the DBUS specification: 63 // https://dbus.freedesktop.org/doc/dbus-specification.html#uuids 64 65 random := make([]byte, 12) 66 if _, err := rand.Read(random); err != nil { 67 return 68 } 69 newMachineID := fmt.Sprintf("%x%x", random, time.Now().Unix()) 70 71 spewFile(pathSystemdMachineID, newMachineID, 0444) 72 spewFile(pathDbusMachineID, newMachineID, 0444) 73 si.Node.MachineID = newMachineID 74 } 75 76 func (si *SysInfo) getTimezone() { 77 const zoneInfoPrefix = "/usr/share/zoneinfo/" 78 79 if fi, err := os.Lstat("/etc/localtime"); err == nil { 80 if fi.Mode()&os.ModeSymlink == os.ModeSymlink { 81 if tzfile, err := os.Readlink("/etc/localtime"); err == nil { 82 tzfile = strings.TrimPrefix(tzfile, "..") 83 if strings.HasPrefix(tzfile, zoneInfoPrefix) { 84 si.Node.Timezone = strings.TrimPrefix(tzfile, zoneInfoPrefix) 85 return 86 } 87 } 88 } 89 } 90 91 if timezone := slurpFile("/etc/timezone"); timezone != "" { 92 si.Node.Timezone = timezone 93 return 94 } 95 96 if f, err := os.Open("/etc/sysconfig/clock"); err == nil { 97 defer f.Close() 98 s := bufio.NewScanner(f) 99 for s.Scan() { 100 if sl := strings.Split(s.Text(), "="); len(sl) == 2 { 101 if sl[0] == "ZONE" { 102 si.Node.Timezone = strings.Trim(sl[1], `"`) 103 return 104 } 105 } 106 } 107 } 108 } 109 110 func (si *SysInfo) getNodeInfo() { 111 si.getHostname() 112 si.getSetMachineID() 113 si.getHypervisor() 114 si.getTimezone() 115 }