[Libguestfs] [PATCH v2 1/3] daemon: Reimplement 'part_get_mbr_part_type' API in OCaml.

Mykola Ivanets stenavin at gmail.com
Thu Jan 25 23:16:19 UTC 2018


Instead of parsing 'parted' output OCaml implementation relies on the following facts:

1. The function is applicable for MBR partitions only (as noted in documentation and as function name suggests).
2. An attempt to call the function for non-MBR partition fails with "part_get_mbr_part_type can only be used on MBR Partitions" error and NULL is returned.
3. MBR partition table can hold up to 4 "primary" partitions.
4. Partition with number >= 5 is logical partition
5. Extnded partition number is <= 4 and has MBR id 0x05 or 0x0f (http://thestarman.pcministry.com/asm/mbr/PartTypes.htm; https://en.wikipedia.org/wiki/Partition_type).
---
 daemon/parted.c           | 106 ----------------------------------------------
 daemon/parted.ml          |  14 ++++++
 daemon/parted.mli         |   2 +
 generator/actions_core.ml |   1 +
 4 files changed, 17 insertions(+), 106 deletions(-)

diff --git a/daemon/parted.c b/daemon/parted.c
index e5435b5..d67c6c5 100644
--- a/daemon/parted.c
+++ b/daemon/parted.c
@@ -602,112 +602,6 @@ do_part_get_name (const char *device, int partnum)
   }
 }
 
-char *
-do_part_get_mbr_part_type (const char *device, int partnum)
-{
-  CLEANUP_FREE char *parttype;
-  char *part_type;
-
-  parttype = do_part_get_parttype (device);
-  if (parttype == NULL)
-    return NULL;
-
-  /* machine parseable output by 'parted -m' did not provide
-   * partition type info.
-   * Use traditional style.
-   */
-  CLEANUP_FREE char *out = print_partition_table (device, false);
-  if (!out)
-    return NULL;
-
-  CLEANUP_FREE_STRING_LIST char **lines = split_lines (out);
-
-  if (!lines)
-    return NULL;
-
-  size_t start = 0, end = 0, row;
-
-  for (row = 0; lines[row] != NULL; ++row)
-    if (STRPREFIX (lines[row], "Number")) {
-      start = row + 1;
-      break;
-    }
-
-  if (start == 0) {
-    reply_with_error ("parted output has no \"Number\" line");
-    return NULL;
-  }
-
-  for (row = start; lines[row] != NULL; ++row)
-    if (STREQ (lines[row], "")) {
-      end = row;
-      break;
-    }
-
-  if (end == 0) {
-    reply_with_error ("parted output has no blank after end of table");
-    return NULL;
-  }
-
-  /* Now parse the lines. */
-  size_t i;
-  int64_t temp_int64;
-  int part_num;
-  char temp_type[16] = {'\0'};
-  for (i = 0, row = start;  row < end; ++i, ++row) {
-    if (STREQ (parttype, "gpt")) {
-      memcpy (temp_type, "primary", strlen ("primary"));
-      if (sscanf (lines[row], "%d%" SCNi64 "B%" SCNi64 "B%" SCNi64 "B",
-		  &part_num,
-		  &temp_int64,
-		  &temp_int64,
-		  &temp_int64) != 4) {
-        reply_with_error ("could not parse row from output of parted print command: %s", lines[row]);
-        return NULL;
-      }
-    } else {
-      if (sscanf (lines[row], "%d%" SCNi64 "B%" SCNi64 "B%" SCNi64 "B" "%15s",
-		  &part_num,
-		  &temp_int64,
-		  &temp_int64,
-		  &temp_int64,
-		  temp_type) != 5) {
-        reply_with_error ("could not parse row from output of parted print command: %s", lines[row]);
-        return NULL;
-      }
-    }
-
-    if (part_num != partnum)
-      continue;
-
-    if (STRPREFIX (temp_type, "primary")) {
-      part_type = strdup ("primary");
-      if (part_type == NULL)
-	goto error;
-    } else if (STRPREFIX (temp_type, "logical")) {
-      part_type = strdup ("logical");
-      if (part_type == NULL)
-	goto error;
-    } else if (STRPREFIX (temp_type, "extended")) {
-      part_type = strdup ("extended");
-      if (part_type == NULL)
-	goto error;
-    } else
-      goto error;
-
-    return part_type;
-  }
-
-  if (row == end) {
-    reply_with_error ("could not find partnum: %d", partnum);
-    return NULL;
-  }
-
- error:
-  reply_with_error ("strdup failed");
-  return NULL;
-}
-
 static char *
 extract_uuid (const char *value)
 {
diff --git a/daemon/parted.ml b/daemon/parted.ml
index ce8da8a..75d9d37 100644
--- a/daemon/parted.ml
+++ b/daemon/parted.ml
@@ -125,6 +125,20 @@ let part_get_parttype device =
   | _ ->
      failwithf "%s: cannot parse the output of parted" device
 
+let part_get_mbr_part_type device partnum =
+  let parttype = part_get_parttype device in
+  let mbr_id = part_get_mbr_id device partnum in
+
+  (* 0x05 - extended partition id within the first 1024 cylinders.
+   * 0x0f - extended partition id beyond the first 1024 cylinders.
+   *)
+  match parttype, partnum, mbr_id with
+  | "msdos", (1|2|3|4), (0x05|0x0f) -> "extended"
+  | "msdos", (1|2|3|4), _ -> "primary"
+  | "msdos", _, _ -> "logical"
+  | _, _, _ ->
+     failwithf "part_get_mbr_part_type can only be used on MBR Partitions"
+
 let part_set_gpt_attributes device partnum attributes =
   if partnum <= 0 then failwith "partition number must be >= 1";
 
diff --git a/daemon/parted.mli b/daemon/parted.mli
index d547f2f..0f59d29 100644
--- a/daemon/parted.mli
+++ b/daemon/parted.mli
@@ -28,6 +28,8 @@ val part_list : string -> partition list
 
 val part_get_parttype : string -> string
 
+val part_get_mbr_part_type : string -> int -> string
+
 val part_get_gpt_type : string -> int -> string
 val part_get_gpt_guid : string -> int -> string
 val part_get_gpt_attributes : string -> int -> int64
diff --git a/generator/actions_core.ml b/generator/actions_core.ml
index 544cb6e..307e414 100644
--- a/generator/actions_core.ml
+++ b/generator/actions_core.ml
@@ -9213,6 +9213,7 @@ All data will be zeroed, but metadata and the like is preserved." };
   { defaults with
     name = "part_get_mbr_part_type"; added = (1, 29, 32);
     style = RString (RPlainString, "partitiontype"), [String (Device, "device"); Int "partnum"], [];
+    impl = OCaml "Parted.part_get_mbr_part_type";
     tests = [
       InitEmpty, Always, TestResultString (
         [["part_init"; "/dev/sda"; "mbr"];
-- 
2.9.5




More information about the Libguestfs mailing list