From 32e661f4216996cda9161e2d2c618838b9798bca Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Tue, 6 Jun 2017 12:07:04 +0100 Subject: [PATCH] =?UTF-8?q?daemon:=20Reimplement=20=E2=80=98part=5Flist?= =?UTF-8?q?=E2=80=99=20API=20in=20OCaml.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- daemon/parted.c | 56 --------------------------------------- daemon/parted.ml | 56 +++++++++++++++++++++++++++++++++++++++ daemon/parted.mli | 8 ++++++ generator/actions_core.ml | 1 + 4 files changed, 65 insertions(+), 56 deletions(-) diff --git a/daemon/parted.c b/daemon/parted.c index b788ed72a..3ad1ba147 100644 --- a/daemon/parted.c +++ b/daemon/parted.c @@ -383,62 +383,6 @@ do_part_get_parttype (const char *device) return r; } -guestfs_int_partition_list * -do_part_list (const char *device) -{ - CLEANUP_FREE char *out = print_partition_table (device, true); - if (!out) - return NULL; - - CLEANUP_FREE_STRING_LIST char **lines = split_lines (out); - - if (!lines) - return NULL; - - guestfs_int_partition_list *r; - - /* lines[0] is "BYT;", lines[1] is the device line which we ignore, - * lines[2..] are the partitions themselves. Count how many. - */ - size_t nr_rows = 0, row; - for (row = 2; lines[row] != NULL; ++row) - ++nr_rows; - - r = malloc (sizeof *r); - if (r == NULL) { - reply_with_perror ("malloc"); - return NULL; - } - r->guestfs_int_partition_list_len = nr_rows; - r->guestfs_int_partition_list_val = - malloc (nr_rows * sizeof (guestfs_int_partition)); - if (r->guestfs_int_partition_list_val == NULL) { - reply_with_perror ("malloc"); - goto error2; - } - - /* Now parse the lines. */ - size_t i; - for (i = 0, row = 2; lines[row] != NULL; ++i, ++row) { - if (sscanf (lines[row], "%d:%" SCNi64 "B:%" SCNi64 "B:%" SCNi64 "B", - &r->guestfs_int_partition_list_val[i].part_num, - &r->guestfs_int_partition_list_val[i].part_start, - &r->guestfs_int_partition_list_val[i].part_end, - &r->guestfs_int_partition_list_val[i].part_size) != 4) { - reply_with_error ("could not parse row from output of parted print command: %s", lines[row]); - goto error3; - } - } - - return r; - - error3: - free (r->guestfs_int_partition_list_val); - error2: - free (r); - return NULL; -} - int do_part_get_bootable (const char *device, int partnum) { diff --git a/daemon/parted.ml b/daemon/parted.ml index 6be41cf66..da31ab5c6 100644 --- a/daemon/parted.ml +++ b/daemon/parted.ml @@ -22,6 +22,8 @@ open Std_utils open Utils +include Structs + (* Test if [sfdisk] is recent enough to have [--part-type], to be used * instead of [--print-id] and [--change-id]. *) @@ -53,3 +55,57 @@ let part_get_mbr_id device partnum = (* It's printed in hex, possibly with a leading space. *) sscanf out " %x" identity + +(* This is not equivalent to print_partition_table in the C code, as + * it only deals with the ‘-m’ option output, and it partially parses + * that. If we convert other functions that don't use the ‘-m’ version + * we'll have to refactor this. XXX + *) +let print_partition_table_machine_readable device = + udev_settle (); + + let args = ref [] in + push_back args "-m"; + push_back args "-s"; + push_back args "--"; + push_back args device; + push_back args "unit"; + push_back args "b"; + push_back args "print"; + + let out = + try command "parted" !args + with + (* Translate "unrecognised disk label" into an errno code. *) + Failure str when String.find str "unrecognised disk label" >= 0 -> + raise (Unix.Unix_error (Unix.EINVAL, "parted", device ^ ": " ^ str)) in + + udev_settle (); + + (* Split the output into lines. *) + let out = String.trim out in + let lines = String.nsplit "\n" out in + + (* lines[0] is "BYT;", lines[1] is the device line which we ignore, + * lines[2..] are the partitions themselves. + *) + match lines with + | "BYT;" :: _ :: lines -> lines + | [] | [_] -> + failwith "too few rows of output from 'parted print' command" + | _ -> + failwith "did not see 'BYT;' magic value in 'parted print' command" + +let part_list device = + let lines = print_partition_table_machine_readable device in + + List.map ( + fun line -> + try sscanf line "%d:%LdB:%LdB:%LdB" + (fun num start end_ size -> + { part_num = Int32.of_int num; + part_start = start; part_end = end_; part_size = size }) + with Scan_failure err -> + failwithf "could not parse row from output of 'parted print' command: %s: %s" + line err + ) lines diff --git a/daemon/parted.mli b/daemon/parted.mli index 33eb6d30d..057d7e8c7 100644 --- a/daemon/parted.mli +++ b/daemon/parted.mli @@ -16,4 +16,12 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *) +type partition = { + part_num : int32; + part_start : int64; + part_end : int64; + part_size : int64; +} + val part_get_mbr_id : string -> int -> int +val part_list : string -> partition list diff --git a/generator/actions_core.ml b/generator/actions_core.ml index d5946b3f5..b1e2559e0 100644 --- a/generator/actions_core.ml +++ b/generator/actions_core.ml @@ -5039,6 +5039,7 @@ table. This works on C but not on C partitions." }; { defaults with name = "part_list"; added = (1, 0, 78); style = RStructList ("partitions", "partition"), [String (Device, "device")], []; + impl = OCaml "Parted.part_list"; tests = [] (* XXX Add a regression test for this. *); shortdesc = "list partitions on a device"; longdesc = "\