Changeset e0bbecb in mainline for uspace/app/hrctl/hrctl.c
- Timestamp:
- 2025-06-09T20:01:03Z (6 weeks ago)
- Children:
- e2a8fd2
- Parents:
- 431b513
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/app/hrctl/hrctl.c
r431b513 re0bbecb 34 34 */ 35 35 36 #include <capa.h> 36 37 #include <ctype.h> 37 38 #include <errno.h> … … 51 52 static errno_t fill_config_devs(int, char **, hr_config_t *); 52 53 static errno_t get_vol_configs_from_sif(const char *, hr_config_t **, size_t *); 54 static int create_from_config(hr_t *, const char *); 55 static int create_from_argv(hr_t *, int, char **); 56 static int handle_create(hr_t *, int, char **); 57 static int assemble_from_config(hr_t *, const char *); 58 static int assemble_from_argv(hr_t *, int, char **); 59 static int handle_assemble(hr_t *, int, char **); 60 static int handle_disassemble(hr_t *, int, char **); 61 static int handle_modify(hr_t *, int, char **); 62 static errno_t print_vol_info(hr_vol_info_t *); 63 static int handle_state(hr_t *, int, char **); 53 64 54 65 static const char usage_str[] = … … 76 87 " -h, --hotspare device add hotspare.\n" 77 88 "\n" 78 " -s, --state Display state of active volumes.\n"89 " -s, --state [volume] Display state of active volume(s).\n" 79 90 "\n" 80 91 "level can be one of:\n" … … 107 118 "\t- volume name must be shorter than 32 characters\n" 108 119 "\t- automatic assembly and disassembly on nested volumes is UNDEFINED!\n"; 109 110 static void usage(void)111 {112 printf("%s", usage_str);113 }114 115 static errno_t fill_config_devs(int argc, char **argv, hr_config_t *cfg)116 {117 errno_t rc;118 size_t i;119 120 for (i = 0; i < HR_MAX_EXTENTS && optind < argc; i++) {121 rc = loc_service_get_id(argv[optind], &cfg->devs[i], 0);122 if (rc == ENOENT) {123 printf(NAME ": device \"%s\" not found, aborting\n",124 argv[optind]);125 return ENOENT;126 } else if (rc != EOK) {127 printf(NAME ": error resolving device \"%s\", aborting\n",128 argv[optind]);129 return EINVAL;130 }131 optind++;132 }133 134 if (optind < argc) {135 printf(NAME ": too many devices specified, max = %u\n",136 HR_MAX_EXTENTS);137 return ELIMIT;138 }139 140 cfg->dev_no = i;141 142 return EOK;143 }144 145 static errno_t get_vol_configs_from_sif(const char *path, hr_config_t **rcfgs,146 size_t *rcount)147 {148 errno_t rc;149 sif_doc_t *doc = NULL;150 sif_node_t *hrconfig_node;151 sif_node_t *root_node;152 sif_node_t *volume_node;153 sif_node_t *nextent;154 const char *ntype;155 const char *devname;156 const char *level_str;157 const char *extent_devname;158 hr_config_t *vol_configs = NULL;159 160 rc = sif_load(path, &doc);161 if (rc != EOK)162 goto error;163 164 root_node = sif_get_root(doc);165 166 hrconfig_node = sif_node_first_child(root_node);167 ntype = sif_node_get_type(hrconfig_node);168 if (str_cmp(ntype, "hrconfig") != 0) {169 rc = EINVAL;170 goto error;171 }172 173 size_t vol_count = 0;174 volume_node = sif_node_first_child(hrconfig_node);175 while (volume_node) {176 ntype = sif_node_get_type(volume_node);177 if (str_cmp(ntype, "volume") != 0) {178 rc = EINVAL;179 goto error;180 }181 vol_configs = realloc(vol_configs,182 (vol_count + 1) * sizeof(hr_config_t));183 if (vol_configs == NULL) {184 rc = ENOMEM;185 goto error;186 }187 188 hr_config_t *cfg = vol_configs + vol_count;189 190 devname = sif_node_get_attr(volume_node, "devname");191 if (devname == NULL) {192 rc = EINVAL;193 goto error;194 }195 str_cpy(cfg->devname, sizeof(cfg->devname), devname);196 197 level_str = sif_node_get_attr(volume_node, "level");198 if (level_str == NULL)199 cfg->level = HR_LVL_UNKNOWN;200 else201 cfg->level = strtol(level_str, NULL, 10);202 203 nextent = sif_node_first_child(volume_node);204 size_t i = 0;205 while (nextent && i < HR_MAX_EXTENTS) {206 ntype = sif_node_get_type(nextent);207 if (str_cmp(ntype, "extent") != 0) {208 rc = EINVAL;209 goto error;210 }211 212 extent_devname = sif_node_get_attr(nextent, "devname");213 if (extent_devname == NULL) {214 rc = EINVAL;215 goto error;216 }217 218 rc = loc_service_get_id(extent_devname, &cfg->devs[i], 0);219 if (rc == ENOENT) {220 printf(NAME ": no device \"%s\", marking as missing\n",221 extent_devname);222 cfg->devs[i] = 0;223 rc = EOK;224 } else if (rc != EOK) {225 printf(NAME ": error resolving device \"%s\", aborting\n",226 extent_devname);227 goto error;228 }229 230 nextent = sif_node_next_child(nextent);231 i++;232 }233 234 if (i > HR_MAX_EXTENTS) {235 printf(NAME ": too many devices specified in volume \"%s\", "236 "skipping\n", devname);237 memset(&vol_configs[vol_count], 0, sizeof(hr_config_t));238 } else {239 cfg->dev_no = i;240 vol_count++;241 }242 243 volume_node = sif_node_next_child(volume_node);244 }245 246 if (rc == EOK) {247 if (rcount)248 *rcount = vol_count;249 if (rcfgs)250 *rcfgs = vol_configs;251 }252 error:253 if (doc != NULL)254 sif_delete(doc);255 if (rc != EOK) {256 if (vol_configs)257 free(vol_configs);258 }259 return rc;260 }261 262 static int create_from_config(hr_t *hr, const char *config_path)263 {264 hr_config_t *vol_configs = NULL;265 size_t vol_count = 0;266 errno_t rc = get_vol_configs_from_sif(config_path, &vol_configs,267 &vol_count);268 if (rc != EOK) {269 printf(NAME ": config parsing failed\n");270 return EXIT_FAILURE;271 }272 273 for (size_t i = 0; i < vol_count; i++) {274 rc = hr_create(hr, &vol_configs[i]);275 if (rc != EOK) {276 printf(NAME ": creation of volume \"%s\" failed: %s, "277 "but continuing\n",278 vol_configs[i].devname, str_error(rc));279 } else {280 printf(NAME ": volume \"%s\" successfully created\n",281 vol_configs[i].devname);282 }283 }284 285 free(vol_configs);286 return EXIT_SUCCESS;287 }288 289 static int create_from_argv(hr_t *hr, int argc, char **argv)290 {291 /* we need name + --level + arg + at least one extent */292 if (optind + 3 >= argc) {293 printf(NAME ": not enough arguments\n");294 return EXIT_FAILURE;295 }296 297 hr_config_t *vol_config = calloc(1, sizeof(hr_config_t));298 if (vol_config == NULL) {299 printf(NAME ": not enough memory\n");300 return EXIT_FAILURE;301 }302 303 const char *name = argv[optind++];304 if (str_size(name) >= HR_DEVNAME_LEN) {305 printf(NAME ": devname must be less then 32 bytes.\n");306 goto error;307 }308 309 str_cpy(vol_config->devname, HR_DEVNAME_LEN, name);310 311 const char *level_opt = argv[optind++];312 if (str_cmp(level_opt, "--level") != 0 &&313 str_cmp(level_opt, "-l") != 0) {314 printf(NAME ": unknown option \"%s\"\n", level_opt);315 goto error;316 }317 318 const char *level_str = argv[optind++];319 if (str_size(level_str) == 1 && isdigit(level_str[0])) {320 vol_config->level = strtol(level_str, NULL, 10);321 } else {322 if (str_cmp(level_str, "mirror") == 0 ||323 str_cmp(level_str, "mirroring") == 0) {324 vol_config->level = HR_LVL_1;325 } else if (str_cmp(level_str, "stripe") == 0 ||326 str_cmp(level_str, "striping") == 0) {327 vol_config->level = HR_LVL_0;328 } else if (str_cmp(level_str, "parity") == 0 ||329 str_cmp(level_str, "parity_distributed") == 0) {330 vol_config->level = HR_LVL_5;331 } else if (str_cmp(level_str, "parity_dedicated") == 0) {332 vol_config->level = HR_LVL_4;333 } else {334 printf(NAME ": unknown level \"%s\"\n", level_str);335 goto error;336 }337 }338 339 errno_t rc = fill_config_devs(argc, argv, vol_config);340 if (rc != EOK)341 goto error;342 343 rc = hr_create(hr, vol_config);344 if (rc != EOK) {345 printf(NAME ": creation failed: %s\n", str_error(rc));346 goto error;347 } else {348 printf(NAME ": volume \"%s\" successfully created\n",349 vol_config->devname);350 }351 352 free(vol_config);353 return EXIT_SUCCESS;354 error:355 free(vol_config);356 return EXIT_FAILURE;357 }358 359 static int handle_create(hr_t *hr, int argc, char **argv)360 {361 int rc;362 363 if (optind >= argc) {364 printf(NAME ": no arguments to --create\n");365 return EXIT_FAILURE;366 }367 368 if (str_cmp(argv[optind], "-f") == 0) {369 optind++;370 if (optind >= argc) {371 printf(NAME ": not enough arguments\n");372 return EXIT_FAILURE;373 }374 375 const char *config_path = argv[optind++];376 377 if (optind < argc) {378 printf(NAME ": unexpected arguments\n");379 return EXIT_FAILURE;380 }381 382 rc = create_from_config(hr, config_path);383 } else {384 rc = create_from_argv(hr, argc, argv);385 }386 387 return rc;388 }389 390 static int assemble_from_config(hr_t *hr, const char *config_path)391 {392 hr_config_t *vol_configs = NULL;393 size_t vol_count = 0;394 errno_t rc = get_vol_configs_from_sif(config_path, &vol_configs,395 &vol_count);396 if (rc != EOK) {397 printf(NAME ": config parsing failed\n");398 return EXIT_FAILURE;399 }400 401 size_t cnt = 0;402 for (size_t i = 0; i < vol_count; i++) {403 size_t tmpcnt = 0;404 (void)hr_assemble(hr, &vol_configs[i], &tmpcnt);405 cnt += tmpcnt;406 }407 408 printf(NAME ": assembled %zu volumes\n", cnt);409 410 free(vol_configs);411 return EXIT_SUCCESS;412 }413 414 static int assemble_from_argv(hr_t *hr, int argc, char **argv)415 {416 hr_config_t *vol_config = calloc(1, sizeof(hr_config_t));417 if (vol_config == NULL) {418 printf(NAME ": not enough memory\n");419 return ENOMEM;420 }421 422 errno_t rc = fill_config_devs(argc, argv, vol_config);423 if (rc != EOK)424 goto error;425 426 size_t cnt;427 rc = hr_assemble(hr, vol_config, &cnt);428 if (rc != EOK) {429 printf(NAME ": assmeble failed: %s\n", str_error(rc));430 goto error;431 }432 433 printf("hrctl: assembled %zu volumes\n", cnt);434 435 free(vol_config);436 return EXIT_SUCCESS;437 error:438 free(vol_config);439 return EXIT_FAILURE;440 }441 442 static int handle_assemble(hr_t *hr, int argc, char **argv)443 {444 int rc;445 446 if (optind >= argc) {447 size_t cnt;448 errno_t rc = hr_auto_assemble(hr, &cnt);449 if (rc != EOK) {450 /* XXX: here have own error codes */451 printf("hrctl: auto assemble rc: %s\n", str_error(rc));452 return EXIT_FAILURE;453 }454 455 printf(NAME ": auto assembled %zu volumes\n", cnt);456 return EXIT_SUCCESS;457 }458 459 if (str_cmp(argv[optind], "-f") == 0) {460 if (++optind >= argc) {461 printf(NAME ": not enough arguments\n");462 return EXIT_FAILURE;463 }464 const char *config_path = argv[optind++];465 466 if (optind < argc) {467 printf(NAME ": unexpected arguments\n");468 return EXIT_FAILURE;469 }470 471 rc = assemble_from_config(hr, config_path);472 } else {473 rc = assemble_from_argv(hr, argc, argv);474 }475 476 return rc;477 }478 479 static int handle_disassemble(hr_t *hr, int argc, char **argv)480 {481 if (optind >= argc) {482 errno_t rc = hr_stop_all(hr);483 if (rc != EOK) {484 printf(NAME ": stopping some volumes failed: %s\n",485 str_error(rc));486 return EXIT_FAILURE;487 }488 return EXIT_SUCCESS;489 }490 491 if (optind + 1 < argc) {492 printf(NAME ": only 1 device can be manually specified\n");493 return EXIT_FAILURE;494 }495 496 const char *devname = argv[optind++];497 498 errno_t rc = hr_stop(hr, devname);499 if (rc != EOK) {500 printf(NAME ": disassembly of device \"%s\" failed: %s\n",501 devname, str_error(rc));502 return EXIT_FAILURE;503 }504 505 return EXIT_SUCCESS;506 }507 508 static int handle_modify(hr_t *hr, int argc, char **argv)509 {510 if (optind >= argc) {511 printf(NAME ": no arguments to --modify\n");512 return EXIT_FAILURE;513 }514 515 const char *volname = argv[optind++];516 517 /* at least 1 option and its agument */518 if (optind + 1 >= argc) {519 printf(NAME ": not enough arguments\n");520 return EXIT_FAILURE;521 }522 523 if (optind + 2 < argc) {524 printf(NAME ": unexpected arguments\n");525 return EXIT_FAILURE;526 }527 528 if (str_cmp(argv[optind], "--fail") == 0 ||529 str_cmp(argv[optind], "-f") == 0) {530 optind++;531 unsigned long extent = strtol(argv[optind++], NULL, 10);532 errno_t rc = hr_fail_extent(hr, volname, extent);533 if (rc != EOK) {534 printf(NAME ": failing extent failed: %s\n",535 str_error(rc));536 return EXIT_FAILURE;537 }538 } else if (str_cmp(argv[optind], "--hotspare") == 0 ||539 str_cmp(argv[optind], "-h") == 0) {540 optind++;541 errno_t rc = hr_add_hotspare(hr, volname, argv[optind++]);542 if (rc != EOK) {543 printf(NAME ": adding hotspare failed: %s\n",544 str_error(rc));545 return EXIT_FAILURE;546 }547 } else {548 printf(NAME ": unknown argument\n");549 return EXIT_FAILURE;550 }551 552 return EXIT_SUCCESS;553 }554 555 static int handle_state(hr_t *hr, int argc, char **argv)556 {557 (void)argc;558 (void)argv;559 560 errno_t rc = hr_print_state(hr);561 if (rc != EOK) {562 printf(NAME ": state printing failed: %s\n", str_error(rc));563 return EXIT_FAILURE;564 }565 566 return EXIT_SUCCESS;567 }568 120 569 121 int main(int argc, char **argv) … … 629 181 } 630 182 183 static void usage(void) 184 { 185 printf("%s", usage_str); 186 } 187 188 static 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 218 static 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 } 325 error: 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 335 static 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 362 static 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; 427 error: 428 free(vol_config); 429 return EXIT_FAILURE; 430 } 431 432 static 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 463 static 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 487 static 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; 510 error: 511 free(vol_config); 512 return EXIT_FAILURE; 513 } 514 515 static 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 552 static 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 581 static 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 628 static 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\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); 692 } 693 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); 714 } 715 716 return EOK; 717 } 718 719 static 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; 725 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; 757 } 758 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 } 769 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; 787 } 788 631 789 /** @} 632 790 */
Note:
See TracChangeset
for help on using the changeset viewer.