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"
33 optgroup_mdadm_available (void)
35 return prog_exists ("mdadm");
39 count_bits (uint64_t bitmap)
46 c = bitmap & 1 ? 1 : 0;
48 return c + count_bits (bitmap);
51 /* Takes optional arguments, consult optargs_bitmask. */
53 do_md_create (const char *name, char *const *devices,
54 int64_t missingbitmap, int nrdevices, int spare,
55 int64_t chunk, const char *level)
63 uint64_t umissingbitmap = (uint64_t) missingbitmap;
65 /* Check the optional parameters and set defaults where appropriate. */
66 if (!(optargs_bitmask & GUESTFS_MD_CREATE_MISSINGBITMAP_BITMASK))
69 if (optargs_bitmask & GUESTFS_MD_CREATE_SPARE_BITMASK) {
71 reply_with_error ("spare must not be negative");
78 if (optargs_bitmask & GUESTFS_MD_CREATE_NRDEVICES_BITMASK) {
80 reply_with_error ("nrdevices is less than 2");
85 nrdevices = count_strings (devices) + count_bits (umissingbitmap);
87 if (optargs_bitmask & GUESTFS_MD_CREATE_LEVEL_BITMASK) {
88 if (STRNEQ (level, "linear") && STRNEQ (level, "raid0") &&
89 STRNEQ (level, "0") && STRNEQ (level, "stripe") &&
90 STRNEQ (level, "raid1") && STRNEQ (level, "1") &&
91 STRNEQ (level, "mirror") &&
92 STRNEQ (level, "raid4") && STRNEQ (level, "4") &&
93 STRNEQ (level, "raid5") && STRNEQ (level, "5") &&
94 STRNEQ (level, "raid6") && STRNEQ (level, "6") &&
95 STRNEQ (level, "raid10") && STRNEQ (level, "10")) {
96 reply_with_error ("unknown level parameter: %s", level);
103 if (optargs_bitmask & GUESTFS_MD_CREATE_CHUNK_BITMASK) {
104 /* chunk is bytes in the libguestfs API, but K when we pass it to mdadm */
105 if ((chunk & 1023) != 0) {
106 reply_with_error ("chunk size must be a multiple of 1024 bytes");
111 /* Check invariant. */
112 if (count_strings (devices) + count_bits (umissingbitmap) !=
113 (size_t) (nrdevices + spare)) {
114 reply_with_error ("devices (%zu) + bits set in missingbitmap (%zu) is not equal to nrdevices (%d) + spare (%d)",
115 count_strings (devices), count_bits (umissingbitmap),
120 size_t MAX_ARGS = nrdevices + 16;
121 const char *argv[MAX_ARGS];
124 ADD_ARG (argv, i, "mdadm");
125 ADD_ARG (argv, i, "--create");
126 /* --run suppresses "Continue creating array" question */
127 ADD_ARG (argv, i, "--run");
128 ADD_ARG (argv, i, name);
129 ADD_ARG (argv, i, "--level");
130 ADD_ARG (argv, i, level);
131 ADD_ARG (argv, i, "--raid-devices");
132 snprintf (nrdevices_s, sizeof nrdevices_s, "%d", nrdevices);
133 ADD_ARG (argv, i, nrdevices_s);
134 if (optargs_bitmask & GUESTFS_MD_CREATE_SPARE_BITMASK) {
135 ADD_ARG (argv, i, "--spare-devices");
136 snprintf (spare_s, sizeof spare_s, "%d", spare);
137 ADD_ARG (argv, i, spare_s);
139 if (optargs_bitmask & GUESTFS_MD_CREATE_CHUNK_BITMASK) {
140 ADD_ARG (argv, i, "--chunk");
141 snprintf (chunk_s, sizeof chunk_s, "%" PRIi64, chunk / 1024);
142 ADD_ARG (argv, i, chunk_s);
145 /* Add devices and "missing". */
147 while (devices[j] != NULL || umissingbitmap != 0) {
148 if (umissingbitmap & 1)
149 ADD_ARG (argv, i, "missing");
151 ADD_ARG (argv, i, devices[j]);
154 umissingbitmap >>= 1;
157 ADD_ARG (argv, i, NULL);
159 r = commandv (NULL, &err, argv);
161 reply_with_error ("mdadm: %s: %s", name, err);
174 glob_errfunc (const char *epath, int eerrno)
176 fprintf (stderr, "glob: failure reading %s: %s\n", epath, strerror (eerrno));
181 do_list_md_devices (void)
184 int size = 0, alloc = 0;
187 memset(&mds, 0, sizeof(mds));
189 #define PREFIX "/sys/block/md"
192 /* Look for directories under /sys/block matching md[0-9]*
193 * As an additional check, we also make sure they have a md subdirectory.
195 int err = glob (PREFIX "[0-9]*" SUFFIX, GLOB_ERR, glob_errfunc, &mds);
196 if (err == GLOB_NOSPACE) {
197 reply_with_error ("glob: returned GLOB_NOSPACE: "
198 "rerun with LIBGUESTFS_DEBUG=1");
200 } else if (err == GLOB_ABORTED) {
201 reply_with_error ("glob: returned GLOB_ABORTED: "
202 "rerun with LIBGUESTFS_DEBUG=1");
206 for (size_t i = 0; i < mds.gl_pathc; i++) {
207 size_t len = strlen (mds.gl_pathv[i]) - strlen (PREFIX) - strlen (SUFFIX);
209 #define DEV "/dev/md"
210 char *dev = malloc (strlen(DEV) + len + 1);
212 reply_with_perror("malloc");
217 n = mempcpy(n, DEV, strlen(DEV));
218 n = mempcpy(n, &mds.gl_pathv[i][strlen(PREFIX)], len);
221 if (add_string_nodup (&r, &size, &alloc, dev) == -1) goto error;
224 if (add_string_nodup (&r, &size, &alloc, NULL) == -1) goto error;
231 if (r != NULL) free_strings (r);
236 do_md_detail(const char *md)
240 char *out = NULL, *err = NULL;
244 int size = 0, alloc = 0;
246 const char *mdadm[] = { "mdadm", "-D", "--export", md, NULL };
247 r = commandv(&out, &err, mdadm);
249 reply_with_error("%s", err);
253 /* Split the command output into lines */
254 lines = split_lines(out);
256 reply_with_perror("malloc");
260 /* Parse the output of mdadm -D --export:
264 * MD_UUID=cfa81b59:b6cfbd53:3f02085b:58f4a2e1
265 * MD_NAME=localhost.localdomain:0
267 for (char **i = lines; *i != NULL; i++) {
270 /* Skip blank lines (shouldn't happen) */
271 if (line[0] == '\0') continue;
273 /* Split the line in 2 at the equals sign */
274 char *eq = strchr(line, '=');
278 /* Remove the MD_ prefix from the key and translate the remainder to lower
280 if (STRPREFIX(line, "MD_")) {
282 for (char *j = line; *j != '\0'; j++) {
287 /* Add the key/value pair to the output */
288 if (add_string(&ret, &size, &alloc, line) == -1 ||
289 add_string(&ret, &size, &alloc, eq) == -1) goto error;
291 /* Ignore lines with no equals sign (shouldn't happen). Log to stderr so
292 * it will show up in LIBGUESTFS_DEBUG. */
293 fprintf(stderr, "md-detail: unexpected mdadm output ignored: %s", line);
299 free(lines); /* We freed the contained strings when we freed out */
301 if (add_string(&ret, &size, &alloc, NULL) == -1) return NULL;
308 if (lines) free(lines);
309 if (ret) free_strings(ret);
315 do_md_stop(const char *md)
320 const char *mdadm[] = { "mdadm", "--stop", md, NULL};
321 r = commandv(NULL, &err, mdadm);
323 reply_with_error("%s", err);