diff --git a/README.md b/README.md index fee41b9f..498a0f78 100644 --- a/README.md +++ b/README.md @@ -546,8 +546,10 @@ Each `ghw.Partition` struct contains these fields: * `ghw.Partition.Disk` is a pointer to the `ghw.Disk` object associated with the partition. This will be `nil` if the `ghw.Partition` struct was returned by the `ghw.DiskPartitions()` library function. -* `ghw.Partition.UUID` is a string containing the volume UUID on Linux, the - partition UUID on MacOS and nothing on Windows. +* `ghw.Partition.UUID` is a string containing the partition UUID on Linux, the + partition UUID on MacOS and nothing on Windows. On Linux + systems, this is derived from the `ID_PART_ENTRY_UUID` udev entry for the + partition. ```go package main diff --git a/pkg/block/block_linux.go b/pkg/block/block_linux.go index 5abc6313..ce164132 100644 --- a/pkg/block/block_linux.go +++ b/pkg/block/block_linux.go @@ -10,7 +10,6 @@ import ( "io" "io/ioutil" "os" - "os/exec" "path/filepath" "strconv" "strings" @@ -209,7 +208,7 @@ func diskPartitions(ctx *context.Context, paths *linuxpath.Paths, disk string) [ } size := partitionSizeBytes(paths, disk, fname) mp, pt, ro := partitionInfo(paths, fname) - du := diskPartUUID(ctx, fname) + du := diskPartUUID(paths, disk, fname) label := diskPartLabel(paths, disk, fname) if pt == "" { pt = diskPartTypeUdev(paths, disk, fname) @@ -268,37 +267,16 @@ func diskPartTypeUdev(paths *linuxpath.Paths, disk string, partition string) str return util.UNKNOWN } -func diskPartUUID(ctx *context.Context, part string) string { - if !ctx.EnableTools { - ctx.Warn("EnableTools=false disables partition UUID detection.") - return "" - } - if !strings.HasPrefix(part, "/dev") { - part = "/dev/" + part - } - args := []string{ - "blkid", - "-s", - "PARTUUID", - part, - } - out, err := exec.Command(args[0], args[1:]...).Output() +func diskPartUUID(paths *linuxpath.Paths, disk string, partition string) string { + info, err := udevInfoPartition(paths, disk, partition) if err != nil { - ctx.Warn("failed to read disk partuuid of %s : %s\n", part, err.Error()) - return "" - } - - if len(out) == 0 { - return "" + return util.UNKNOWN } - parts := strings.Split(string(out), "PARTUUID=") - if len(parts) != 2 { - ctx.Warn("failed to parse the partuuid of %s\n", part) - return "" + if pType, ok := info["ID_PART_ENTRY_UUID"]; ok { + return pType } - - return strings.ReplaceAll(strings.TrimSpace(parts[1]), `"`, "") + return util.UNKNOWN } func diskIsRemovable(paths *linuxpath.Paths, disk string) bool { diff --git a/pkg/block/block_linux_test.go b/pkg/block/block_linux_test.go index 3529711a..98290e45 100644 --- a/pkg/block/block_linux_test.go +++ b/pkg/block/block_linux_test.go @@ -288,6 +288,37 @@ func TestDiskTypeUdev(t *testing.T) { } } +func TestDiskPartUUID(t *testing.T) { + if _, ok := os.LookupEnv("GHW_TESTING_SKIP_BLOCK"); ok { + t.Skip("Skipping block tests.") + } + baseDir, _ := ioutil.TempDir("", "test") + defer os.RemoveAll(baseDir) + ctx := context.New() + ctx.Chroot = baseDir + paths := linuxpath.New(ctx) + partUUID := "11111111-1111-1111-1111-111111111111" + + _ = os.MkdirAll(paths.SysBlock, 0755) + _ = os.MkdirAll(paths.RunUdevData, 0755) + + // Emulate a disk with one partition with uuid + _ = os.Mkdir(filepath.Join(paths.SysBlock, "sda"), 0755) + _ = os.Mkdir(filepath.Join(paths.SysBlock, "sda", "sda1"), 0755) + _ = ioutil.WriteFile(filepath.Join(paths.SysBlock, "sda", "sda1", "dev"), []byte("259:0\n"), 0644) + _ = ioutil.WriteFile(filepath.Join(paths.RunUdevData, "b259:0"), []byte(fmt.Sprintf("E:ID_PART_ENTRY_UUID=%s\n", partUUID)), 0644) + uuid := diskPartUUID(paths, "sda", "sda1") + if uuid != partUUID { + t.Fatalf("Got uuid %s but expected %s", uuid, partUUID) + } + + // Check empty uuid if not found + uuid = diskPartUUID(paths, "sda", "sda2") + if uuid != util.UNKNOWN { + t.Fatalf("Got uuid %s, but expected %s label", uuid, util.UNKNOWN) + } +} + // TestLoopDevicesWithOption tests to see if we find loop devices when the option is activated func TestLoopDevicesWithOption(t *testing.T) { if _, ok := os.LookupEnv("GHW_TESTING_SKIP_BLOCK"); ok {