source: mainline/uspace/app/hrctl/hrctl.c@ f34568c

Last change on this file since f34568c was f34568c, checked in by Miroslav Cimerman <mc@…>, 3 weeks ago

hr: print % done of REBUILD operation

  • Property mode set to 100644
File size: 20.2 KB
Line 
1/*
2 * Copyright (c) 2025 Miroslav Cimerman
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup hrctl
30 * @{
31 */
32/**
33 * @file
34 */
35
36#include <capa.h>
37#include <ctype.h>
38#include <errno.h>
39#include <getopt.h>
40#include <hr.h>
41#include <sif.h>
42#include <stdlib.h>
43#include <stdio.h>
44#include <str.h>
45#include <str_error.h>
46
47/* #define HRCTL_SAMPLE_CONFIG_PATH "/cfg/sample_hr_config.sif" */
48
49#define NAME "hrctl"
50
51static void usage(void);
52static errno_t fill_config_devs(int, char **, hr_config_t *);
53static errno_t get_vol_configs_from_sif(const char *, hr_config_t **, size_t *);
54static int create_from_config(hr_t *, const char *);
55static int create_from_argv(hr_t *, int, char **);
56static int handle_create(hr_t *, int, char **);
57static int assemble_from_config(hr_t *, const char *);
58static int assemble_from_argv(hr_t *, int, char **);
59static int handle_assemble(hr_t *, int, char **);
60static int handle_disassemble(hr_t *, int, char **);
61static int handle_modify(hr_t *, int, char **);
62static errno_t print_vol_info(hr_vol_info_t *);
63static int handle_state(hr_t *, int, char **);
64
65static const char usage_str[] =
66 NAME ": HelenOS RAID configuration and management utility.\n"
67 "Usage: " NAME " [OPTION]...\n"
68 "\n"
69 "Options:\n"
70 " -h, --help Display this message and exit.\n"
71 "\n"
72 " -c, --create Create a volume, options:\n"
73 " name {-l , --level level} device... manual device specification, or\n"
74 " -f configuration.sif create from configuration file.\n"
75 "\n"
76 " -a, --assemble Assemble volume(s), options:\n"
77 " [device...] manual device specification, or\n"
78 " [-f configuration.sif] assemble from configuration file, or\n"
79 " no option is automatic assembly.\n"
80 "\n"
81 " -d, --disassemble Deactivate/disassemble, options:\n"
82 " [volume] specific volume, or\n"
83 " all volumes with no specified option.\n"
84 "\n"
85 " -m, --modify volume Modify a volume, options:\n"
86 " -f, --fail index fail an extent (DANGEROUS), or\n"
87 " -h, --hotspare device add hotspare.\n"
88 "\n"
89 " -s, --state [volume] Display state of active volume(s).\n"
90 "\n"
91 "level can be one of:\n"
92 " 0 | stripe | striping |\n"
93 " 1 | mirror | mirroring |\n"
94 " 4 | parity_dedicated |\n"
95 " 5 | parity | parity_distributed\n"
96 "\n"
97 "Example usage:\n"
98 "\t\thrctl --create hr0 --level 5 disk1 disk2 disk3\n"
99 "\t\thrctl -c hr0 -l 5 disk1 disk2 disk3\n"
100 "\t\thrctl -c -f cfg.sif\n"
101 "\t\thrctl --assemble disk1 disk2 disk3\n"
102 "\t\thrctl -a\n"
103 "\t\thrctl -d devices/hr0\n"
104 "\t\thrctl -d\n"
105 "\t\thrctl --modify devices/hr0 --fail 0\n"
106 "\t\thrctl --modify devices/hr0 --hotspare disk4\n"
107 "\t\thrctl -s\n"
108 "\n"
109 "Notes:\n"
110 " Volume service names are automatically prepended with \"devices/\" prefix.\n"
111 " Simulating an extent failure with -m volume -f index is dangerous. It marks\n"
112 " metadata as dirty in other healthy extents, and therefore invalidates\n"
113 " the specified extent.\n"
114 " Nested levels have to be created manually, or from config file, but need to\n"
115 " be specified as separate volumes.\n"
116 "\n"
117 "Limitations:\n"
118 "\t- volume name must be shorter than 32 characters\n"
119 "\t- automatic assembly and disassembly on nested volumes is UNDEFINED!\n";
120
121int main(int argc, char **argv)
122{
123 int rc = EXIT_SUCCESS;
124 hr_t *hr = NULL;
125
126 if (argc < 2) {
127 rc = EXIT_FAILURE;
128 goto end;
129 }
130
131 rc = hr_sess_init(&hr);
132 if (rc != EOK) {
133 printf(NAME ": hr server session init failed: %s\n",
134 str_error(rc));
135 return EXIT_FAILURE;
136 }
137
138 optreset = 1;
139 optind = 0;
140
141 struct option const top_level_opts[] = {
142 { "help", no_argument, 0, 'h' },
143 { "create", no_argument, 0, 'c' },
144 { "assemble", no_argument, 0, 'a' },
145 { "disassemble", no_argument, 0, 'd' },
146 { "modify", no_argument, 0, 'm' },
147 { "state", no_argument, 0, 's' },
148 { 0, 0, 0, 0 }
149 };
150
151 int c = getopt_long(argc, argv, "hcadms", top_level_opts, NULL);
152 switch (c) {
153 case 'h':
154 usage();
155 goto end;
156 case 'c':
157 rc = handle_create(hr, argc, argv);
158 goto end;
159 case 'a':
160 rc = handle_assemble(hr, argc, argv);
161 goto end;
162 case 'd':
163 rc = handle_disassemble(hr, argc, argv);
164 goto end;
165 case 'm':
166 rc = handle_modify(hr, argc, argv);
167 goto end;
168 case 's':
169 rc = handle_state(hr, argc, argv);
170 goto end;
171 default:
172 goto end;
173 }
174
175end:
176 hr_sess_destroy(hr);
177
178 if (rc != EXIT_SUCCESS)
179 printf(NAME ": use --help to see usage\n");
180 return rc;
181}
182
183static void usage(void)
184{
185 printf("%s", usage_str);
186}
187
188static errno_t fill_config_devs(int argc, char **argv, hr_config_t *cfg)
189{
190 errno_t rc;
191 size_t i;
192
193 for (i = 0; i < HR_MAX_EXTENTS && optind < argc; i++) {
194 rc = loc_service_get_id(argv[optind], &cfg->devs[i], 0);
195 if (rc == ENOENT) {
196 printf(NAME ": device \"%s\" not found, aborting\n",
197 argv[optind]);
198 return ENOENT;
199 } else if (rc != EOK) {
200 printf(NAME ": error resolving device \"%s\", aborting\n",
201 argv[optind]);
202 return EINVAL;
203 }
204 optind++;
205 }
206
207 if (optind < argc) {
208 printf(NAME ": too many devices specified, max = %u\n",
209 HR_MAX_EXTENTS);
210 return ELIMIT;
211 }
212
213 cfg->dev_no = i;
214
215 return EOK;
216}
217
218static errno_t get_vol_configs_from_sif(const char *path, hr_config_t **rcfgs,
219 size_t *rcount)
220{
221 errno_t rc;
222 sif_doc_t *doc = NULL;
223 sif_node_t *hrconfig_node;
224 sif_node_t *root_node;
225 sif_node_t *volume_node;
226 sif_node_t *nextent;
227 const char *ntype;
228 const char *devname;
229 const char *level_str;
230 const char *extent_devname;
231 hr_config_t *vol_configs = NULL;
232
233 rc = sif_load(path, &doc);
234 if (rc != EOK)
235 goto error;
236
237 root_node = sif_get_root(doc);
238
239 hrconfig_node = sif_node_first_child(root_node);
240 ntype = sif_node_get_type(hrconfig_node);
241 if (str_cmp(ntype, "hrconfig") != 0) {
242 rc = EINVAL;
243 goto error;
244 }
245
246 size_t vol_count = 0;
247 volume_node = sif_node_first_child(hrconfig_node);
248 while (volume_node) {
249 ntype = sif_node_get_type(volume_node);
250 if (str_cmp(ntype, "volume") != 0) {
251 rc = EINVAL;
252 goto error;
253 }
254 vol_configs = realloc(vol_configs,
255 (vol_count + 1) * sizeof(hr_config_t));
256 if (vol_configs == NULL) {
257 rc = ENOMEM;
258 goto error;
259 }
260
261 hr_config_t *cfg = vol_configs + vol_count;
262
263 devname = sif_node_get_attr(volume_node, "devname");
264 if (devname == NULL) {
265 rc = EINVAL;
266 goto error;
267 }
268 str_cpy(cfg->devname, sizeof(cfg->devname), devname);
269
270 level_str = sif_node_get_attr(volume_node, "level");
271 if (level_str == NULL)
272 cfg->level = HR_LVL_UNKNOWN;
273 else
274 cfg->level = strtol(level_str, NULL, 10);
275
276 nextent = sif_node_first_child(volume_node);
277 size_t i = 0;
278 while (nextent && i < HR_MAX_EXTENTS) {
279 ntype = sif_node_get_type(nextent);
280 if (str_cmp(ntype, "extent") != 0) {
281 rc = EINVAL;
282 goto error;
283 }
284
285 extent_devname = sif_node_get_attr(nextent, "devname");
286 if (extent_devname == NULL) {
287 rc = EINVAL;
288 goto error;
289 }
290
291 rc = loc_service_get_id(extent_devname, &cfg->devs[i], 0);
292 if (rc == ENOENT) {
293 printf(NAME ": no device \"%s\", marking as missing\n",
294 extent_devname);
295 cfg->devs[i] = 0;
296 rc = EOK;
297 } else if (rc != EOK) {
298 printf(NAME ": error resolving device \"%s\", aborting\n",
299 extent_devname);
300 goto error;
301 }
302
303 nextent = sif_node_next_child(nextent);
304 i++;
305 }
306
307 if (i > HR_MAX_EXTENTS) {
308 printf(NAME ": too many devices specified in volume \"%s\", "
309 "skipping\n", devname);
310 memset(&vol_configs[vol_count], 0, sizeof(hr_config_t));
311 } else {
312 cfg->dev_no = i;
313 vol_count++;
314 }
315
316 volume_node = sif_node_next_child(volume_node);
317 }
318
319 if (rc == EOK) {
320 if (rcount)
321 *rcount = vol_count;
322 if (rcfgs)
323 *rcfgs = vol_configs;
324 }
325error:
326 if (doc != NULL)
327 sif_delete(doc);
328 if (rc != EOK) {
329 if (vol_configs)
330 free(vol_configs);
331 }
332 return rc;
333}
334
335static int create_from_config(hr_t *hr, const char *config_path)
336{
337 hr_config_t *vol_configs = NULL;
338 size_t vol_count = 0;
339 errno_t rc = get_vol_configs_from_sif(config_path, &vol_configs,
340 &vol_count);
341 if (rc != EOK) {
342 printf(NAME ": config parsing failed\n");
343 return EXIT_FAILURE;
344 }
345
346 for (size_t i = 0; i < vol_count; i++) {
347 rc = hr_create(hr, &vol_configs[i]);
348 if (rc != EOK) {
349 printf(NAME ": creation of volume \"%s\" failed: %s, "
350 "but continuing\n",
351 vol_configs[i].devname, str_error(rc));
352 } else {
353 printf(NAME ": volume \"%s\" successfully created\n",
354 vol_configs[i].devname);
355 }
356 }
357
358 free(vol_configs);
359 return EXIT_SUCCESS;
360}
361
362static int create_from_argv(hr_t *hr, int argc, char **argv)
363{
364 /* we need name + --level + arg + at least one extent */
365 if (optind + 3 >= argc) {
366 printf(NAME ": not enough arguments\n");
367 return EXIT_FAILURE;
368 }
369
370 hr_config_t *vol_config = calloc(1, sizeof(hr_config_t));
371 if (vol_config == NULL) {
372 printf(NAME ": not enough memory\n");
373 return EXIT_FAILURE;
374 }
375
376 const char *name = argv[optind++];
377 if (str_size(name) >= HR_DEVNAME_LEN) {
378 printf(NAME ": devname must be less then 32 bytes.\n");
379 goto error;
380 }
381
382 str_cpy(vol_config->devname, HR_DEVNAME_LEN, name);
383
384 const char *level_opt = argv[optind++];
385 if (str_cmp(level_opt, "--level") != 0 &&
386 str_cmp(level_opt, "-l") != 0) {
387 printf(NAME ": unknown option \"%s\"\n", level_opt);
388 goto error;
389 }
390
391 const char *level_str = argv[optind++];
392 if (str_size(level_str) == 1 && isdigit(level_str[0])) {
393 vol_config->level = strtol(level_str, NULL, 10);
394 } else {
395 if (str_cmp(level_str, "mirror") == 0 ||
396 str_cmp(level_str, "mirroring") == 0) {
397 vol_config->level = HR_LVL_1;
398 } else if (str_cmp(level_str, "stripe") == 0 ||
399 str_cmp(level_str, "striping") == 0) {
400 vol_config->level = HR_LVL_0;
401 } else if (str_cmp(level_str, "parity") == 0 ||
402 str_cmp(level_str, "parity_distributed") == 0) {
403 vol_config->level = HR_LVL_5;
404 } else if (str_cmp(level_str, "parity_dedicated") == 0) {
405 vol_config->level = HR_LVL_4;
406 } else {
407 printf(NAME ": unknown level \"%s\"\n", level_str);
408 goto error;
409 }
410 }
411
412 errno_t rc = fill_config_devs(argc, argv, vol_config);
413 if (rc != EOK)
414 goto error;
415
416 rc = hr_create(hr, vol_config);
417 if (rc != EOK) {
418 printf(NAME ": creation failed: %s\n", str_error(rc));
419 goto error;
420 } else {
421 printf(NAME ": volume \"%s\" successfully created\n",
422 vol_config->devname);
423 }
424
425 free(vol_config);
426 return EXIT_SUCCESS;
427error:
428 free(vol_config);
429 return EXIT_FAILURE;
430}
431
432static int handle_create(hr_t *hr, int argc, char **argv)
433{
434 int rc;
435
436 if (optind >= argc) {
437 printf(NAME ": no arguments to --create\n");
438 return EXIT_FAILURE;
439 }
440
441 if (str_cmp(argv[optind], "-f") == 0) {
442 optind++;
443 if (optind >= argc) {
444 printf(NAME ": not enough arguments\n");
445 return EXIT_FAILURE;
446 }
447
448 const char *config_path = argv[optind++];
449
450 if (optind < argc) {
451 printf(NAME ": unexpected arguments\n");
452 return EXIT_FAILURE;
453 }
454
455 rc = create_from_config(hr, config_path);
456 } else {
457 rc = create_from_argv(hr, argc, argv);
458 }
459
460 return rc;
461}
462
463static int assemble_from_config(hr_t *hr, const char *config_path)
464{
465 hr_config_t *vol_configs = NULL;
466 size_t vol_count = 0;
467 errno_t rc = get_vol_configs_from_sif(config_path, &vol_configs,
468 &vol_count);
469 if (rc != EOK) {
470 printf(NAME ": config parsing failed\n");
471 return EXIT_FAILURE;
472 }
473
474 size_t cnt = 0;
475 for (size_t i = 0; i < vol_count; i++) {
476 size_t tmpcnt = 0;
477 (void)hr_assemble(hr, &vol_configs[i], &tmpcnt);
478 cnt += tmpcnt;
479 }
480
481 printf(NAME ": assembled %zu volumes\n", cnt);
482
483 free(vol_configs);
484 return EXIT_SUCCESS;
485}
486
487static int assemble_from_argv(hr_t *hr, int argc, char **argv)
488{
489 hr_config_t *vol_config = calloc(1, sizeof(hr_config_t));
490 if (vol_config == NULL) {
491 printf(NAME ": not enough memory\n");
492 return ENOMEM;
493 }
494
495 errno_t rc = fill_config_devs(argc, argv, vol_config);
496 if (rc != EOK)
497 goto error;
498
499 size_t cnt;
500 rc = hr_assemble(hr, vol_config, &cnt);
501 if (rc != EOK) {
502 printf(NAME ": assmeble failed: %s\n", str_error(rc));
503 goto error;
504 }
505
506 printf("hrctl: assembled %zu volumes\n", cnt);
507
508 free(vol_config);
509 return EXIT_SUCCESS;
510error:
511 free(vol_config);
512 return EXIT_FAILURE;
513}
514
515static int handle_assemble(hr_t *hr, int argc, char **argv)
516{
517 int rc;
518
519 if (optind >= argc) {
520 size_t cnt;
521 errno_t rc = hr_auto_assemble(hr, &cnt);
522 if (rc != EOK) {
523 /* XXX: here have own error codes */
524 printf("hrctl: auto assemble rc: %s\n", str_error(rc));
525 return EXIT_FAILURE;
526 }
527
528 printf(NAME ": auto assembled %zu volumes\n", cnt);
529 return EXIT_SUCCESS;
530 }
531
532 if (str_cmp(argv[optind], "-f") == 0) {
533 if (++optind >= argc) {
534 printf(NAME ": not enough arguments\n");
535 return EXIT_FAILURE;
536 }
537 const char *config_path = argv[optind++];
538
539 if (optind < argc) {
540 printf(NAME ": unexpected arguments\n");
541 return EXIT_FAILURE;
542 }
543
544 rc = assemble_from_config(hr, config_path);
545 } else {
546 rc = assemble_from_argv(hr, argc, argv);
547 }
548
549 return rc;
550}
551
552static int handle_disassemble(hr_t *hr, int argc, char **argv)
553{
554 if (optind >= argc) {
555 errno_t rc = hr_stop_all(hr);
556 if (rc != EOK) {
557 printf(NAME ": stopping some volumes failed: %s\n",
558 str_error(rc));
559 return EXIT_FAILURE;
560 }
561 return EXIT_SUCCESS;
562 }
563
564 if (optind + 1 < argc) {
565 printf(NAME ": only 1 device can be manually specified\n");
566 return EXIT_FAILURE;
567 }
568
569 const char *devname = argv[optind++];
570
571 errno_t rc = hr_stop(hr, devname);
572 if (rc != EOK) {
573 printf(NAME ": disassembly of device \"%s\" failed: %s\n",
574 devname, str_error(rc));
575 return EXIT_FAILURE;
576 }
577
578 return EXIT_SUCCESS;
579}
580
581static int handle_modify(hr_t *hr, int argc, char **argv)
582{
583 if (optind >= argc) {
584 printf(NAME ": no arguments to --modify\n");
585 return EXIT_FAILURE;
586 }
587
588 const char *volname = argv[optind++];
589
590 /* at least 1 option and its agument */
591 if (optind + 1 >= argc) {
592 printf(NAME ": not enough arguments\n");
593 return EXIT_FAILURE;
594 }
595
596 if (optind + 2 < argc) {
597 printf(NAME ": unexpected arguments\n");
598 return EXIT_FAILURE;
599 }
600
601 if (str_cmp(argv[optind], "--fail") == 0 ||
602 str_cmp(argv[optind], "-f") == 0) {
603 optind++;
604 unsigned long extent = strtol(argv[optind++], NULL, 10);
605 errno_t rc = hr_fail_extent(hr, volname, extent);
606 if (rc != EOK) {
607 printf(NAME ": failing extent failed: %s\n",
608 str_error(rc));
609 return EXIT_FAILURE;
610 }
611 } else if (str_cmp(argv[optind], "--hotspare") == 0 ||
612 str_cmp(argv[optind], "-h") == 0) {
613 optind++;
614 errno_t rc = hr_add_hotspare(hr, volname, argv[optind++]);
615 if (rc != EOK) {
616 printf(NAME ": adding hotspare failed: %s\n",
617 str_error(rc));
618 return EXIT_FAILURE;
619 }
620 } else {
621 printf(NAME ": unknown argument\n");
622 return EXIT_FAILURE;
623 }
624
625 return EXIT_SUCCESS;
626}
627
628static errno_t print_vol_info(hr_vol_info_t *info)
629{
630 errno_t rc;
631 size_t i;
632 hr_extent_t *ext;
633 const char *devname;
634
635 printf("volume: \"%s\" (%" PRIun ")\n", info->devname, info->svc_id);
636
637 printf("| metadata type: %s\n",
638 hr_get_metadata_type_str(info->meta_type));
639 printf("| level: %s\n", hr_get_level_str(info->level));
640 if (info->layout != HR_RLQ_NONE)
641 printf("| layout: %s\n",
642 hr_get_layout_str(info->layout));
643
644 if (info->strip_size > 0) {
645 if (info->strip_size < 1024) {
646 printf("| strip size: %" PRIu32 "B\n",
647 info->strip_size);
648 } else {
649 printf("| strip size: %" PRIu32 "KiB\n",
650 info->strip_size / 1024);
651 }
652 }
653
654 printf("| no. of extents: %zu\n", info->extent_no);
655 printf("|no. of hotspares: %zu\n", info->hotspare_no);
656 printf("|number of blocks: %" PRIu64 "\n", info->data_blkno);
657 printf("| block size: %zuB\n", info->bsize);
658
659 capa_spec_t capa;
660 char *scapa = NULL;
661 capa_from_blocks(info->data_blkno, info->bsize, &capa);
662 capa_simplify(&capa);
663 rc = capa_format(&capa, &scapa);
664 if (rc != EOK) {
665 printf(NAME ": failed to format capacity: %s\n", str_error(rc));
666 return rc;
667 }
668
669 printf("| volume capacity: %s\n", scapa);
670
671 free(scapa);
672
673 printf("| state: %s", hr_get_vol_state_str(info->state));
674 if (info->state == HR_VOL_REBUILD) {
675 unsigned int percent =
676 (info->rebuild_blk * 100) / info->data_blkno;
677 printf(" (%u%% done)\n", percent);
678 } else {
679 printf("\n");
680 }
681
682 printf("| extents:\n");
683
684 for (i = 0; i < info->extent_no; i++) {
685 ext = &info->extents[i];
686 char *tmpname = NULL;
687 if (ext->state == HR_EXT_MISSING || ext->state == HR_EXT_NONE) {
688 devname = "MISSING";
689 } else {
690 rc = loc_service_get_name(ext->svc_id, &tmpname);
691 if (rc != EOK)
692 devname = "MISSING";
693 else
694 devname = tmpname;
695 }
696 printf("| %zu %s\n", i, hr_get_ext_state_str(ext->state));
697 printf("| %s\n", devname);
698 if (tmpname != NULL)
699 free(tmpname);
700 }
701
702 if (info->hotspare_no == 0)
703 return EOK;
704
705 printf("| hotspares:\n");
706 for (i = 0; i < info->hotspare_no; i++) {
707 ext = &info->hotspares[i];
708 char *tmpname;
709 if (ext->state == HR_EXT_MISSING || ext->state == HR_EXT_NONE) {
710 devname = "MISSING";
711 } else {
712 rc = loc_service_get_name(ext->svc_id, &tmpname);
713 if (rc != EOK)
714 devname = "MISSING";
715 else
716 devname = tmpname;
717 }
718 printf("| %zu %s\n", i, hr_get_ext_state_str(ext->state));
719 printf("| %s\n", devname);
720 if (tmpname != NULL)
721 free(tmpname);
722 }
723
724 return EOK;
725}
726
727static int handle_state(hr_t *hr, int argc, char **argv)
728{
729 errno_t rc;
730 size_t cnt;
731 hr_pair_vol_state_t *pairs = NULL;
732 char *devname;
733
734 /* print state of all volumes */
735 if (optind >= argc) {
736 rc = hr_get_vol_states(hr, &pairs, &cnt);
737 if (rc != EOK) {
738 printf(NAME ": failed getting state of volumes: %s\n",
739 str_error(rc));
740 return EXIT_FAILURE;
741 }
742
743 if (cnt == 0) {
744 printf(NAME ": no active volumes\n");
745 return EXIT_SUCCESS;
746 }
747
748 for (size_t i = 0; i < cnt; i++) {
749 service_id_t svc_id = pairs[i].svc_id;
750 hr_vol_state_t state = pairs[i].state;
751 rc = loc_service_get_name(svc_id, &devname);
752 if (rc != EOK) {
753 printf(NAME ": getting service name failed: "
754 "%s\n", str_error(rc));
755 return EXIT_FAILURE;
756 }
757 printf("volume \"%s\" (%" PRIun ") %s\n", devname,
758 svc_id, hr_get_vol_state_str(state));
759
760 free(devname);
761 }
762 free(pairs);
763
764 return EXIT_SUCCESS;
765 }
766
767 /* print volume info of requested volumes */
768 while (optind < argc) {
769 service_id_t svc_id;
770 devname = argv[optind++];
771 rc = loc_service_get_id(devname, &svc_id, 0);
772 if (rc != EOK) {
773 printf(NAME ": getting service id of \"%s\" failed: "
774 "%s\n", devname, str_error(rc));
775 return EXIT_FAILURE;
776 }
777
778 hr_vol_info_t info;
779 rc = hr_get_vol_info(hr, svc_id, &info);
780 if (rc != EOK) {
781 printf(NAME ": getting volume info failed: %s\n",
782 str_error(rc));
783 return EXIT_FAILURE;
784 }
785
786 rc = print_vol_info(&info);
787 if (rc != EOK) {
788 printf(NAME ": volume info printing failed: %s\n",
789 str_error(rc));
790 return EXIT_FAILURE;
791 }
792 }
793
794 return EXIT_SUCCESS;
795}
796
797/** @}
798 */
Note: See TracBrowser for help on using the repository browser.