all_platform/vendor/github.com/super-l/machine-code/goos/linux.go
2025-03-16 23:57:25 +08:00

270 lines
5.9 KiB
Go

//go:build linux
// +build linux
package goos
import (
"bytes"
"crypto/md5"
"encoding/hex"
"errors"
"fmt"
"github.com/super-l/machine-code/types"
"os"
"os/exec"
"path/filepath"
"strings"
)
type LinuxMachine struct{}
const DiskByIDPath = "/dev/disk/by-id/"
const DiskByUUIDPath = "/dev/disk/by-uuid/"
func (linux LinuxMachine) GetMachine() (types.MachineInformation, []error) {
var errs []error
platformUUID, err := linux.GetUUID()
if err != nil {
errs = append(errs, err)
}
boardSerialNumber, err := linux.GetBoardSerialNumber()
if err != nil {
errs = append(errs, err)
}
cpuSerialNumber, err := linux.GetCpuSerialNumber()
if err != nil {
errs = append(errs, err)
}
diskSerialNumber, err := linux.GetDiskSerialNumber()
if err != nil {
errs = append(errs, err)
}
macAddr, err := GetMACAddress()
if err != nil {
errs = append(errs, err)
}
machineData := types.MachineInformation{
UUID: platformUUID,
BoardSerialNumber: boardSerialNumber,
CpuSerialNumber: cpuSerialNumber,
DiskSerialNumber: diskSerialNumber,
Mac: macAddr,
}
return machineData, errs
}
// 主板序列码
func (linux LinuxMachine) GetBoardSerialNumber() (serialNumber string, err error) {
// dmidecode -s system-serial-number
var cmd *exec.Cmd
cmd = exec.Command("dmidecode", "-s", "system-serial-number")
var out bytes.Buffer
cmd.Stdout = &out
cmd.Stderr = os.Stderr
err = cmd.Start()
if err != nil {
return "", err
}
err = cmd.Wait()
if err == nil {
serial_number := out.String()
serial_number = strings.Replace(serial_number, "\n", "", -1)
return serial_number, nil
}
return "", err
}
// CPU序列码
func (linux LinuxMachine) GetCpuSerialNumber() (cpuId string, err error) {
// dmidecode -t processor |grep ID |head -1
cmds := []*exec.Cmd{
exec.Command("dmidecode", "-t", "processor"),
exec.Command("grep", "ID"),
exec.Command("head", "-1"),
}
cpuId, err = linux.execPipeLine(cmds...)
cpuId = strings.TrimSpace(cpuId)
cpuId = strings.Replace(cpuId, "ID: ", "", -1)
cpuId = strings.Replace(cpuId, "\t", "", -1)
cpuId = strings.Replace(cpuId, "\n", "", -1)
cpuId = strings.Replace(cpuId, " ", "-", -1)
return
}
// 获取硬盘编号
func (linux LinuxMachine) GetDiskSerialNumber() (serialNumber string, err error) {
id, err1 := linux.GetDiskSerialNumberById()
uuid, err2 := linux.GetDiskSerialNumberByUUID()
if err1 != nil && err2 != nil {
return "", err1
}
return fmt.Sprintf("id:%s uuid_md5:%s", id, uuid), nil
}
// 获取硬盘编号
func (linux LinuxMachine) GetDiskSerialNumberById() (serialNumber string, err error) {
// ls /dev/disk/by-id -al
entries, err := os.ReadDir(DiskByIDPath)
if err != nil {
return "", errors.New(fmt.Sprintf("Error reading disk directory: %s", err))
}
for _, entry := range entries {
if entry.IsDir() {
continue
}
linkPath := filepath.Join(DiskByIDPath, entry.Name())
_, err = os.Readlink(linkPath)
if err != nil {
continue
}
if strings.Contains(entry.Name(), "ata-") {
parts := strings.Split(entry.Name(), "-")
if len(parts) > 1 {
serialNumber = parts[1]
} else {
serialNumber = entry.Name()
}
}
}
if serialNumber == "" {
return "", errors.New("disk id serial number not found")
}
return serialNumber, nil
}
// 获取硬盘编号
func (linux LinuxMachine) GetDiskSerialNumberByUUID() (string, error) {
var result []string
entries, err := os.ReadDir(DiskByUUIDPath)
if err != nil {
return "", errors.New(fmt.Sprintf("error reading disk directory:", err))
}
for _, entry := range entries {
if entry.IsDir() {
continue
}
name := entry.Name()
linkPath := filepath.Join(DiskByUUIDPath, entry.Name())
_, err = os.Readlink(linkPath)
if err != nil {
continue
}
result = append(result, name)
}
if len(result) == 0 {
return "", errors.New("disk uuid serial number not found")
}
idListStr := strings.Join(result, "|")
s := md5.New()
s.Write([]byte(idListStr))
md5Result := hex.EncodeToString(s.Sum(nil))
return md5Result, nil
}
// 设备唯一UUID
func (linux LinuxMachine) GetUUID() (UUID string, err error) {
// dmidecode -s system-uuid UUID
var cmd *exec.Cmd
cmd = exec.Command("dmidecode", "-s", "system-uuid")
var out bytes.Buffer
cmd.Stdout = &out
cmd.Stderr = os.Stderr
err = cmd.Start()
if err != nil {
return "", err
}
err = cmd.Wait()
if err == nil {
uuid := out.String()
uuid = strings.Replace(uuid, "\n", "", -1)
return uuid, nil
}
return "", err
}
func (linux LinuxMachine) GetCpuSerialNumber2() (cpuId string, err error) {
// dmidecode -t processor |grep ID |head -1
var cmd *exec.Cmd
cmd = exec.Command("dmidecode", "-t", "processor", "|grep ID |head -1")
var out bytes.Buffer
cmd.Stdout = &out
cmd.Stderr = os.Stderr
err = cmd.Start()
if err != nil {
return "", err
}
err = cmd.Wait()
if err == nil {
uuid := out.String()
//uuid = strings.Replace(uuid, "\n", "", -1)
return uuid, nil
}
return "", err
}
func (LinuxMachine) pipeline(cmds ...*exec.Cmd) (pipeLineOutput, collectedStandardError []byte, pipeLineError error) {
if len(cmds) < 1 {
return nil, nil, nil
}
var output bytes.Buffer
var stderr bytes.Buffer
last := len(cmds) - 1
for i, cmd := range cmds[:last] {
var err error
if cmds[i+1].Stdin, err = cmd.StdoutPipe(); err != nil {
return nil, nil, err
}
cmd.Stderr = &stderr
}
cmds[last].Stdout, cmds[last].Stderr = &output, &stderr
for _, cmd := range cmds {
if err := cmd.Start(); err != nil {
return output.Bytes(), stderr.Bytes(), err
}
}
for _, cmd := range cmds {
if err := cmd.Wait(); err != nil {
return output.Bytes(), stderr.Bytes(), err
}
}
return output.Bytes(), stderr.Bytes(), nil
}
func (linux LinuxMachine) execPipeLine(cmds ...*exec.Cmd) (string, error) {
output, stderr, err := linux.pipeline(cmds...)
if err != nil {
return "", err
}
if len(output) > 0 {
return string(output), nil
}
if len(stderr) > 0 {
return string(stderr), nil
}
return "", errors.New("no returns")
}