oem-preloader: update partition UUID fecthing method

blkid gets fs UUID from image file, not partition UUID.

BUG=b/465210828

Change-Id: Iad764f22b32c0afb613b98e9c2a2fcd3423bbc6d
Reviewed-on: https://cos-review.googlesource.com/c/cos/tools/+/131621
Cloud-Build: GCB Service account <228075978874@cloudbuild.gserviceaccount.com>
Tested-by: He Gao <hegao@google.com>
Reviewed-by: Robert Kolchmeyer <rkolchmeyer@google.com>
diff --git a/src/pkg/oempreloader/seal.go b/src/pkg/oempreloader/seal.go
index fb49cac..49fc0ba 100644
--- a/src/pkg/oempreloader/seal.go
+++ b/src/pkg/oempreloader/seal.go
@@ -77,7 +77,7 @@
 		return fmt.Errorf("failed to read grub file: %v", err)
 	}
 
-	uuid, err := fetchPartitionUUID(imagePath, oemPartitionNum)
+	uuid, err := fetchOEMUUID(imagePath)
 	if err != nil {
 		return fmt.Errorf("failed to find OEM partition UUID: %v", err)
 	}
@@ -179,24 +179,8 @@
 	return nil
 }
 
-func fetchPartitionUUID(imagePath string, partitionNum int) (string, error) {
-	partitionStart, err := readPartitionStart(imagePath, partitionNum)
-	if err != nil {
-		return "", fmt.Errorf("failed to read OEM partition start: %v", err)
-	}
-	cmd := exec.Command(
-		"blkid",
-		"-o", "value",
-		"-s", "UUID",
-		"-p",
-		fmt.Sprintf("--offset=%d", partitionStart),
-		imagePath,
-	)
-	outputBytes, err := cmd.CombinedOutput()
-	if err != nil {
-		return "", fmt.Errorf("blkid failed: %v, output: %s", err, string(outputBytes))
-	}
-	return string(outputBytes), nil
+func fetchOEMUUID(imagePath string) (string, error) {
+	return partutil.ReadPartitionUUID(imagePath, oemPartitionNum)
 }
 
 // Temporary solution, will remove once migrate to commandline baked in kernel.
diff --git a/src/pkg/tools/partutil/handle_partition_table.go b/src/pkg/tools/partutil/handle_partition_table.go
index c924ad8..a091c20 100644
--- a/src/pkg/tools/partutil/handle_partition_table.go
+++ b/src/pkg/tools/partutil/handle_partition_table.go
@@ -218,6 +218,38 @@
 	return start, nil
 }
 
+// ReadPartitionUUID reads PARTUUID of a partition.
+func ReadPartitionUUID(disk string, partNumInt int) (string, error) {
+	if len(disk) <= 0 || partNumInt <= 0 {
+		return "", fmt.Errorf("invalid input: disk=%q, partNumInt=%d", disk, partNumInt)
+	}
+
+	// get partition number string
+	partNum, err := PartNumIntToString(disk, partNumInt)
+	if err != nil {
+		return "", fmt.Errorf("error in converting partition number, "+
+			"input: disk=%q, partNumInt=%d, "+
+			"error msg: (%v)", disk, partNumInt, err)
+	}
+	partName := disk + partNum
+
+	table, err := ReadPartitionTableJSON(disk)
+	if err != nil {
+		return "", fmt.Errorf("cannot read partition table of %q, "+
+			"input: disk=%q, partNumInt=%d, "+
+			"error msg: (%v)", disk, disk, partNumInt, err)
+	}
+
+	for _, p := range table.PartitionTable.Partitions {
+		if p.Node != partName {
+			continue
+		}
+		return p.UUID, nil
+
+	}
+	return "", fmt.Errorf("failed to find partition name %q in disk %q", disk, partName)
+}
+
 // IsPartitionMinimal determines if a partition is the smallest size it can be.
 // If this function returns true, MinimizePartition can make the given partition
 // smaller.
diff --git a/src/pkg/tools/partutil/handle_partition_table_test.go b/src/pkg/tools/partutil/handle_partition_table_test.go
index 644066e..6e4b851 100644
--- a/src/pkg/tools/partutil/handle_partition_table_test.go
+++ b/src/pkg/tools/partutil/handle_partition_table_test.go
@@ -308,3 +308,40 @@
 		})
 	}
 }
+
+func TestReadPartitionUUID(t *testing.T) {
+	var testNames partutiltest.TestNames
+	t.Cleanup(func() { partutiltest.TearDown(&testNames) })
+	partutiltest.SetupFakeDisk("tmp_disk_read_partition_uuid", "", t, &testNames)
+	diskName := testNames.DiskName
+	testData := []struct {
+		testName string
+		disk     string
+		partNum  int
+		want     string
+		wantErr  bool
+	}{
+		{
+			testName: "Pass",
+			disk:     diskName,
+			partNum:  8,
+			want:     "33E9D4B7-25DD-964B-A431-3233FE4E3D66",
+		}, {
+			testName: "InvalidPartNum",
+			disk:     diskName,
+			partNum:  15,
+			wantErr:  true,
+		},
+	}
+	for _, input := range testData {
+		t.Run(input.testName, func(t *testing.T) {
+			res, err := ReadPartitionUUID(input.disk, input.partNum)
+			if (err != nil) != input.wantErr {
+				t.Fatalf("unexpected error status, wantErr: %v, got error: (%v)", input.wantErr, err)
+			}
+			if res != input.want {
+				t.Fatalf("wrong result in %q, res: %q, expected: %q", input.testName, res, input.want)
+			}
+		})
+	}
+}