From 2ca0fa778de5e748f4545eddf9798e7a723fe07e Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Sun, 4 Jun 2017 09:35:31 +0100 Subject: [PATCH] =?UTF-8?q?daemon:=20Reimplement=20=E2=80=98list=5Fmd=5Fde?= =?UTF-8?q?vices=E2=80=99=20API=20in=20OCaml.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- daemon/Makefile.am | 2 + daemon/md.c | 125 ++++++++++---------------------------- daemon/md.ml | 48 +++++++++++++++ daemon/md.mli | 19 ++++++ generator/actions_core.ml | 1 + 5 files changed, 101 insertions(+), 94 deletions(-) create mode 100644 daemon/md.ml create mode 100644 daemon/md.mli diff --git a/daemon/Makefile.am b/daemon/Makefile.am index 2e723bfc8..873f6b394 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -252,6 +252,7 @@ SOURCES_MLI = \ ldm.mli \ link.mli \ lvm.mli \ + md.mli \ mount.mli \ mountable.mli \ parted.mli \ @@ -274,6 +275,7 @@ SOURCES_ML = \ ldm.ml \ link.ml \ lvm.ml \ + md.ml \ mount.ml \ parted.ml \ realpath.ml \ diff --git a/daemon/md.c b/daemon/md.c index 246e38150..55461b95a 100644 --- a/daemon/md.c +++ b/daemon/md.c @@ -24,7 +24,6 @@ #include #include #include -#include #ifdef HAVE_LINUX_RAID_MD_U_H #include @@ -32,6 +31,8 @@ #include #endif /* HAVE_LINUX_RAID_MD_U_H */ +#include + #include "daemon.h" #include "actions.h" #include "optgroups.h" @@ -43,6 +44,35 @@ optgroup_mdadm_available (void) return prog_exists ("mdadm"); } +/* Check if 'dev' is a real RAID device, because in the case where md + * is linked directly into the kernel (not a module), /dev/md0 is + * sometimes created. This is called from OCaml function + * Md.list_md_devices. + */ +extern value guestfs_int_daemon_is_raid_device (value devicev); + +/* NB: This is a "noalloc" call. */ +value +guestfs_int_daemon_is_raid_device (value devv) +{ + const char *dev = String_val (devv); + int ret = 1; + +#if defined(HAVE_LINUX_RAID_MD_U_H) && defined(GET_ARRAY_INFO) + int fd; + mdu_array_info_t array; + + fd = open (dev, O_RDONLY); + if (fd >= 0) { + if (ioctl (fd, GET_ARRAY_INFO, &array) == -1 && errno == ENODEV) + ret = 0; + close (fd); + } +#endif + + return Val_bool (ret); +} + static size_t count_bits (uint64_t bitmap) { @@ -186,99 +216,6 @@ do_md_create (const char *name, char *const *devices, #pragma GCC diagnostic pop #endif -static int -glob_errfunc (const char *epath, int eerrno) -{ - fprintf (stderr, "glob: failure reading %s: %s\n", epath, strerror (eerrno)); - return 1; -} - -/* Check if 'dev' is a real RAID device, because in the case where md - * is linked directly into the kernel (not a module), /dev/md0 is - * sometimes created. - */ -static int -is_raid_device (const char *dev) -{ - int ret = 1; - -#if defined(HAVE_LINUX_RAID_MD_U_H) && defined(GET_ARRAY_INFO) - int fd; - mdu_array_info_t array; - - fd = open (dev, O_RDONLY); - if (fd >= 0) { - if (ioctl (fd, GET_ARRAY_INFO, &array) == -1 && errno == ENODEV) - ret = 0; - close (fd); - } -#endif - - return ret; -} - -char ** -do_list_md_devices (void) -{ - CLEANUP_FREE_STRINGSBUF DECLARE_STRINGSBUF (ret); - glob_t mds; - - memset (&mds, 0, sizeof mds); - -#define PREFIX "/sys/block/md" -#define SUFFIX "/md" - - /* Look for directories under /sys/block matching md[0-9]* - * As an additional check, we also make sure they have a md subdirectory. - */ - const int err = glob (PREFIX "[0-9]*" SUFFIX, GLOB_ERR, glob_errfunc, &mds); - if (err == GLOB_NOSPACE) { - reply_with_error ("glob: returned GLOB_NOSPACE: " - "rerun with LIBGUESTFS_DEBUG=1"); - goto error; - } else if (err == GLOB_ABORTED) { - reply_with_error ("glob: returned GLOB_ABORTED: " - "rerun with LIBGUESTFS_DEBUG=1"); - goto error; - } - - for (size_t i = 0; i < mds.gl_pathc; i++) { - size_t len; - char *dev, *n; - - len = strlen (mds.gl_pathv[i]) - strlen (PREFIX) - strlen (SUFFIX); - -#define DEV "/dev/md" - dev = malloc (strlen (DEV) + len + 1); - if (NULL == dev) { - reply_with_perror ("malloc"); - goto error; - } - - n = dev; - n = mempcpy (n, DEV, strlen (DEV)); - n = mempcpy (n, &mds.gl_pathv[i][strlen (PREFIX)], len); - *n = '\0'; - - if (!is_raid_device (dev)) { - free (dev); - continue; - } - - if (add_string_nodup (&ret, dev) == -1) goto error; - } - - if (end_stringsbuf (&ret) == -1) goto error; - globfree (&mds); - - return take_stringsbuf (&ret); - - error: - globfree (&mds); - - return NULL; -} - char ** do_md_detail (const char *md) { diff --git a/daemon/md.ml b/daemon/md.ml new file mode 100644 index 000000000..caf87cf8f --- /dev/null +++ b/daemon/md.ml @@ -0,0 +1,48 @@ +(* 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 + +external is_raid_device : string -> bool = + "guestfs_int_daemon_is_raid_device" "noalloc" + +let re_md = Str.regexp "^md[0-9]+$" + +let list_md_devices () = + (* Look for directories under /sys/block matching md[0-9]+ + * As an additional check, we also make sure they have a md subdirectory. + *) + let devs = Sys.readdir "/sys/block" in + let devs = Array.to_list devs in + let devs = List.filter (fun d -> Str.string_match re_md d 0) devs in + let devs = List.filter ( + fun d -> is_directory (sprintf "/sys/block/%s/md" d) + ) devs in + + (* Construct the equivalent /dev/md[0-9]+ device names. *) + let devs = List.map ((^) "/dev/") devs in + + (* Check they are really RAID devices. *) + let devs = List.filter is_raid_device devs in + + (* Return the list sorted. *) + sort_device_names devs diff --git a/daemon/md.mli b/daemon/md.mli new file mode 100644 index 000000000..56b6ea65e --- /dev/null +++ b/daemon/md.mli @@ -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 list_md_devices : unit -> string list diff --git a/generator/actions_core.ml b/generator/actions_core.ml index f6f006eee..140ba6c1b 100644 --- a/generator/actions_core.ml +++ b/generator/actions_core.ml @@ -6632,6 +6632,7 @@ If not set, this defaults to C. { defaults with name = "list_md_devices"; added = (1, 15, 4); style = RStringList (RDevice, "devices"), [], []; + impl = OCaml "Md.list_md_devices"; shortdesc = "list Linux md (RAID) devices"; longdesc = "\ List all Linux md devices." };