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