daemon: Reimplement ‘part_list’ API in OCaml.

This commit is contained in:
Richard W.M. Jones
2017-06-06 12:07:04 +01:00
parent 4052f613d2
commit 32e661f421
4 changed files with 65 additions and 56 deletions

View File

@@ -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)
{

View File

@@ -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

View File

@@ -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

View File

@@ -5039,6 +5039,7 @@ table. This works on C<gpt> but not on C<mbr> 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 = "\