mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-21 22:53:37 +00:00
daemon: Reimplement ‘lvs’ API in OCaml.
This commit is contained in:
@@ -251,6 +251,7 @@ SOURCES_MLI = \
|
||||
is.mli \
|
||||
ldm.mli \
|
||||
link.mli \
|
||||
lvm.mli \
|
||||
mount.mli \
|
||||
mountable.mli \
|
||||
parted.mli \
|
||||
@@ -272,6 +273,7 @@ SOURCES_ML = \
|
||||
is.ml \
|
||||
ldm.ml \
|
||||
link.ml \
|
||||
lvm.ml \
|
||||
mount.ml \
|
||||
parted.ml \
|
||||
realpath.ml \
|
||||
|
||||
151
daemon/lvm.c
151
daemon/lvm.c
@@ -101,89 +101,6 @@ convert_lvm_output (char *out, const char *prefix)
|
||||
return take_stringsbuf (&ret);
|
||||
}
|
||||
|
||||
/* Filter a colon-separated output of
|
||||
* lvs -o lv_attr,vg_name,lv_name
|
||||
* removing thin layouts, and building the device path as we expect it.
|
||||
*
|
||||
* This is used only when lvm has no -S.
|
||||
*/
|
||||
static char **
|
||||
filter_convert_old_lvs_output (char *out)
|
||||
{
|
||||
char *p, *pend;
|
||||
CLEANUP_FREE_STRINGSBUF DECLARE_STRINGSBUF (ret);
|
||||
|
||||
p = out;
|
||||
while (p) {
|
||||
size_t len;
|
||||
char *saveptr;
|
||||
char *lv_attr, *vg_name, *lv_name;
|
||||
|
||||
pend = strchr (p, '\n'); /* Get the next line of output. */
|
||||
if (pend) {
|
||||
*pend = '\0';
|
||||
pend++;
|
||||
}
|
||||
|
||||
while (*p && c_isspace (*p)) /* Skip any leading whitespace. */
|
||||
p++;
|
||||
|
||||
/* Sigh, skip trailing whitespace too. "pvs", I'm looking at you. */
|
||||
len = strlen (p)-1;
|
||||
while (*p && c_isspace (p[len]))
|
||||
p[len--] = '\0';
|
||||
|
||||
if (!*p) { /* Empty line? Skip it. */
|
||||
skip_line:
|
||||
p = pend;
|
||||
continue;
|
||||
}
|
||||
|
||||
lv_attr = strtok_r (p, ":", &saveptr);
|
||||
if (!lv_attr)
|
||||
goto skip_line;
|
||||
|
||||
vg_name = strtok_r (NULL, ":", &saveptr);
|
||||
if (!vg_name)
|
||||
goto skip_line;
|
||||
|
||||
lv_name = strtok_r (NULL, ":", &saveptr);
|
||||
if (!lv_name)
|
||||
goto skip_line;
|
||||
|
||||
/* Ignore thin layouts (RHBZ#1278878). */
|
||||
if (lv_attr[0] == 't')
|
||||
goto skip_line;
|
||||
|
||||
/* Ignore activationskip (RHBZ#1306666). */
|
||||
if (strlen (lv_attr) >= 10 && lv_attr[9] == 'k')
|
||||
goto skip_line;
|
||||
|
||||
/* Ignore "unknown device" message (RHBZ#1054761). */
|
||||
if (STRNEQ (p, "unknown device")) {
|
||||
char buf[256];
|
||||
|
||||
snprintf (buf, sizeof buf, "/dev/%s/%s", vg_name, lv_name);
|
||||
if (add_string (&ret, buf) == -1) {
|
||||
free (out);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
p = pend;
|
||||
}
|
||||
|
||||
free (out);
|
||||
|
||||
if (ret.size > 0)
|
||||
sort_strings (ret.argv, ret.size);
|
||||
|
||||
if (end_stringsbuf (&ret) == -1)
|
||||
return NULL;
|
||||
|
||||
return take_stringsbuf (&ret);
|
||||
}
|
||||
|
||||
char **
|
||||
do_pvs (void)
|
||||
{
|
||||
@@ -220,74 +137,6 @@ do_vgs (void)
|
||||
return convert_lvm_output (out, NULL);
|
||||
}
|
||||
|
||||
/* Check whether lvs has -S to filter its output.
|
||||
* It is available only in lvm2 >= 2.02.107.
|
||||
*/
|
||||
static int
|
||||
test_lvs_has_S_opt (void)
|
||||
{
|
||||
static int result = -1;
|
||||
if (result != -1)
|
||||
return result;
|
||||
|
||||
CLEANUP_FREE char *out = NULL;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
|
||||
int r = command (&out, &err, "lvm", "lvs", "--help", NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("lvm lvs --help: %s", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strstr (out, "-S") == NULL)
|
||||
result = 0;
|
||||
else
|
||||
result = 1;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
char **
|
||||
do_lvs (void)
|
||||
{
|
||||
char *out;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r;
|
||||
const int has_S = test_lvs_has_S_opt ();
|
||||
|
||||
if (has_S < 0)
|
||||
return NULL;
|
||||
|
||||
if (has_S > 0) {
|
||||
r = command (&out, &err,
|
||||
"lvm", "lvs",
|
||||
"-o", "vg_name,lv_name",
|
||||
"-S", "lv_role=public && lv_skip_activation!=yes",
|
||||
"--noheadings",
|
||||
"--separator", "/", NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (out);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return convert_lvm_output (out, "/dev/");
|
||||
} else {
|
||||
r = command (&out, &err,
|
||||
"lvm", "lvs",
|
||||
"-o", "lv_attr,vg_name,lv_name",
|
||||
"--noheadings",
|
||||
"--separator", ":", NULL);
|
||||
if (r == -1) {
|
||||
reply_with_error ("%s", err);
|
||||
free (out);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return filter_convert_old_lvs_output (out);
|
||||
}
|
||||
}
|
||||
|
||||
/* These were so complex to implement that I ended up auto-generating
|
||||
* the code. That code is in stubs.c, and it is generated as usual
|
||||
* by generator.ml.
|
||||
|
||||
98
daemon/lvm.ml
Normal file
98
daemon/lvm.ml
Normal file
@@ -0,0 +1,98 @@
|
||||
(* guestfs-inspection
|
||||
* Copyright (C) 2009-2017 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.
|
||||
*)
|
||||
|
||||
open Printf
|
||||
|
||||
open Std_utils
|
||||
|
||||
open Utils
|
||||
|
||||
(* Check whether lvs has -S to filter its output.
|
||||
* It is available only in lvm2 >= 2.02.107.
|
||||
*)
|
||||
let lvs_has_S_opt = lazy (
|
||||
let out = command "lvm" ["lvs"; "--help"] in
|
||||
String.find out "-S" >= 0
|
||||
)
|
||||
|
||||
let rec lvs () =
|
||||
let has_S = Lazy.force lvs_has_S_opt in
|
||||
if has_S then (
|
||||
let out = command "lvm" ["lvs";
|
||||
"-o"; "vg_name,lv_name";
|
||||
"-S"; "lv_role=public && lv_skip_activation!=yes";
|
||||
"--noheadings";
|
||||
"--separator"; "/"] in
|
||||
convert_lvm_output ~prefix:"/dev/" out
|
||||
)
|
||||
else (
|
||||
let out = command "lvm" ["lvs";
|
||||
"-o"; "lv_attr,vg_name,lv_name";
|
||||
"--noheadings";
|
||||
"--separator"; ":"] in
|
||||
filter_convert_old_lvs_output out
|
||||
)
|
||||
|
||||
and convert_lvm_output ?prefix out =
|
||||
let lines = String.nsplit "\n" out in
|
||||
|
||||
(* Skip leading and trailing ("pvs", I'm looking at you) whitespace. *)
|
||||
let lines = List.map String.trim lines in
|
||||
|
||||
(* Skip empty lines. *)
|
||||
let lines = List.filter ((<>) "") lines in
|
||||
|
||||
(* Ignore "unknown device" message (RHBZ#1054761). *)
|
||||
let lines = List.filter ((<>) "unknown device") lines in
|
||||
|
||||
(* Add a prefix? *)
|
||||
let lines =
|
||||
match prefix with
|
||||
| None -> lines
|
||||
| Some prefix -> List.map ((^) prefix) lines in
|
||||
|
||||
(* Sort and return. *)
|
||||
List.sort compare lines
|
||||
|
||||
(* Filter a colon-separated output of
|
||||
* lvs -o lv_attr,vg_name,lv_name
|
||||
* removing thin layouts, and building the device path as we expect it.
|
||||
*
|
||||
* This is used only when lvm has no -S.
|
||||
*)
|
||||
and filter_convert_old_lvs_output out =
|
||||
let lines = String.nsplit "\n" out in
|
||||
let lines = List.map String.trim lines in
|
||||
let lines = List.filter ((<>) "") lines in
|
||||
let lines = List.filter ((<>) "unknown device") lines in
|
||||
|
||||
let lines = filter_map (
|
||||
fun line ->
|
||||
match String.nsplit ":" line with
|
||||
| [ lv_attr; vg_name; lv_name ] ->
|
||||
(* Ignore thin layouts (RHBZ#1278878). *)
|
||||
if String.length lv_attr > 0 && lv_attr.[0] = 't' then None
|
||||
(* Ignore activationskip (RHBZ#1306666). *)
|
||||
else if String.length lv_attr > 9 && lv_attr.[9] = 'k' then None
|
||||
else
|
||||
Some (sprintf "/dev/%s/%s" vg_name lv_name)
|
||||
| _ ->
|
||||
None
|
||||
) lines in
|
||||
|
||||
List.sort compare lines
|
||||
19
daemon/lvm.mli
Normal file
19
daemon/lvm.mli
Normal file
@@ -0,0 +1,19 @@
|
||||
(* guestfs-inspection
|
||||
* Copyright (C) 2009-2017 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.
|
||||
*)
|
||||
|
||||
val lvs : unit -> string list
|
||||
@@ -1732,6 +1732,7 @@ See also C<guestfs_vgs_full>." };
|
||||
{ defaults with
|
||||
name = "lvs"; added = (0, 0, 4);
|
||||
style = RStringList (RDevice, "logvols"), [], [];
|
||||
impl = OCaml "Lvm.lvs";
|
||||
optional = Some "lvm2";
|
||||
tests = [
|
||||
InitBasicFSonLVM, Always, TestResult (
|
||||
|
||||
Reference in New Issue
Block a user