1 /* $NetBSD: toollib.c,v 1.1.1.3 2009/12/02 00:25:56 haad Exp $ */
2
3 /*
4 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
5 * Copyright (C) 2004-2009 Red Hat, Inc. All rights reserved.
6 *
7 * This file is part of LVM2.
8 *
9 * This copyrighted material is made available to anyone wishing to use,
10 * modify, copy, or redistribute it subject to the terms and conditions
11 * of the GNU Lesser General Public License v.2.1.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, write to the Free Software Foundation,
15 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 */
17
18 #include "tools.h"
19 #include "lv_alloc.h"
20 #include "xlate.h"
21
22 #include <sys/stat.h>
23 #include <sys/wait.h>
24
command_name(struct cmd_context * cmd)25 const char *command_name(struct cmd_context *cmd)
26 {
27 return cmd->command->name;
28 }
29
30 /*
31 * Strip dev_dir if present
32 */
skip_dev_dir(struct cmd_context * cmd,const char * vg_name,unsigned * dev_dir_found)33 char *skip_dev_dir(struct cmd_context *cmd, const char *vg_name,
34 unsigned *dev_dir_found)
35 {
36 const char *dmdir = dm_dir();
37 size_t dmdir_len = strlen(dmdir), vglv_sz;
38 char *vgname, *lvname, *layer, *vglv;
39
40 /* FIXME Do this properly */
41 if (*vg_name == '/') {
42 while (*vg_name == '/')
43 vg_name++;
44 vg_name--;
45 }
46
47 /* Reformat string if /dev/mapper found */
48 if (!strncmp(vg_name, dmdir, dmdir_len) && vg_name[dmdir_len] == '/') {
49 if (dev_dir_found)
50 *dev_dir_found = 1;
51 vg_name += dmdir_len;
52 while (*vg_name == '/')
53 vg_name++;
54
55 if (!dm_split_lvm_name(cmd->mem, vg_name, &vgname, &lvname, &layer) ||
56 *layer) {
57 log_error("skip_dev_dir: Couldn't split up device name %s",
58 vg_name);
59 return (char *) vg_name;
60 }
61 vglv_sz = strlen(vgname) + strlen(lvname) + 2;
62 if (!(vglv = dm_pool_alloc(cmd->mem, vglv_sz)) ||
63 dm_snprintf(vglv, vglv_sz, "%s%s%s", vgname,
64 *lvname ? "/" : "",
65 lvname) < 0) {
66 log_error("vg/lv string alloc failed");
67 return (char *) vg_name;
68 }
69 return vglv;
70 }
71
72 if (!strncmp(vg_name, cmd->dev_dir, strlen(cmd->dev_dir))) {
73 if (dev_dir_found)
74 *dev_dir_found = 1;
75 vg_name += strlen(cmd->dev_dir);
76 while (*vg_name == '/')
77 vg_name++;
78 } else if (dev_dir_found)
79 *dev_dir_found = 0;
80
81 return (char *) vg_name;
82 }
83
84 /*
85 * Metadata iteration functions
86 */
process_each_lv_in_vg(struct cmd_context * cmd,const struct volume_group * vg,const struct dm_list * arg_lvnames,const struct dm_list * tags,void * handle,process_single_lv_fn_t process_single)87 int process_each_lv_in_vg(struct cmd_context *cmd,
88 const struct volume_group *vg,
89 const struct dm_list *arg_lvnames,
90 const struct dm_list *tags,
91 void *handle,
92 process_single_lv_fn_t process_single)
93 {
94 int ret_max = ECMD_PROCESSED;
95 int ret = 0;
96 unsigned process_all = 0;
97 unsigned process_lv = 0;
98 unsigned tags_supplied = 0;
99 unsigned lvargs_supplied = 0;
100 unsigned lvargs_matched = 0;
101
102 struct lv_list *lvl;
103
104 if (!vg_check_status(vg, EXPORTED_VG))
105 return ECMD_FAILED;
106
107 if (tags && !dm_list_empty(tags))
108 tags_supplied = 1;
109
110 if (arg_lvnames && !dm_list_empty(arg_lvnames))
111 lvargs_supplied = 1;
112
113 /* Process all LVs in this VG if no restrictions given */
114 if (!tags_supplied && !lvargs_supplied)
115 process_all = 1;
116
117 /* Or if VG tags match */
118 if (!process_lv && tags_supplied &&
119 str_list_match_list(tags, &vg->tags)) {
120 process_all = 1;
121 }
122
123 dm_list_iterate_items(lvl, &vg->lvs) {
124 if (lvl->lv->status & SNAPSHOT)
125 continue;
126
127 if (lv_is_virtual_origin(lvl->lv) && !arg_count(cmd, all_ARG))
128 continue;
129
130 /* Should we process this LV? */
131 if (process_all)
132 process_lv = 1;
133 else
134 process_lv = 0;
135
136 /* LV tag match? */
137 if (!process_lv && tags_supplied &&
138 str_list_match_list(tags, &lvl->lv->tags)) {
139 process_lv = 1;
140 }
141
142 /* LV name match? */
143 if (lvargs_supplied &&
144 str_list_match_item(arg_lvnames, lvl->lv->name)) {
145 process_lv = 1;
146 lvargs_matched++;
147 }
148
149 if (!process_lv)
150 continue;
151
152 ret = process_single(cmd, lvl->lv, handle);
153 if (ret > ret_max)
154 ret_max = ret;
155 if (sigint_caught())
156 return ret_max;
157 }
158
159 if (lvargs_supplied && lvargs_matched != dm_list_size(arg_lvnames)) {
160 log_error("One or more specified logical volume(s) not found.");
161 if (ret_max < ECMD_FAILED)
162 ret_max = ECMD_FAILED;
163 }
164
165 return ret_max;
166 }
167
process_each_lv(struct cmd_context * cmd,int argc,char ** argv,uint32_t flags,void * handle,int (* process_single)(struct cmd_context * cmd,struct logical_volume * lv,void * handle))168 int process_each_lv(struct cmd_context *cmd, int argc, char **argv,
169 uint32_t flags, void *handle,
170 int (*process_single) (struct cmd_context * cmd,
171 struct logical_volume * lv,
172 void *handle))
173 {
174 int opt = 0;
175 int ret_max = ECMD_PROCESSED;
176 int ret = 0;
177
178 struct dm_list *tags_arg;
179 struct dm_list *vgnames; /* VGs to process */
180 struct str_list *sll, *strl;
181 struct volume_group *vg;
182 struct dm_list tags, lvnames;
183 struct dm_list arg_lvnames; /* Cmdline vgname or vgname/lvname */
184 char *vglv;
185 size_t vglv_sz;
186
187 const char *vgname;
188
189 dm_list_init(&tags);
190 dm_list_init(&arg_lvnames);
191
192 if (argc) {
193 struct dm_list arg_vgnames;
194
195 log_verbose("Using logical volume(s) on command line");
196 dm_list_init(&arg_vgnames);
197
198 for (; opt < argc; opt++) {
199 const char *lv_name = argv[opt];
200 char *vgname_def;
201 unsigned dev_dir_found = 0;
202
203 /* Do we have a tag or vgname or lvname? */
204 vgname = lv_name;
205
206 if (*vgname == '@') {
207 if (!validate_name(vgname + 1)) {
208 log_error("Skipping invalid tag %s",
209 vgname);
210 continue;
211 }
212 if (!str_list_add(cmd->mem, &tags,
213 dm_pool_strdup(cmd->mem,
214 vgname + 1))) {
215 log_error("strlist allocation failed");
216 return ECMD_FAILED;
217 }
218 continue;
219 }
220
221 /* FIXME Jumbled parsing */
222 vgname = skip_dev_dir(cmd, vgname, &dev_dir_found);
223
224 if (*vgname == '/') {
225 log_error("\"%s\": Invalid path for Logical "
226 "Volume", argv[opt]);
227 if (ret_max < ECMD_FAILED)
228 ret_max = ECMD_FAILED;
229 continue;
230 }
231 lv_name = vgname;
232 if (strchr(vgname, '/')) {
233 /* Must be an LV */
234 lv_name = strchr(vgname, '/');
235 while (*lv_name == '/')
236 lv_name++;
237 if (!(vgname = extract_vgname(cmd, vgname))) {
238 if (ret_max < ECMD_FAILED)
239 ret_max = ECMD_FAILED;
240 continue;
241 }
242 } else if (!dev_dir_found &&
243 (vgname_def = default_vgname(cmd))) {
244 vgname = vgname_def;
245 } else
246 lv_name = NULL;
247
248 if (!str_list_add(cmd->mem, &arg_vgnames,
249 dm_pool_strdup(cmd->mem, vgname))) {
250 log_error("strlist allocation failed");
251 return ECMD_FAILED;
252 }
253
254 if (!lv_name) {
255 if (!str_list_add(cmd->mem, &arg_lvnames,
256 dm_pool_strdup(cmd->mem,
257 vgname))) {
258 log_error("strlist allocation failed");
259 return ECMD_FAILED;
260 }
261 } else {
262 vglv_sz = strlen(vgname) + strlen(lv_name) + 2;
263 if (!(vglv = dm_pool_alloc(cmd->mem, vglv_sz)) ||
264 dm_snprintf(vglv, vglv_sz, "%s/%s", vgname,
265 lv_name) < 0) {
266 log_error("vg/lv string alloc failed");
267 return ECMD_FAILED;
268 }
269 if (!str_list_add(cmd->mem, &arg_lvnames, vglv)) {
270 log_error("strlist allocation failed");
271 return ECMD_FAILED;
272 }
273 }
274 }
275 vgnames = &arg_vgnames;
276 }
277
278 if (!argc || !dm_list_empty(&tags)) {
279 log_verbose("Finding all logical volumes");
280 if (!(vgnames = get_vgnames(cmd, 0)) || dm_list_empty(vgnames)) {
281 log_error("No volume groups found");
282 return ret_max;
283 }
284 }
285
286 vg = NULL;
287 dm_list_iterate_items(strl, vgnames) {
288 vgname = strl->str;
289 if (is_orphan_vg(vgname))
290 continue; /* FIXME Unnecessary? */
291 vg = vg_read(cmd, vgname, NULL, flags);
292
293 if (vg_read_error(vg)) {
294 vg_release(vg);
295 if (ret_max < ECMD_FAILED) {
296 log_error("Skipping volume group %s", vgname);
297 ret_max = ECMD_FAILED;
298 } else
299 stack;
300 continue;
301 }
302
303 tags_arg = &tags;
304 dm_list_init(&lvnames); /* LVs to be processed in this VG */
305 dm_list_iterate_items(sll, &arg_lvnames) {
306 const char *vg_name = sll->str;
307 const char *lv_name = strchr(vg_name, '/');
308
309 if ((!lv_name && !strcmp(vg_name, vgname))) {
310 /* Process all LVs in this VG */
311 tags_arg = NULL;
312 dm_list_init(&lvnames);
313 break;
314 } else if (!strncmp(vg_name, vgname, strlen(vgname)) &&
315 strlen(vgname) == (size_t) (lv_name - vg_name)) {
316 if (!str_list_add(cmd->mem, &lvnames,
317 dm_pool_strdup(cmd->mem,
318 lv_name + 1))) {
319 log_error("strlist allocation failed");
320 vg_release(vg);
321 return ECMD_FAILED;
322 }
323 }
324 }
325
326 ret = process_each_lv_in_vg(cmd, vg, &lvnames, tags_arg,
327 handle, process_single);
328 unlock_and_release_vg(cmd, vg, vgname);
329 if (ret > ret_max)
330 ret_max = ret;
331 if (sigint_caught())
332 break;
333 }
334
335 return ret_max;
336 }
337
process_each_segment_in_pv(struct cmd_context * cmd,struct volume_group * vg,struct physical_volume * pv,void * handle,int (* process_single)(struct cmd_context * cmd,struct volume_group * vg,struct pv_segment * pvseg,void * handle))338 int process_each_segment_in_pv(struct cmd_context *cmd,
339 struct volume_group *vg,
340 struct physical_volume *pv,
341 void *handle,
342 int (*process_single) (struct cmd_context * cmd,
343 struct volume_group * vg,
344 struct pv_segment * pvseg,
345 void *handle))
346 {
347 struct pv_segment *pvseg;
348 struct pv_list *pvl;
349 const char *vg_name = NULL;
350 int ret_max = ECMD_PROCESSED;
351 int ret;
352 struct volume_group *old_vg = vg;
353 struct pv_segment _free_pv_segment = { .pv = pv };
354
355 if (is_pv(pv) && !vg && !is_orphan(pv)) {
356 vg_name = pv_vg_name(pv);
357
358 vg = vg_read(cmd, vg_name, NULL, 0);
359 if (vg_read_error(vg)) {
360 vg_release(vg);
361 log_error("Skipping volume group %s", vg_name);
362 return ECMD_FAILED;
363 }
364
365 /*
366 * Replace possibly incomplete PV structure with new one
367 * allocated in vg_read_internal() path.
368 */
369 if (!(pvl = find_pv_in_vg(vg, pv_dev_name(pv)))) {
370 log_error("Unable to find %s in volume group %s",
371 pv_dev_name(pv), vg_name);
372 vg_release(vg);
373 return ECMD_FAILED;
374 }
375
376 pv = pvl->pv;
377 }
378
379 if (dm_list_empty(&pv->segments)) {
380 ret = process_single(cmd, NULL, &_free_pv_segment, handle);
381 if (ret > ret_max)
382 ret_max = ret;
383 } else
384 dm_list_iterate_items(pvseg, &pv->segments) {
385 ret = process_single(cmd, vg, pvseg, handle);
386 if (ret > ret_max)
387 ret_max = ret;
388 if (sigint_caught())
389 break;
390 }
391
392 if (vg_name)
393 unlock_vg(cmd, vg_name);
394 if (!old_vg)
395 vg_release(vg);
396
397 return ret_max;
398 }
399
process_each_segment_in_lv(struct cmd_context * cmd,struct logical_volume * lv,void * handle,int (* process_single)(struct cmd_context * cmd,struct lv_segment * seg,void * handle))400 int process_each_segment_in_lv(struct cmd_context *cmd,
401 struct logical_volume *lv,
402 void *handle,
403 int (*process_single) (struct cmd_context * cmd,
404 struct lv_segment * seg,
405 void *handle))
406 {
407 struct lv_segment *seg;
408 int ret_max = ECMD_PROCESSED;
409 int ret;
410
411 dm_list_iterate_items(seg, &lv->segments) {
412 ret = process_single(cmd, seg, handle);
413 if (ret > ret_max)
414 ret_max = ret;
415 if (sigint_caught())
416 break;
417 }
418
419 return ret_max;
420 }
421
_process_one_vg(struct cmd_context * cmd,const char * vg_name,const char * vgid,struct dm_list * tags,struct dm_list * arg_vgnames,uint32_t flags,void * handle,int ret_max,int (* process_single)(struct cmd_context * cmd,const char * vg_name,struct volume_group * vg,void * handle))422 static int _process_one_vg(struct cmd_context *cmd, const char *vg_name,
423 const char *vgid,
424 struct dm_list *tags, struct dm_list *arg_vgnames,
425 uint32_t flags, void *handle, int ret_max,
426 int (*process_single) (struct cmd_context * cmd,
427 const char *vg_name,
428 struct volume_group * vg,
429 void *handle))
430 {
431 struct volume_group *vg;
432 int ret = 0;
433
434 log_verbose("Finding volume group \"%s\"", vg_name);
435
436 vg = vg_read(cmd, vg_name, vgid, flags);
437 /* Allow FAILED_INCONSISTENT through only for vgcfgrestore */
438 if (vg_read_error(vg) &&
439 !((vg_read_error(vg) == FAILED_INCONSISTENT) &&
440 (flags & READ_ALLOW_INCONSISTENT))) {
441 ret_max = ECMD_FAILED;
442 goto_out;
443 }
444
445 if (!dm_list_empty(tags)) {
446 /* Only process if a tag matches or it's on arg_vgnames */
447 if (!str_list_match_item(arg_vgnames, vg_name) &&
448 !str_list_match_list(tags, &vg->tags))
449 goto out;
450 }
451
452 if ((ret = process_single(cmd, vg_name, vg,
453 handle)) > ret_max)
454 ret_max = ret;
455
456 out:
457 if (vg_read_error(vg))
458 vg_release(vg);
459 else
460 unlock_and_release_vg(cmd, vg, vg_name);
461 return ret_max;
462 }
463
process_each_vg(struct cmd_context * cmd,int argc,char ** argv,uint32_t flags,void * handle,int (* process_single)(struct cmd_context * cmd,const char * vg_name,struct volume_group * vg,void * handle))464 int process_each_vg(struct cmd_context *cmd, int argc, char **argv,
465 uint32_t flags, void *handle,
466 int (*process_single) (struct cmd_context * cmd,
467 const char *vg_name,
468 struct volume_group * vg,
469 void *handle))
470 {
471 int opt = 0;
472 int ret_max = ECMD_PROCESSED;
473
474 struct str_list *sl;
475 struct dm_list *vgnames, *vgids;
476 struct dm_list arg_vgnames, tags;
477
478 const char *vg_name, *vgid;
479
480 dm_list_init(&tags);
481 dm_list_init(&arg_vgnames);
482
483 if (argc) {
484 log_verbose("Using volume group(s) on command line");
485
486 for (; opt < argc; opt++) {
487 vg_name = argv[opt];
488 if (*vg_name == '@') {
489 if (!validate_name(vg_name + 1)) {
490 log_error("Skipping invalid tag %s",
491 vg_name);
492 if (ret_max < EINVALID_CMD_LINE)
493 ret_max = EINVALID_CMD_LINE;
494 continue;
495 }
496 if (!str_list_add(cmd->mem, &tags,
497 dm_pool_strdup(cmd->mem,
498 vg_name + 1))) {
499 log_error("strlist allocation failed");
500 return ECMD_FAILED;
501 }
502 continue;
503 }
504
505 vg_name = skip_dev_dir(cmd, vg_name, NULL);
506 if (strchr(vg_name, '/')) {
507 log_error("Invalid volume group name: %s",
508 vg_name);
509 if (ret_max < EINVALID_CMD_LINE)
510 ret_max = EINVALID_CMD_LINE;
511 continue;
512 }
513 if (!str_list_add(cmd->mem, &arg_vgnames,
514 dm_pool_strdup(cmd->mem, vg_name))) {
515 log_error("strlist allocation failed");
516 return ECMD_FAILED;
517 }
518 }
519
520 vgnames = &arg_vgnames;
521 }
522
523 if (!argc || !dm_list_empty(&tags)) {
524 log_verbose("Finding all volume groups");
525 if (!(vgids = get_vgids(cmd, 0)) || dm_list_empty(vgids)) {
526 log_error("No volume groups found");
527 return ret_max;
528 }
529 dm_list_iterate_items(sl, vgids) {
530 vgid = sl->str;
531 if (!vgid || !(vg_name = vgname_from_vgid(cmd->mem, vgid)) ||
532 is_orphan_vg(vg_name))
533 continue;
534 ret_max = _process_one_vg(cmd, vg_name, vgid, &tags,
535 &arg_vgnames,
536 flags, handle,
537 ret_max, process_single);
538 if (sigint_caught())
539 return ret_max;
540 }
541 } else {
542 dm_list_iterate_items(sl, vgnames) {
543 vg_name = sl->str;
544 if (is_orphan_vg(vg_name))
545 continue; /* FIXME Unnecessary? */
546 ret_max = _process_one_vg(cmd, vg_name, NULL, &tags,
547 &arg_vgnames,
548 flags, handle,
549 ret_max, process_single);
550 if (sigint_caught())
551 return ret_max;
552 }
553 }
554
555 return ret_max;
556 }
557
process_each_pv_in_vg(struct cmd_context * cmd,struct volume_group * vg,const struct dm_list * tags,void * handle,process_single_pv_fn_t process_single)558 int process_each_pv_in_vg(struct cmd_context *cmd, struct volume_group *vg,
559 const struct dm_list *tags, void *handle,
560 process_single_pv_fn_t process_single)
561 {
562 int ret_max = ECMD_PROCESSED;
563 int ret = 0;
564 struct pv_list *pvl;
565
566 dm_list_iterate_items(pvl, &vg->pvs) {
567 if (tags && !dm_list_empty(tags) &&
568 !str_list_match_list(tags, &pvl->pv->tags)) {
569 continue;
570 }
571 if ((ret = process_single(cmd, vg, pvl->pv, handle)) > ret_max)
572 ret_max = ret;
573 if (sigint_caught())
574 return ret_max;
575 }
576
577 return ret_max;
578 }
579
_process_all_devs(struct cmd_context * cmd,void * handle,int (* process_single)(struct cmd_context * cmd,struct volume_group * vg,struct physical_volume * pv,void * handle))580 static int _process_all_devs(struct cmd_context *cmd, void *handle,
581 int (*process_single) (struct cmd_context * cmd,
582 struct volume_group * vg,
583 struct physical_volume * pv,
584 void *handle))
585 {
586 struct physical_volume *pv;
587 struct physical_volume pv_dummy;
588 struct dev_iter *iter;
589 struct device *dev;
590
591 int ret_max = ECMD_PROCESSED;
592 int ret = 0;
593
594 if (!scan_vgs_for_pvs(cmd)) {
595 stack;
596 return ECMD_FAILED;
597 }
598
599 if (!(iter = dev_iter_create(cmd->filter, 1))) {
600 log_error("dev_iter creation failed");
601 return ECMD_FAILED;
602 }
603
604 while ((dev = dev_iter_get(iter))) {
605 if (!(pv = pv_read(cmd, dev_name(dev), NULL, NULL, 0, 0))) {
606 memset(&pv_dummy, 0, sizeof(pv_dummy));
607 dm_list_init(&pv_dummy.tags);
608 dm_list_init(&pv_dummy.segments);
609 pv_dummy.dev = dev;
610 pv_dummy.fmt = NULL;
611 pv = &pv_dummy;
612 }
613 ret = process_single(cmd, NULL, pv, handle);
614 if (ret > ret_max)
615 ret_max = ret;
616 if (sigint_caught())
617 break;
618 }
619
620 dev_iter_destroy(iter);
621
622 return ret_max;
623 }
624
625 /*
626 * If the lock_type is LCK_VG_READ (used only in reporting commands),
627 * we lock VG_GLOBAL to enable use of metadata cache.
628 * This can pause alongide pvscan or vgscan process for a while.
629 */
process_each_pv(struct cmd_context * cmd,int argc,char ** argv,struct volume_group * vg,uint32_t flags,int scan_label_only,void * handle,int (* process_single)(struct cmd_context * cmd,struct volume_group * vg,struct physical_volume * pv,void * handle))630 int process_each_pv(struct cmd_context *cmd, int argc, char **argv,
631 struct volume_group *vg, uint32_t flags,
632 int scan_label_only, void *handle,
633 int (*process_single) (struct cmd_context * cmd,
634 struct volume_group * vg,
635 struct physical_volume * pv,
636 void *handle))
637 {
638 int opt = 0;
639 int ret_max = ECMD_PROCESSED;
640 int ret = 0;
641 int lock_global = !(flags & READ_WITHOUT_LOCK) && !(flags & READ_FOR_UPDATE);
642
643 struct pv_list *pvl;
644 struct physical_volume *pv;
645 struct dm_list *pvslist, *vgnames;
646 struct dm_list tags;
647 struct str_list *sll;
648 char *tagname;
649 int scanned = 0;
650
651 dm_list_init(&tags);
652
653 if (lock_global && !lock_vol(cmd, VG_GLOBAL, LCK_VG_READ)) {
654 log_error("Unable to obtain global lock.");
655 return ECMD_FAILED;
656 }
657
658 if (argc) {
659 log_verbose("Using physical volume(s) on command line");
660 for (; opt < argc; opt++) {
661 if (*argv[opt] == '@') {
662 tagname = argv[opt] + 1;
663
664 if (!validate_name(tagname)) {
665 log_error("Skipping invalid tag %s",
666 tagname);
667 if (ret_max < EINVALID_CMD_LINE)
668 ret_max = EINVALID_CMD_LINE;
669 continue;
670 }
671 if (!str_list_add(cmd->mem, &tags,
672 dm_pool_strdup(cmd->mem,
673 tagname))) {
674 log_error("strlist allocation failed");
675 goto bad;
676 }
677 continue;
678 }
679 if (vg) {
680 if (!(pvl = find_pv_in_vg(vg, argv[opt]))) {
681 log_error("Physical Volume \"%s\" not "
682 "found in Volume Group "
683 "\"%s\"", argv[opt],
684 vg->name);
685 ret_max = ECMD_FAILED;
686 continue;
687 }
688 pv = pvl->pv;
689 } else {
690 if (!(pv = pv_read(cmd, argv[opt], NULL,
691 NULL, 1, scan_label_only))) {
692 log_error("Failed to read physical "
693 "volume \"%s\"", argv[opt]);
694 ret_max = ECMD_FAILED;
695 continue;
696 }
697
698 /*
699 * If a PV has no MDAs it may appear to be an
700 * orphan until the metadata is read off
701 * another PV in the same VG. Detecting this
702 * means checking every VG by scanning every
703 * PV on the system.
704 */
705 if (!scanned && is_orphan(pv)) {
706 if (!scan_label_only &&
707 !scan_vgs_for_pvs(cmd)) {
708 stack;
709 ret_max = ECMD_FAILED;
710 continue;
711 }
712 scanned = 1;
713 if (!(pv = pv_read(cmd, argv[opt],
714 NULL, NULL, 1,
715 scan_label_only))) {
716 log_error("Failed to read "
717 "physical volume "
718 "\"%s\"", argv[opt]);
719 ret_max = ECMD_FAILED;
720 continue;
721 }
722 }
723 }
724
725 ret = process_single(cmd, vg, pv, handle);
726 if (ret > ret_max)
727 ret_max = ret;
728 if (sigint_caught())
729 goto out;
730 }
731 if (!dm_list_empty(&tags) && (vgnames = get_vgnames(cmd, 0)) &&
732 !dm_list_empty(vgnames)) {
733 dm_list_iterate_items(sll, vgnames) {
734 vg = vg_read(cmd, sll->str, NULL, flags);
735 if (vg_read_error(vg)) {
736 ret_max = ECMD_FAILED;
737 vg_release(vg);
738 stack;
739 continue;
740 }
741
742 ret = process_each_pv_in_vg(cmd, vg, &tags,
743 handle,
744 process_single);
745
746 unlock_and_release_vg(cmd, vg, sll->str);
747
748 if (ret > ret_max)
749 ret_max = ret;
750 if (sigint_caught())
751 goto out;
752 }
753 }
754 } else {
755 if (vg) {
756 log_verbose("Using all physical volume(s) in "
757 "volume group");
758 ret = process_each_pv_in_vg(cmd, vg, NULL, handle,
759 process_single);
760 if (ret > ret_max)
761 ret_max = ret;
762 if (sigint_caught())
763 goto out;
764 } else if (arg_count(cmd, all_ARG)) {
765 ret = _process_all_devs(cmd, handle, process_single);
766 if (ret > ret_max)
767 ret_max = ret;
768 if (sigint_caught())
769 goto out;
770 } else {
771 log_verbose("Scanning for physical volume names");
772
773 if (!(pvslist = get_pvs(cmd)))
774 goto bad;
775
776 dm_list_iterate_items(pvl, pvslist) {
777 ret = process_single(cmd, NULL, pvl->pv,
778 handle);
779 if (ret > ret_max)
780 ret_max = ret;
781 if (sigint_caught())
782 goto out;
783 }
784 }
785 }
786 out:
787 if (lock_global)
788 unlock_vg(cmd, VG_GLOBAL);
789 return ret_max;
790 bad:
791 if (lock_global)
792 unlock_vg(cmd, VG_GLOBAL);
793
794 return ECMD_FAILED;
795 }
796
797 /*
798 * Determine volume group name from a logical volume name
799 */
extract_vgname(struct cmd_context * cmd,const char * lv_name)800 const char *extract_vgname(struct cmd_context *cmd, const char *lv_name)
801 {
802 const char *vg_name = lv_name;
803 char *st;
804 char *dev_dir = cmd->dev_dir;
805 int dev_dir_provided = 0;
806
807 /* Path supplied? */
808 if (vg_name && strchr(vg_name, '/')) {
809 /* Strip dev_dir (optional) */
810 if (*vg_name == '/') {
811 while (*vg_name == '/')
812 vg_name++;
813 vg_name--;
814 }
815 if (!strncmp(vg_name, dev_dir, strlen(dev_dir))) {
816 vg_name += strlen(dev_dir);
817 dev_dir_provided = 1;
818 while (*vg_name == '/')
819 vg_name++;
820 }
821 if (*vg_name == '/') {
822 log_error("\"%s\": Invalid path for Logical "
823 "Volume", lv_name);
824 return 0;
825 }
826
827 /* Require exactly one set of consecutive slashes */
828 if ((st = strchr(vg_name, '/')))
829 while (*st == '/')
830 st++;
831
832 if (!strchr(vg_name, '/') || strchr(st, '/')) {
833 log_error("\"%s\": Invalid path for Logical Volume",
834 lv_name);
835 return 0;
836 }
837
838 vg_name = dm_pool_strdup(cmd->mem, vg_name);
839 if (!vg_name) {
840 log_error("Allocation of vg_name failed");
841 return 0;
842 }
843
844 *strchr(vg_name, '/') = '\0';
845 return vg_name;
846 }
847
848 if (!(vg_name = default_vgname(cmd))) {
849 if (lv_name)
850 log_error("Path required for Logical Volume \"%s\"",
851 lv_name);
852 return 0;
853 }
854
855 return vg_name;
856 }
857
858 /*
859 * Extract default volume group name from environment
860 */
default_vgname(struct cmd_context * cmd)861 char *default_vgname(struct cmd_context *cmd)
862 {
863 char *vg_path;
864
865 /* Take default VG from environment? */
866 vg_path = getenv("LVM_VG_NAME");
867 if (!vg_path)
868 return 0;
869
870 vg_path = skip_dev_dir(cmd, vg_path, NULL);
871
872 if (strchr(vg_path, '/')) {
873 log_error("Environment Volume Group in LVM_VG_NAME invalid: "
874 "\"%s\"", vg_path);
875 return 0;
876 }
877
878 return dm_pool_strdup(cmd->mem, vg_path);
879 }
880
881 /*
882 * Process physical extent range specifiers
883 */
_add_pe_range(struct dm_pool * mem,const char * pvname,struct dm_list * pe_ranges,uint32_t start,uint32_t count)884 static int _add_pe_range(struct dm_pool *mem, const char *pvname,
885 struct dm_list *pe_ranges, uint32_t start, uint32_t count)
886 {
887 struct pe_range *per;
888
889 log_debug("Adding PE range: start PE %" PRIu32 " length %" PRIu32
890 " on %s", start, count, pvname);
891
892 /* Ensure no overlap with existing areas */
893 dm_list_iterate_items(per, pe_ranges) {
894 if (((start < per->start) && (start + count - 1 >= per->start))
895 || ((start >= per->start) &&
896 (per->start + per->count - 1) >= start)) {
897 log_error("Overlapping PE ranges specified (%" PRIu32
898 "-%" PRIu32 ", %" PRIu32 "-%" PRIu32 ")"
899 " on %s",
900 start, start + count - 1, per->start,
901 per->start + per->count - 1, pvname);
902 return 0;
903 }
904 }
905
906 if (!(per = dm_pool_alloc(mem, sizeof(*per)))) {
907 log_error("Allocation of list failed");
908 return 0;
909 }
910
911 per->start = start;
912 per->count = count;
913 dm_list_add(pe_ranges, &per->list);
914
915 return 1;
916 }
917
xstrtouint32(const char * s,char ** p,int base,uint32_t * result)918 static int xstrtouint32(const char *s, char **p, int base, uint32_t *result)
919 {
920 unsigned long ul;
921
922 errno = 0;
923 ul = strtoul(s, p, base);
924 if (errno || *p == s || (uint32_t) ul != ul)
925 return -1;
926 *result = ul;
927 return 0;
928 }
929
_parse_pes(struct dm_pool * mem,char * c,struct dm_list * pe_ranges,const char * pvname,uint32_t size)930 static int _parse_pes(struct dm_pool *mem, char *c, struct dm_list *pe_ranges,
931 const char *pvname, uint32_t size)
932 {
933 char *endptr;
934 uint32_t start, end;
935
936 /* Default to whole PV */
937 if (!c) {
938 if (!_add_pe_range(mem, pvname, pe_ranges, UINT32_C(0), size))
939 return_0;
940 return 1;
941 }
942
943 while (*c) {
944 if (*c != ':')
945 goto error;
946
947 c++;
948
949 /* Disallow :: and :\0 */
950 if (*c == ':' || !*c)
951 goto error;
952
953 /* Default to whole range */
954 start = UINT32_C(0);
955 end = size - 1;
956
957 /* Start extent given? */
958 if (isdigit(*c)) {
959 if (xstrtouint32(c, &endptr, 10, &start))
960 goto error;
961 c = endptr;
962 /* Just one number given? */
963 if (!*c || *c == ':')
964 end = start;
965 }
966 /* Range? */
967 if (*c == '-') {
968 c++;
969 if (isdigit(*c)) {
970 if (xstrtouint32(c, &endptr, 10, &end))
971 goto error;
972 c = endptr;
973 }
974 }
975 if (*c && *c != ':')
976 goto error;
977
978 if ((start > end) || (end > size - 1)) {
979 log_error("PE range error: start extent %" PRIu32 " to "
980 "end extent %" PRIu32, start, end);
981 return 0;
982 }
983
984 if (!_add_pe_range(mem, pvname, pe_ranges, start, end - start + 1))
985 return_0;
986
987 }
988
989 return 1;
990
991 error:
992 log_error("Physical extent parsing error at %s", c);
993 return 0;
994 }
995
_create_pv_entry(struct dm_pool * mem,struct pv_list * pvl,char * colon,int allocatable_only,struct dm_list * r)996 static int _create_pv_entry(struct dm_pool *mem, struct pv_list *pvl,
997 char *colon, int allocatable_only, struct dm_list *r)
998 {
999 const char *pvname;
1000 struct pv_list *new_pvl = NULL, *pvl2;
1001 struct dm_list *pe_ranges;
1002
1003 pvname = pv_dev_name(pvl->pv);
1004 if (allocatable_only && !(pvl->pv->status & ALLOCATABLE_PV)) {
1005 log_error("Physical volume %s not allocatable", pvname);
1006 return 1;
1007 }
1008
1009 if (allocatable_only && (pvl->pv->status & MISSING_PV)) {
1010 log_error("Physical volume %s is missing", pvname);
1011 return 1;
1012 }
1013
1014 if (allocatable_only &&
1015 (pvl->pv->pe_count == pvl->pv->pe_alloc_count)) {
1016 log_error("No free extents on physical volume \"%s\"", pvname);
1017 return 1;
1018 }
1019
1020 dm_list_iterate_items(pvl2, r)
1021 if (pvl->pv->dev == pvl2->pv->dev) {
1022 new_pvl = pvl2;
1023 break;
1024 }
1025
1026 if (!new_pvl) {
1027 if (!(new_pvl = dm_pool_alloc(mem, sizeof(*new_pvl)))) {
1028 log_error("Unable to allocate physical volume list.");
1029 return 0;
1030 }
1031
1032 memcpy(new_pvl, pvl, sizeof(*new_pvl));
1033
1034 if (!(pe_ranges = dm_pool_alloc(mem, sizeof(*pe_ranges)))) {
1035 log_error("Allocation of pe_ranges list failed");
1036 return 0;
1037 }
1038 dm_list_init(pe_ranges);
1039 new_pvl->pe_ranges = pe_ranges;
1040 dm_list_add(r, &new_pvl->list);
1041 }
1042
1043 /* Determine selected physical extents */
1044 if (!_parse_pes(mem, colon, new_pvl->pe_ranges, pv_dev_name(pvl->pv),
1045 pvl->pv->pe_count))
1046 return_0;
1047
1048 return 1;
1049 }
1050
create_pv_list(struct dm_pool * mem,struct volume_group * vg,int argc,char ** argv,int allocatable_only)1051 struct dm_list *create_pv_list(struct dm_pool *mem, struct volume_group *vg, int argc,
1052 char **argv, int allocatable_only)
1053 {
1054 struct dm_list *r;
1055 struct pv_list *pvl;
1056 struct dm_list tags, arg_pvnames;
1057 const char *pvname = NULL;
1058 char *colon, *tagname;
1059 int i;
1060
1061 /* Build up list of PVs */
1062 if (!(r = dm_pool_alloc(mem, sizeof(*r)))) {
1063 log_error("Allocation of list failed");
1064 return NULL;
1065 }
1066 dm_list_init(r);
1067
1068 dm_list_init(&tags);
1069 dm_list_init(&arg_pvnames);
1070
1071 for (i = 0; i < argc; i++) {
1072 if (*argv[i] == '@') {
1073 tagname = argv[i] + 1;
1074 if (!validate_name(tagname)) {
1075 log_error("Skipping invalid tag %s", tagname);
1076 continue;
1077 }
1078 dm_list_iterate_items(pvl, &vg->pvs) {
1079 if (str_list_match_item(&pvl->pv->tags,
1080 tagname)) {
1081 if (!_create_pv_entry(mem, pvl, NULL,
1082 allocatable_only,
1083 r))
1084 return_NULL;
1085 }
1086 }
1087 continue;
1088 }
1089
1090 pvname = argv[i];
1091
1092 if ((colon = strchr(pvname, ':'))) {
1093 if (!(pvname = dm_pool_strndup(mem, pvname,
1094 (unsigned) (colon -
1095 pvname)))) {
1096 log_error("Failed to clone PV name");
1097 return NULL;
1098 }
1099 }
1100
1101 if (!(pvl = find_pv_in_vg(vg, pvname))) {
1102 log_error("Physical Volume \"%s\" not found in "
1103 "Volume Group \"%s\"", pvname, vg->name);
1104 return NULL;
1105 }
1106 if (!_create_pv_entry(mem, pvl, colon, allocatable_only, r))
1107 return_NULL;
1108 }
1109
1110 if (dm_list_empty(r))
1111 log_error("No specified PVs have space available");
1112
1113 return dm_list_empty(r) ? NULL : r;
1114 }
1115
clone_pv_list(struct dm_pool * mem,struct dm_list * pvsl)1116 struct dm_list *clone_pv_list(struct dm_pool *mem, struct dm_list *pvsl)
1117 {
1118 struct dm_list *r;
1119 struct pv_list *pvl, *new_pvl;
1120
1121 /* Build up list of PVs */
1122 if (!(r = dm_pool_alloc(mem, sizeof(*r)))) {
1123 log_error("Allocation of list failed");
1124 return NULL;
1125 }
1126 dm_list_init(r);
1127
1128 dm_list_iterate_items(pvl, pvsl) {
1129 if (!(new_pvl = dm_pool_zalloc(mem, sizeof(*new_pvl)))) {
1130 log_error("Unable to allocate physical volume list.");
1131 return NULL;
1132 }
1133
1134 memcpy(new_pvl, pvl, sizeof(*new_pvl));
1135 dm_list_add(r, &new_pvl->list);
1136 }
1137
1138 return r;
1139 }
1140
apply_lvname_restrictions(const char * name)1141 int apply_lvname_restrictions(const char *name)
1142 {
1143 if (!strncmp(name, "snapshot", 8)) {
1144 log_error("Names starting \"snapshot\" are reserved. "
1145 "Please choose a different LV name.");
1146 return 0;
1147 }
1148
1149 if (!strncmp(name, "pvmove", 6)) {
1150 log_error("Names starting \"pvmove\" are reserved. "
1151 "Please choose a different LV name.");
1152 return 0;
1153 }
1154
1155 if (strstr(name, "_mlog")) {
1156 log_error("Names including \"_mlog\" are reserved. "
1157 "Please choose a different LV name.");
1158 return 0;
1159 }
1160
1161 if (strstr(name, "_mimage")) {
1162 log_error("Names including \"_mimage\" are reserved. "
1163 "Please choose a different LV name.");
1164 return 0;
1165 }
1166
1167 if (strstr(name, "_vorigin")) {
1168 log_error("Names including \"_vorigin\" are reserved. "
1169 "Please choose a different LV name.");
1170 return 0;
1171 }
1172
1173 return 1;
1174 }
1175
is_reserved_lvname(const char * name)1176 int is_reserved_lvname(const char *name)
1177 {
1178 int rc, old_suppress;
1179
1180 old_suppress = log_suppress(2);
1181 rc = !apply_lvname_restrictions(name);
1182 log_suppress(old_suppress);
1183
1184 return rc;
1185 }
1186
vgcreate_params_set_defaults(struct vgcreate_params * vp_def,struct volume_group * vg)1187 void vgcreate_params_set_defaults(struct vgcreate_params *vp_def,
1188 struct volume_group *vg)
1189 {
1190 if (vg) {
1191 vp_def->vg_name = NULL;
1192 vp_def->extent_size = vg->extent_size;
1193 vp_def->max_pv = vg->max_pv;
1194 vp_def->max_lv = vg->max_lv;
1195 vp_def->alloc = vg->alloc;
1196 vp_def->clustered = vg_is_clustered(vg);
1197 } else {
1198 vp_def->vg_name = NULL;
1199 vp_def->extent_size = DEFAULT_EXTENT_SIZE * 2;
1200 vp_def->max_pv = DEFAULT_MAX_PV;
1201 vp_def->max_lv = DEFAULT_MAX_LV;
1202 vp_def->alloc = DEFAULT_ALLOC_POLICY;
1203 vp_def->clustered = DEFAULT_CLUSTERED;
1204 }
1205 }
1206
1207 /*
1208 * Set members of struct vgcreate_params from cmdline arguments.
1209 * Do preliminary validation with arg_*() interface.
1210 * Further, more generic validation is done in validate_vgcreate_params().
1211 * This function is to remain in tools directory.
1212 */
vgcreate_params_set_from_args(struct cmd_context * cmd,struct vgcreate_params * vp_new,struct vgcreate_params * vp_def)1213 int vgcreate_params_set_from_args(struct cmd_context *cmd,
1214 struct vgcreate_params *vp_new,
1215 struct vgcreate_params *vp_def)
1216 {
1217 vp_new->vg_name = skip_dev_dir(cmd, vp_def->vg_name, NULL);
1218 vp_new->max_lv = arg_uint_value(cmd, maxlogicalvolumes_ARG,
1219 vp_def->max_lv);
1220 vp_new->max_pv = arg_uint_value(cmd, maxphysicalvolumes_ARG,
1221 vp_def->max_pv);
1222 vp_new->alloc = arg_uint_value(cmd, alloc_ARG, vp_def->alloc);
1223
1224 /* Units of 512-byte sectors */
1225 vp_new->extent_size =
1226 arg_uint_value(cmd, physicalextentsize_ARG, vp_def->extent_size);
1227
1228 if (arg_count(cmd, clustered_ARG))
1229 vp_new->clustered =
1230 !strcmp(arg_str_value(cmd, clustered_ARG,
1231 vp_def->clustered ? "y":"n"), "y");
1232 else
1233 /* Default depends on current locking type */
1234 vp_new->clustered = locking_is_clustered();
1235
1236 if (arg_sign_value(cmd, physicalextentsize_ARG, 0) == SIGN_MINUS) {
1237 log_error("Physical extent size may not be negative");
1238 return 1;
1239 }
1240
1241 if (arg_sign_value(cmd, maxlogicalvolumes_ARG, 0) == SIGN_MINUS) {
1242 log_error("Max Logical Volumes may not be negative");
1243 return 1;
1244 }
1245
1246 if (arg_sign_value(cmd, maxphysicalvolumes_ARG, 0) == SIGN_MINUS) {
1247 log_error("Max Physical Volumes may not be negative");
1248 return 1;
1249 }
1250
1251 return 0;
1252 }
1253
lv_refresh(struct cmd_context * cmd,struct logical_volume * lv)1254 int lv_refresh(struct cmd_context *cmd, struct logical_volume *lv)
1255 {
1256 return suspend_lv(cmd, lv) && resume_lv(cmd, lv);
1257 }
1258
vg_refresh_visible(struct cmd_context * cmd,struct volume_group * vg)1259 int vg_refresh_visible(struct cmd_context *cmd, struct volume_group *vg)
1260 {
1261 struct lv_list *lvl;
1262 int r = 1;
1263
1264 dm_list_iterate_items(lvl, &vg->lvs)
1265 if (lv_is_visible(lvl->lv))
1266 if (!lv_refresh(cmd, lvl->lv))
1267 r = 0;
1268
1269 return r;
1270 }
1271
lv_spawn_background_polling(struct cmd_context * cmd,struct logical_volume * lv)1272 void lv_spawn_background_polling(struct cmd_context *cmd,
1273 struct logical_volume *lv)
1274 {
1275 const char *pvname;
1276
1277 if ((lv->status & PVMOVE) &&
1278 (pvname = get_pvmove_pvname_from_lv_mirr(lv))) {
1279 log_verbose("Spawning background pvmove process for %s",
1280 pvname);
1281 pvmove_poll(cmd, pvname, 1);
1282 } else if ((lv->status & LOCKED) &&
1283 (pvname = get_pvmove_pvname_from_lv(lv))) {
1284 log_verbose("Spawning background pvmove process for %s",
1285 pvname);
1286 pvmove_poll(cmd, pvname, 1);
1287 }
1288
1289 if (lv->status & CONVERTING) {
1290 log_verbose("Spawning background lvconvert process for %s",
1291 lv->name);
1292 lvconvert_poll(cmd, lv, 1);
1293 }
1294 }
1295
1296 /*
1297 * Intial sanity checking of non-recovery related command-line arguments.
1298 *
1299 * Output arguments:
1300 * pp: structure allocated by caller, fields written / validated here
1301 */
pvcreate_params_validate(struct cmd_context * cmd,int argc,char ** argv,struct pvcreate_params * pp)1302 int pvcreate_params_validate(struct cmd_context *cmd,
1303 int argc, char **argv,
1304 struct pvcreate_params *pp)
1305 {
1306 if (!argc) {
1307 log_error("Please enter a physical volume path");
1308 return 0;
1309 }
1310
1311 if (arg_count(cmd, yes_ARG) && !arg_count(cmd, force_ARG)) {
1312 log_error("Option y can only be given with option f");
1313 return 0;
1314 }
1315
1316 pp->yes = arg_count(cmd, yes_ARG);
1317 pp->force = arg_count(cmd, force_ARG);
1318
1319 if (arg_int_value(cmd, labelsector_ARG, 0) >= LABEL_SCAN_SECTORS) {
1320 log_error("labelsector must be less than %lu",
1321 LABEL_SCAN_SECTORS);
1322 return 0;
1323 } else {
1324 pp->labelsector = arg_int64_value(cmd, labelsector_ARG,
1325 DEFAULT_LABELSECTOR);
1326 }
1327
1328 if (!(cmd->fmt->features & FMT_MDAS) &&
1329 (arg_count(cmd, pvmetadatacopies_ARG) ||
1330 arg_count(cmd, metadatasize_ARG) ||
1331 arg_count(cmd, dataalignment_ARG) ||
1332 arg_count(cmd, dataalignmentoffset_ARG))) {
1333 log_error("Metadata and data alignment parameters only "
1334 "apply to text format.");
1335 return 0;
1336 }
1337
1338 if (arg_count(cmd, pvmetadatacopies_ARG) &&
1339 arg_int_value(cmd, pvmetadatacopies_ARG, -1) > 2) {
1340 log_error("Metadatacopies may only be 0, 1 or 2");
1341 return 0;
1342 }
1343
1344 if (arg_count(cmd, zero_ARG))
1345 pp->zero = strcmp(arg_str_value(cmd, zero_ARG, "y"), "n");
1346
1347 if (arg_sign_value(cmd, dataalignment_ARG, 0) == SIGN_MINUS) {
1348 log_error("Physical volume data alignment may not be negative");
1349 return 0;
1350 }
1351 pp->data_alignment = arg_uint64_value(cmd, dataalignment_ARG, UINT64_C(0));
1352
1353 if (pp->data_alignment > ULONG_MAX) {
1354 log_error("Physical volume data alignment is too big.");
1355 return 0;
1356 }
1357
1358 if (pp->data_alignment && pp->pe_start) {
1359 if (pp->pe_start % pp->data_alignment)
1360 log_warn("WARNING: Ignoring data alignment %" PRIu64
1361 " incompatible with --restorefile value (%"
1362 PRIu64").", pp->data_alignment, pp->pe_start);
1363 pp->data_alignment = 0;
1364 }
1365
1366 if (arg_sign_value(cmd, dataalignmentoffset_ARG, 0) == SIGN_MINUS) {
1367 log_error("Physical volume data alignment offset may not be negative");
1368 return 0;
1369 }
1370 pp->data_alignment_offset = arg_uint64_value(cmd, dataalignmentoffset_ARG, UINT64_C(0));
1371
1372 if (pp->data_alignment_offset > ULONG_MAX) {
1373 log_error("Physical volume data alignment offset is too big.");
1374 return 0;
1375 }
1376
1377 if (pp->data_alignment_offset && pp->pe_start) {
1378 log_warn("WARNING: Ignoring data alignment offset %" PRIu64
1379 " incompatible with --restorefile value (%"
1380 PRIu64").", pp->data_alignment_offset, pp->pe_start);
1381 pp->data_alignment_offset = 0;
1382 }
1383
1384 if (arg_sign_value(cmd, metadatasize_ARG, 0) == SIGN_MINUS) {
1385 log_error("Metadata size may not be negative");
1386 return 0;
1387 }
1388
1389 pp->pvmetadatasize = arg_uint64_value(cmd, metadatasize_ARG, UINT64_C(0));
1390 if (!pp->pvmetadatasize)
1391 pp->pvmetadatasize = find_config_tree_int(cmd,
1392 "metadata/pvmetadatasize",
1393 DEFAULT_PVMETADATASIZE);
1394
1395 pp->pvmetadatacopies = arg_int_value(cmd, pvmetadatacopies_ARG, -1);
1396 if (pp->pvmetadatacopies < 0)
1397 pp->pvmetadatacopies = find_config_tree_int(cmd,
1398 "metadata/pvmetadatacopies",
1399 DEFAULT_PVMETADATACOPIES);
1400
1401 return 1;
1402 }
1403
1404