1
0
mirror of https://github.com/shirou/gopsutil.git synced 2025-04-26 13:48:59 +08:00

Read disk model and serial from udev data or sysfs on Linux

It reads model and serial data directly from files instead of using
`udevadm` command. This way obtaining the disk serial number doesn't
depend on command execution, and can be also possible even if udev or
udevadm are not available.
This commit is contained in:
Jaime Soriano Pastor 2018-06-01 13:57:14 +02:00
parent eeb1d38d69
commit f03124bf86

View File

@ -3,10 +3,11 @@
package disk package disk
import ( import (
"bufio"
"bytes"
"context" "context"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os/exec"
"path/filepath" "path/filepath"
"strconv" "strconv"
"strings" "strings"
@ -385,26 +386,33 @@ func GetDiskSerialNumber(name string) string {
} }
func GetDiskSerialNumberWithContext(ctx context.Context, name string) string { func GetDiskSerialNumberWithContext(ctx context.Context, name string) string {
n := fmt.Sprintf("--name=%s", name) var stat unix.Stat_t
udevadm, err := exec.LookPath("/sbin/udevadm") err := unix.Stat(name, &stat)
if err != nil { if err != nil {
return "" return ""
} }
major := unix.Major(stat.Rdev)
minor := unix.Minor(stat.Rdev)
out, err := invoke.CommandWithContext(ctx, udevadm, "info", "--query=property", n) // Try to get the serial from udev data
udevDataPath := fmt.Sprintf("/run/udev/data/b%d:%d", major, minor)
// does not return error, just an empty string if udevdata, err := ioutil.ReadFile(udevDataPath); err == nil {
if err != nil { scanner := bufio.NewScanner(bytes.NewReader(udevdata))
return "" for scanner.Scan() {
} values := strings.Split(scanner.Text(), "=")
lines := strings.Split(string(out), "\n") if len(values) == 2 && values[0] == "E:ID_SERIAL" {
for _, line := range lines { return values[1]
values := strings.Split(line, "=") }
if len(values) < 2 || values[0] != "ID_SERIAL" {
// only get ID_SERIAL, not ID_SERIAL_SHORT
continue
} }
return values[1] }
// Try to get the serial from sysfs, look at the disk device (minor 0) directly
// because if it is a partition it is not going to contain any device information
devicePath := fmt.Sprintf("/sys/dev/block/%d:0/device", major)
model, _ := ioutil.ReadFile(filepath.Join(devicePath, "model"))
serial, _ := ioutil.ReadFile(filepath.Join(devicePath, "serial"))
if len(model) > 0 && len(serial) > 0 {
return fmt.Sprintf("%s_%s", string(model), string(serial))
} }
return "" return ""
} }