mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-22 07:03:38 +00:00
These were previously written in very convoluted C which had to deal with parsing the crazy output of the "lvm" command. In fact the parsing was so complex that it was generated by the generator. It's easier to do this in OCaml. These are basically legacy APIs. They cannot be expanded and LVM already supports many more fields. We should replace these with APIs for getting single named fields from LVM.
222 lines
8.5 KiB
OCaml
222 lines
8.5 KiB
OCaml
(* guestfs-inspection
|
|
* Copyright (C) 2009-2025 Red Hat Inc.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*)
|
|
|
|
(* This file implements the complicated lvs-full, vgs-full and pvs-full APIs
|
|
*
|
|
* XXX Deprecate these APIs are replace with APIs for getting single
|
|
* named fields from LVM. That will be slower but far more flexible
|
|
* and extensible.
|
|
*)
|
|
|
|
open Unix
|
|
open Printf
|
|
|
|
open Std_utils
|
|
|
|
open Utils
|
|
|
|
(* LVM UUIDs are basically 32 byte strings with '-' inserted.
|
|
* Remove the '-' characters and check it's the right length.
|
|
*)
|
|
let parse_uuid uuid =
|
|
let uuid' =
|
|
uuid |> String.explode |> List.filter ((<>) '-') |> String.implode in
|
|
if String.length uuid' <> 32 then
|
|
failwithf "lvm-full: parse_uuid: unexpected UUID format: %S" uuid;
|
|
uuid'
|
|
|
|
(* Parse the percent fields. These can be empty. *)
|
|
let parse_percent pc = if pc = "" then None else Some (float_of_string pc)
|
|
|
|
(* XXX These must match generator/structs.ml *)
|
|
let lvm_pv_cols = [
|
|
"pv_name"; (* FString *)
|
|
"pv_uuid"; (* FUUID *)
|
|
"pv_fmt"; (* FString *)
|
|
"pv_size"; (* FBytes *)
|
|
"dev_size"; (* FBytes *)
|
|
"pv_free"; (* FBytes *)
|
|
"pv_used"; (* FBytes *)
|
|
"pv_attr"; (* FString (* XXX *) *)
|
|
"pv_pe_count"; (* FInt64 *)
|
|
"pv_pe_alloc_count"; (* FInt64 *)
|
|
"pv_tags"; (* FString *)
|
|
"pe_start"; (* FBytes *)
|
|
"pv_mda_count"; (* FInt64 *)
|
|
"pv_mda_free"; (* FBytes *)
|
|
]
|
|
|
|
let tokenize_pvs = function
|
|
| [ pv_name; pv_uuid; pv_fmt; pv_size; dev_size; pv_free;
|
|
pv_used; pv_attr; pv_pe_count; pv_pe_alloc_count; pv_tags;
|
|
pe_start; pv_mda_count; pv_mda_free ] ->
|
|
{ Structs.pv_name = pv_name;
|
|
pv_uuid = parse_uuid pv_uuid;
|
|
pv_fmt = pv_fmt;
|
|
pv_size = Int64.of_string pv_size;
|
|
dev_size = Int64.of_string dev_size;
|
|
pv_free = Int64.of_string pv_free;
|
|
pv_used = Int64.of_string pv_used;
|
|
pv_attr = pv_attr;
|
|
pv_pe_count = Int64.of_string pv_pe_count;
|
|
pv_pe_alloc_count = Int64.of_string pv_pe_alloc_count;
|
|
pv_tags = pv_tags;
|
|
pe_start = Int64.of_string pe_start;
|
|
pv_mda_count = Int64.of_string pv_mda_count;
|
|
pv_mda_free = Int64.of_string pv_mda_free }
|
|
|
|
| fields ->
|
|
failwithf "pvs-full: tokenize_pvs: unexpected number of fields: %d"
|
|
(List.length fields)
|
|
|
|
(* XXX These must match generator/structs.ml *)
|
|
let lvm_vg_cols = [
|
|
"vg_name"; (* FString *)
|
|
"vg_uuid"; (* FUUID *)
|
|
"vg_fmt"; (* FString *)
|
|
"vg_attr"; (* FString (* XXX *) *)
|
|
"vg_size"; (* FBytes *)
|
|
"vg_free"; (* FBytes *)
|
|
"vg_sysid"; (* FString *)
|
|
"vg_extent_size"; (* FBytes *)
|
|
"vg_extent_count"; (* FInt64 *)
|
|
"vg_free_count"; (* FInt64 *)
|
|
"max_lv"; (* FInt64 *)
|
|
"max_pv"; (* FInt64 *)
|
|
"pv_count"; (* FInt64 *)
|
|
"lv_count"; (* FInt64 *)
|
|
"snap_count"; (* FInt64 *)
|
|
"vg_seqno"; (* FInt64 *)
|
|
"vg_tags"; (* FString *)
|
|
"vg_mda_count"; (* FInt64 *)
|
|
"vg_mda_free"; (* FBytes *)
|
|
]
|
|
|
|
let tokenize_vgs = function
|
|
| [ vg_name; vg_uuid; vg_fmt; vg_attr; vg_size; vg_free; vg_sysid;
|
|
vg_extent_size; vg_extent_count; vg_free_count; max_lv;
|
|
max_pv; pv_count; lv_count; snap_count; vg_seqno; vg_tags;
|
|
vg_mda_count; vg_mda_free ] ->
|
|
{ Structs.vg_name = vg_name;
|
|
vg_uuid = parse_uuid vg_uuid;
|
|
vg_fmt = vg_fmt;
|
|
vg_attr = vg_attr;
|
|
vg_size = Int64.of_string vg_size;
|
|
vg_free = Int64.of_string vg_free;
|
|
vg_sysid = vg_sysid;
|
|
vg_extent_size = Int64.of_string vg_extent_size;
|
|
vg_extent_count = Int64.of_string vg_extent_count;
|
|
vg_free_count = Int64.of_string vg_free_count;
|
|
max_lv = Int64.of_string max_lv;
|
|
max_pv = Int64.of_string max_pv;
|
|
pv_count = Int64.of_string pv_count;
|
|
lv_count = Int64.of_string lv_count;
|
|
snap_count = Int64.of_string snap_count;
|
|
vg_seqno = Int64.of_string vg_seqno;
|
|
vg_tags = vg_tags;
|
|
vg_mda_count = Int64.of_string vg_mda_count;
|
|
vg_mda_free = Int64.of_string vg_mda_free }
|
|
|
|
| fields ->
|
|
failwithf "pvs-full: tokenize_vgs: unexpected number of fields: %d"
|
|
(List.length fields)
|
|
|
|
(* XXX These must match generator/structs.ml *)
|
|
let lvm_lv_cols = [
|
|
"lv_name"; (* FString *)
|
|
"lv_uuid"; (* FUUID *)
|
|
"lv_attr"; (* FString (* XXX *) *)
|
|
"lv_major"; (* FInt64 *)
|
|
"lv_minor"; (* FInt64 *)
|
|
"lv_kernel_major"; (* FInt64 *)
|
|
"lv_kernel_minor"; (* FInt64 *)
|
|
"lv_size"; (* FBytes *)
|
|
"seg_count"; (* FInt64 *)
|
|
"origin"; (* FString *)
|
|
"snap_percent"; (* FOptPercent *)
|
|
"copy_percent"; (* FOptPercent *)
|
|
"move_pv"; (* FString *)
|
|
"lv_tags"; (* FString *)
|
|
"mirror_log"; (* FString *)
|
|
"modules"; (* FString *)
|
|
]
|
|
|
|
let tokenize_lvs = function
|
|
| [ lv_name; lv_uuid; lv_attr; lv_major; lv_minor; lv_kernel_major;
|
|
lv_kernel_minor; lv_size; seg_count; origin; snap_percent;
|
|
copy_percent; move_pv; lv_tags; mirror_log; modules ] ->
|
|
{ Structs.lv_name = lv_name;
|
|
lv_uuid = parse_uuid lv_uuid;
|
|
lv_attr = lv_attr;
|
|
lv_major = Int64.of_string lv_major;
|
|
lv_minor = Int64.of_string lv_minor;
|
|
lv_kernel_major = Int64.of_string lv_kernel_major;
|
|
lv_kernel_minor = Int64.of_string lv_kernel_minor;
|
|
lv_size = Int64.of_string lv_size;
|
|
seg_count = Int64.of_string seg_count;
|
|
origin = origin;
|
|
snap_percent = parse_percent snap_percent;
|
|
copy_percent = parse_percent copy_percent;
|
|
move_pv = move_pv;
|
|
lv_tags = lv_tags;
|
|
mirror_log = mirror_log;
|
|
modules = modules }
|
|
|
|
| fields ->
|
|
failwithf "pvs-full: tokenize_vgs: unexpected number of fields: %d"
|
|
(List.length fields)
|
|
|
|
let rec pvs_full () =
|
|
let out = run_lvm_command "pvs" lvm_pv_cols in
|
|
let lines = trim_and_split out in
|
|
let pvs = List.map tokenize_pvs lines in
|
|
pvs
|
|
|
|
and vgs_full () =
|
|
let out = run_lvm_command "vgs" lvm_vg_cols in
|
|
let lines = trim_and_split out in
|
|
let vgs = List.map tokenize_vgs lines in
|
|
vgs
|
|
|
|
and lvs_full () =
|
|
let out = run_lvm_command "lvs" lvm_lv_cols in
|
|
let lines = trim_and_split out in
|
|
let lvs = List.map tokenize_lvs lines in
|
|
lvs
|
|
|
|
and run_lvm_command typ cols =
|
|
let cols = String.concat "," cols in
|
|
let cmd = [ typ; "-o"; cols;
|
|
"--unbuffered"; "--noheadings"; "--nosuffix";
|
|
"--separator"; "\r"; "--units"; "b" ] in
|
|
command "lvm" cmd
|
|
|
|
and trim_and_split out =
|
|
(* Split the output into lines. *)
|
|
let lines = String.nsplit "\n" out in
|
|
|
|
(* LVM puts leading whitespace on each line so remove that. *)
|
|
let lines = List.map String.triml lines in
|
|
|
|
(* Ignore any blank lines. *)
|
|
let lines = List.filter ((<>) "") lines in
|
|
|
|
(* Split each line into fields. *)
|
|
let lines = List.map (String.nsplit "\r") lines in
|
|
lines
|