1 /* libguestfs - the guestfsd daemon
2 * Copyright (C) 2011 Red Hat Inc.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
29 #include "optgroups.h"
32 optgroup_mdadm_available (void)
34 return prog_exists ("mdadm");
38 count_bits (uint64_t bitmap)
45 c = bitmap & 1 ? 1 : 0;
47 return c + count_bits (bitmap);
50 /* Takes optional arguments, consult optargs_bitmask. */
52 do_mdadm_create (const char *name, char *const *devices,
53 int64_t missingbitmap, int nrdevices, int spare,
54 int64_t chunk, const char *level)
62 uint64_t umissingbitmap = (uint64_t) missingbitmap;
64 /* Check the optional parameters and set defaults where appropriate. */
65 if (!(optargs_bitmask & GUESTFS_MDADM_CREATE_MISSINGBITMAP_BITMASK))
68 if (optargs_bitmask & GUESTFS_MDADM_CREATE_SPARE_BITMASK) {
70 reply_with_error ("spare must not be negative");
77 if (optargs_bitmask & GUESTFS_MDADM_CREATE_NRDEVICES_BITMASK) {
79 reply_with_error ("nrdevices is less than 2");
84 nrdevices = count_strings (devices) + count_bits (umissingbitmap);
86 if (optargs_bitmask & GUESTFS_MDADM_CREATE_LEVEL_BITMASK) {
87 if (STRNEQ (level, "linear") && STRNEQ (level, "raid0") &&
88 STRNEQ (level, "0") && STRNEQ (level, "stripe") &&
89 STRNEQ (level, "raid1") && STRNEQ (level, "1") &&
90 STRNEQ (level, "mirror") &&
91 STRNEQ (level, "raid4") && STRNEQ (level, "4") &&
92 STRNEQ (level, "raid5") && STRNEQ (level, "5") &&
93 STRNEQ (level, "raid6") && STRNEQ (level, "6") &&
94 STRNEQ (level, "raid10") && STRNEQ (level, "10")) {
95 reply_with_error ("unknown level parameter: %s", level);
102 if (optargs_bitmask & GUESTFS_MDADM_CREATE_CHUNK_BITMASK) {
103 /* chunk is bytes in the libguestfs API, but K when we pass it to mdadm */
104 if ((chunk & 1023) != 0) {
105 reply_with_error ("chunk size must be a multiple of 1024 bytes");
110 /* Check invariant. */
111 if (count_strings (devices) + count_bits (umissingbitmap) !=
112 (size_t) (nrdevices + spare)) {
113 reply_with_error ("devices (%zu) + bits set in missingbitmap (%zu) is not equal to nrdevices (%d) + spare (%d)",
114 count_strings (devices), count_bits (umissingbitmap),
119 size_t MAX_ARGS = nrdevices + 16;
120 const char *argv[MAX_ARGS];
123 ADD_ARG (argv, i, "mdadm");
124 ADD_ARG (argv, i, "--create");
125 /* --run suppresses "Continue creating array" question */
126 ADD_ARG (argv, i, "--run");
127 ADD_ARG (argv, i, name);
128 ADD_ARG (argv, i, "--level");
129 ADD_ARG (argv, i, level);
130 ADD_ARG (argv, i, "--raid-devices");
131 snprintf (nrdevices_s, sizeof nrdevices_s, "%d", nrdevices);
132 ADD_ARG (argv, i, nrdevices_s);
133 if (optargs_bitmask & GUESTFS_MDADM_CREATE_SPARE_BITMASK) {
134 ADD_ARG (argv, i, "--spare-devices");
135 snprintf (spare_s, sizeof spare_s, "%d", spare);
136 ADD_ARG (argv, i, spare_s);
138 if (optargs_bitmask & GUESTFS_MDADM_CREATE_CHUNK_BITMASK) {
139 ADD_ARG (argv, i, "--chunk");
140 snprintf (chunk_s, sizeof chunk_s, "%" PRIi64, chunk / 1024);
141 ADD_ARG (argv, i, chunk_s);
144 /* Add devices and "missing". */
146 while (devices[j] != NULL || umissingbitmap != 0) {
147 if (umissingbitmap & 1)
148 ADD_ARG (argv, i, "missing");
150 ADD_ARG (argv, i, devices[j]);
153 umissingbitmap >>= 1;
156 ADD_ARG (argv, i, NULL);
158 r = commandv (NULL, &err, argv);
160 reply_with_error ("mdadm: %s: %s", name, err);
173 glob_errfunc (const char *epath, int eerrno)
175 fprintf (stderr, "glob: failure reading %s: %s\n", epath, strerror (eerrno));
180 do_list_md_devices (void)
183 int size = 0, alloc = 0;
186 memset(&mds, 0, sizeof(mds));
188 #define PREFIX "/sys/block/md"
191 /* Look for directories under /sys/block matching md[0-9]*
192 * As an additional check, we also make sure they have a md subdirectory.
194 int err = glob (PREFIX "[0-9]*" SUFFIX, GLOB_ERR, glob_errfunc, &mds);
195 if (err == GLOB_NOSPACE) {
196 reply_with_error ("glob: returned GLOB_NOSPACE: "
197 "rerun with LIBGUESTFS_DEBUG=1");
199 } else if (err == GLOB_ABORTED) {
200 reply_with_error ("glob: returned GLOB_ABORTED: "
201 "rerun with LIBGUESTFS_DEBUG=1");
205 for (size_t i = 0; i < mds.gl_pathc; i++) {
206 size_t len = strlen (mds.gl_pathv[i]) - strlen (PREFIX) - strlen (SUFFIX);
208 #define DEV "/dev/md"
209 char *dev = malloc (strlen(DEV) + len + 1);
211 reply_with_perror("malloc");
216 n = mempcpy(n, DEV, strlen(DEV));
217 n = mempcpy(n, &mds.gl_pathv[i][strlen(PREFIX)], len);
220 if (add_string_nodup (&r, &size, &alloc, dev) == -1) goto error;
223 if (add_string_nodup (&r, &size, &alloc, NULL) == -1) goto error;
230 if (r != NULL) free_strings (r);