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

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

hr: move state printing to hrctl

One IPC call is for short volume states printing
and other one for specific volume detailed info
printing.

  • Property mode set to 100644
File size: 20.0 KB
RevLine 
[94d84a0]1/*
[8b51009]2 * Copyright (c) 2025 Miroslav Cimerman
[94d84a0]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
[e0bbecb]36#include <capa.h>
[964e897]37#include <ctype.h>
[94d84a0]38#include <errno.h>
39#include <getopt.h>
40#include <hr.h>
[e192339]41#include <sif.h>
[94d84a0]42#include <stdlib.h>
43#include <stdio.h>
44#include <str.h>
45#include <str_error.h>
46
[d1d355f]47/* #define HRCTL_SAMPLE_CONFIG_PATH "/cfg/sample_hr_config.sif" */
48
49#define NAME "hrctl"
[e192339]50
[6f13257]51static void usage(void);
52static errno_t fill_config_devs(int, char **, hr_config_t *);
[e5ea5f8]53static errno_t get_vol_configs_from_sif(const char *, hr_config_t **, size_t *);
[e0bbecb]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 **);
[94d84a0]64
65static const char usage_str[] =
[d482b05]66 NAME ": HelenOS RAID configuration and management utility.\n"
67 "Usage: " NAME " [OPTION]...\n"
[94d84a0]68 "\n"
69 "Options:\n"
[d1d355f]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"
[217d0fb]86 " -f, --fail index fail an extent (DANGEROUS), or\n"
[d1d355f]87 " -h, --hotspare device add hotspare.\n"
[94d84a0]88 "\n"
[e0bbecb]89 " -s, --state [volume] Display state of active volume(s).\n"
[972b011]90 "\n"
[431b513]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"
[94d84a0]97 "Example usage:\n"
[d1d355f]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"
[217d0fb]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"
[e5ea5f8]114 " Nested levels have to be created manually, or from config file, but need to\n"
115 " be specified as separate volumes.\n"
[d1d355f]116 "\n"
[ee83e9c]117 "Limitations:\n"
[e5ea5f8]118 "\t- volume name must be shorter than 32 characters\n"
119 "\t- automatic assembly and disassembly on nested volumes is UNDEFINED!\n";
[94d84a0]120
[e0bbecb]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
[94d84a0]183static void usage(void)
184{
185 printf("%s", usage_str);
186}
187
[d1d355f]188static errno_t fill_config_devs(int argc, char **argv, hr_config_t *cfg)
[94d84a0]189{
190 errno_t rc;
[68e357e]191 size_t i;
[94d84a0]192
[fde80323]193 for (i = 0; i < HR_MAX_EXTENTS && optind < argc; i++) {
[ee83e9c]194 rc = loc_service_get_id(argv[optind], &cfg->devs[i], 0);
[e47a032]195 if (rc == ENOENT) {
[d1d355f]196 printf(NAME ": device \"%s\" not found, aborting\n",
[e47a032]197 argv[optind]);
[d1d355f]198 return ENOENT;
[e47a032]199 } else if (rc != EOK) {
[d1d355f]200 printf(NAME ": error resolving device \"%s\", aborting\n",
[e47a032]201 argv[optind]);
[94d84a0]202 return EINVAL;
203 }
[fde80323]204 optind++;
[d1d355f]205 }
206
207 if (optind < argc) {
208 printf(NAME ": too many devices specified, max = %u\n",
209 HR_MAX_EXTENTS);
210 return ELIMIT;
[94d84a0]211 }
212
[d1d355f]213 cfg->dev_no = i;
214
[94d84a0]215 return EOK;
216}
217
[e5ea5f8]218static errno_t get_vol_configs_from_sif(const char *path, hr_config_t **rcfgs,
219 size_t *rcount)
[e192339]220{
221 errno_t rc;
222 sif_doc_t *doc = NULL;
[e5ea5f8]223 sif_node_t *hrconfig_node;
224 sif_node_t *root_node;
225 sif_node_t *volume_node;
[e192339]226 sif_node_t *nextent;
227 const char *ntype;
228 const char *devname;
229 const char *level_str;
230 const char *extent_devname;
[e5ea5f8]231 hr_config_t *vol_configs = NULL;
[e192339]232
233 rc = sif_load(path, &doc);
234 if (rc != EOK)
235 goto error;
236
[e5ea5f8]237 root_node = sif_get_root(doc);
[e192339]238
[e5ea5f8]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;
[e192339]243 goto error;
244 }
245
[e5ea5f8]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) {
[e192339]251 rc = EINVAL;
252 goto error;
253 }
[e5ea5f8]254 vol_configs = realloc(vol_configs,
255 (vol_count + 1) * sizeof(hr_config_t));
[52e40513]256 if (vol_configs == NULL) {
257 rc = ENOMEM;
258 goto error;
259 }
260
[e5ea5f8]261 hr_config_t *cfg = vol_configs + vol_count;
[e192339]262
[e5ea5f8]263 devname = sif_node_get_attr(volume_node, "devname");
264 if (devname == NULL) {
265 rc = EINVAL;
[e192339]266 goto error;
267 }
[e5ea5f8]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++;
[e192339]305 }
306
[e5ea5f8]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++;
[e192339]314 }
315
[e5ea5f8]316 volume_node = sif_node_next_child(volume_node);
[e192339]317 }
318
[e5ea5f8]319 if (rc == EOK) {
320 if (rcount)
321 *rcount = vol_count;
322 if (rcfgs)
323 *rcfgs = vol_configs;
324 }
[e192339]325error:
326 if (doc != NULL)
327 sif_delete(doc);
[e5ea5f8]328 if (rc != EOK) {
329 if (vol_configs)
330 free(vol_configs);
331 }
[e192339]332 return rc;
333}
334
[e5ea5f8]335static int create_from_config(hr_t *hr, const char *config_path)
[94d84a0]336{
[e5ea5f8]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");
[d1d355f]367 return EXIT_FAILURE;
368 }
[68e357e]369
[d1d355f]370 hr_config_t *vol_config = calloc(1, sizeof(hr_config_t));
371 if (vol_config == NULL) {
[e5ea5f8]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++];
[431b513]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 }
[e5ea5f8]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;
[d1d355f]439 }
[94d84a0]440
[d1d355f]441 if (str_cmp(argv[optind], "-f") == 0) {
[e5ea5f8]442 optind++;
443 if (optind >= argc) {
[d1d355f]444 printf(NAME ": not enough arguments\n");
[e5ea5f8]445 return EXIT_FAILURE;
[d1d355f]446 }
[e5ea5f8]447
[d1d355f]448 const char *config_path = argv[optind++];
[e5ea5f8]449
450 if (optind < argc) {
451 printf(NAME ": unexpected arguments\n");
452 return EXIT_FAILURE;
[d1d355f]453 }
[e5ea5f8]454
455 rc = create_from_config(hr, config_path);
[d1d355f]456 } else {
[e5ea5f8]457 rc = create_from_argv(hr, argc, argv);
458 }
[94d84a0]459
[e5ea5f8]460 return rc;
461}
[94d84a0]462
[e5ea5f8]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 }
[94d84a0]473
[e5ea5f8]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 }
[94d84a0]480
[e5ea5f8]481 printf(NAME ": assembled %zu volumes\n", cnt);
[964e897]482
[e5ea5f8]483 free(vol_configs);
484 return EXIT_SUCCESS;
485}
[b0f1366]486
[e5ea5f8]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;
[b0f1366]493 }
494
[e5ea5f8]495 errno_t rc = fill_config_devs(argc, argv, vol_config);
496 if (rc != EOK)
[d1d355f]497 goto error;
[b0f1366]498
[e5ea5f8]499 size_t cnt;
500 rc = hr_assemble(hr, vol_config, &cnt);
[94d84a0]501 if (rc != EOK) {
[e5ea5f8]502 printf(NAME ": assmeble failed: %s\n", str_error(rc));
[d1d355f]503 goto error;
[94d84a0]504 }
505
[e5ea5f8]506 printf("hrctl: assembled %zu volumes\n", cnt);
507
[d1d355f]508 free(vol_config);
509 return EXIT_SUCCESS;
510error:
511 free(vol_config);
512 return EXIT_FAILURE;
513}
514
[fc265b4]515static int handle_assemble(hr_t *hr, int argc, char **argv)
[d1d355f]516{
[e5ea5f8]517 int rc;
518
[d1d355f]519 if (optind >= argc) {
520 size_t cnt;
[fc265b4]521 errno_t rc = hr_auto_assemble(hr, &cnt);
[d082801]522 if (rc != EOK) {
523 /* XXX: here have own error codes */
524 printf("hrctl: auto assemble rc: %s\n", str_error(rc));
[d1d355f]525 return EXIT_FAILURE;
[d082801]526 }
527
[d1d355f]528 printf(NAME ": auto assembled %zu volumes\n", cnt);
529 return EXIT_SUCCESS;
[94d84a0]530 }
531
[d1d355f]532 if (str_cmp(argv[optind], "-f") == 0) {
533 if (++optind >= argc) {
534 printf(NAME ": not enough arguments\n");
[e5ea5f8]535 return EXIT_FAILURE;
[d1d355f]536 }
537 const char *config_path = argv[optind++];
[e5ea5f8]538
[d1d355f]539 if (optind < argc) {
540 printf(NAME ": unexpected arguments\n");
[e5ea5f8]541 return EXIT_FAILURE;
[d1d355f]542 }
543
[e5ea5f8]544 rc = assemble_from_config(hr, config_path);
545 } else {
546 rc = assemble_from_argv(hr, argc, argv);
[d1d355f]547 }
548
[e5ea5f8]549 return rc;
[d1d355f]550}
551
[fc265b4]552static int handle_disassemble(hr_t *hr, int argc, char **argv)
[d1d355f]553{
554 if (optind >= argc) {
[fc265b4]555 errno_t rc = hr_stop_all(hr);
[d1d355f]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
[fc265b4]571 errno_t rc = hr_stop(hr, devname);
[d1d355f]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
[fc265b4]581static int handle_modify(hr_t *hr, int argc, char **argv)
[d1d355f]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);
[fc265b4]605 errno_t rc = hr_fail_extent(hr, volname, extent);
[d1d355f]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++;
[fc265b4]614 errno_t rc = hr_add_hotspare(hr, volname, argv[optind++]);
[d1d355f]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
[e0bbecb]628static errno_t print_vol_info(hr_vol_info_t *info)
[d1d355f]629{
[e0bbecb]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);
[d1d355f]658
[e0bbecb]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);
[d1d355f]664 if (rc != EOK) {
[e0bbecb]665 printf(NAME ": failed to format capacity: %s\n", str_error(rc));
666 return rc;
[d1d355f]667 }
668
[e0bbecb]669 printf("| volume capacity: %s\n", scapa);
[d1d355f]670
[e0bbecb]671 free(scapa);
[d1d355f]672
[e0bbecb]673 printf("| state: %s\n", hr_get_vol_state_str(info->state));
674 printf("| extents:\n");
675
676 for (i = 0; i < info->extent_no; i++) {
677 ext = &info->extents[i];
678 char *tmpname = NULL;
679 if (ext->state == HR_EXT_MISSING || ext->state == HR_EXT_NONE) {
680 devname = "MISSING";
681 } else {
682 rc = loc_service_get_name(ext->svc_id, &tmpname);
683 if (rc != EOK)
684 devname = "MISSING";
685 else
686 devname = tmpname;
687 }
688 printf("| %zu %s\n", i, hr_get_ext_state_str(ext->state));
689 printf("| %s\n", devname);
690 if (tmpname != NULL)
691 free(tmpname);
[d1d355f]692 }
693
[e0bbecb]694 if (info->hotspare_no == 0)
695 return EOK;
696
697 printf("| hotspares:\n");
698 for (i = 0; i < info->hotspare_no; i++) {
699 ext = &info->hotspares[i];
700 char *tmpname;
701 if (ext->state == HR_EXT_MISSING || ext->state == HR_EXT_NONE) {
702 devname = "MISSING";
703 } else {
704 rc = loc_service_get_name(ext->svc_id, &tmpname);
705 if (rc != EOK)
706 devname = "MISSING";
707 else
708 devname = tmpname;
709 }
710 printf("| %zu %s\n", i, hr_get_ext_state_str(ext->state));
711 printf("| %s\n", devname);
712 if (tmpname != NULL)
713 free(tmpname);
[fc265b4]714 }
715
[e0bbecb]716 return EOK;
717}
[d1d355f]718
[e0bbecb]719static int handle_state(hr_t *hr, int argc, char **argv)
720{
721 errno_t rc;
722 size_t cnt;
723 hr_pair_vol_state_t *pairs = NULL;
724 char *devname;
[d1d355f]725
[e0bbecb]726 /* print state of all volumes */
727 if (optind >= argc) {
728 rc = hr_get_vol_states(hr, &pairs, &cnt);
729 if (rc != EOK) {
730 printf(NAME ": failed getting state of volumes: %s\n",
731 str_error(rc));
732 return EXIT_FAILURE;
733 }
734
735 if (cnt == 0) {
736 printf(NAME ": no active volumes\n");
737 return EXIT_SUCCESS;
738 }
739
740 for (size_t i = 0; i < cnt; i++) {
741 service_id_t svc_id = pairs[i].svc_id;
742 hr_vol_state_t state = pairs[i].state;
743 rc = loc_service_get_name(svc_id, &devname);
744 if (rc != EOK) {
745 printf(NAME ": getting service name failed: "
746 "%s\n", str_error(rc));
747 return EXIT_FAILURE;
748 }
749 printf("volume \"%s\" (%" PRIun ") %s\n", devname,
750 svc_id, hr_get_vol_state_str(state));
751
752 free(devname);
753 }
754 free(pairs);
755
756 return EXIT_SUCCESS;
[d1d355f]757 }
758
[e0bbecb]759 /* print volume info of requested volumes */
760 while (optind < argc) {
761 service_id_t svc_id;
762 devname = argv[optind++];
763 rc = loc_service_get_id(devname, &svc_id, 0);
764 if (rc != EOK) {
765 printf(NAME ": getting service id of \"%s\" failed: "
766 "%s\n", devname, str_error(rc));
767 return EXIT_FAILURE;
768 }
[fc265b4]769
[e0bbecb]770 hr_vol_info_t info;
771 rc = hr_get_vol_info(hr, svc_id, &info);
772 if (rc != EOK) {
773 printf(NAME ": getting volume info failed: %s\n",
774 str_error(rc));
775 return EXIT_FAILURE;
776 }
777
778 rc = print_vol_info(&info);
779 if (rc != EOK) {
780 printf(NAME ": volume info printing failed: %s\n",
781 str_error(rc));
782 return EXIT_FAILURE;
783 }
784 }
785
786 return EXIT_SUCCESS;
[94d84a0]787}
788
789/** @}
790 */
Note: See TracBrowser for help on using the repository browser.