Changeset d1d355f in mainline for uspace/app/hrctl/hrctl.c
- Timestamp:
- 2025-05-06T21:30:30Z (5 weeks ago)
- Children:
- c2f0160
- Parents:
- 40f56a4
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/app/hrctl/hrctl.c
r40f56a4 rd1d355f 43 43 #include <str_error.h> 44 44 45 #define HRCTL_SAMPLE_CONFIG_PATH "/cfg/sample_hr_config.sif" 45 /* #define HRCTL_SAMPLE_CONFIG_PATH "/cfg/sample_hr_config.sif" */ 46 47 #define NAME "hrctl" 46 48 47 49 static void usage(void); 48 static errno_t fill_config_devs(int, char **, int,hr_config_t *);50 static errno_t fill_config_devs(int, char **, hr_config_t *); 49 51 static errno_t load_config(const char *, hr_config_t *); 50 52 51 53 static const char usage_str[] = 52 "Usage: hrctl [OPTION]... -n <dev_no> <devices>...\n"54 "Usage: hrctl [OPTION]...\n" 53 55 "\n" 54 56 "Options:\n" 55 " -h, --help display this message and exit\n"56 " -C, --create-file=PATH create an array from file,\n"57 " sample file at: " HRCTL_SAMPLE_CONFIG_PATH "\n"58 " -A, --auto-assemble try to auto assemble all valid arrays\n"59 " -s, --status display status of active arrays\n"60 " -H, --hotspare=DEV add hotspare extent\n"61 " - D, --destroy destroy/disassemble an active array\n"62 " -F, --fail-extent fail an extent, use with -D and set it before\n"63 " -c, --create=NAME create new array\n"64 " -a, --assemble try to assemble from specified extents\n"65 " -n non-zero number of devices\n"66 " - l, --level=LEVEL set the RAID level,\n"67 " valid values: 0, 1, 4, 5\n"68 " -0 striping\n"69 " -1 mirroring\n"70 " - 4 parity on one extent\n"71 " -5 distributed parity\n"72 " \n"73 " When specifying name for creation or assembly, the device name\n"74 " is automatically prepended with \"devices/\" prefix.\n"57 " -h, --help Display this message and exit.\n" 58 "\n" 59 " -c, --create Create a volume, options:\n" 60 " name {-l , --level level} device... manual device specification, or\n" 61 " -f configuration.sif create from configuration file.\n" 62 "\n" 63 " -a, --assemble Assemble volume(s), options:\n" 64 " [device...] manual device specification, or\n" 65 " [-f configuration.sif] assemble from configuration file, or\n" 66 " no option is automatic assembly.\n" 67 "\n" 68 " -d, --disassemble Deactivate/disassemble, options:\n" 69 " [volume] specific volume, or\n" 70 " all volumes with no specified option.\n" 71 "\n" 72 " -m, --modify volume Modify a volume, options:\n" 73 " -f, --fail index fail an extent, or\n" 74 " -h, --hotspare device add hotspare.\n" 75 "\n" 76 " -s, --status Display status of active volumes.\n" 75 77 "\n" 76 78 "Example usage:\n" 77 " hrctl --create hr0 -0 -n 2 devices/\\hw\\0 devices/\\hw\\1\n" 78 " - creates new mirroring RAID device named /hr0 consisting\n" 79 " of 2 drives\n" 80 " hrctl --assemble -n 2 devices/\\hw\\0 devices/\\hw\\1\n" 81 " - assembles RAID devices from specified extents,\n" 82 " that were previously in an (active) array\n" 83 " hrctl devices/hr0 --hotspare=devices/disk10\n" 84 " - adds \"devices/disk10\" as hotspare extent\n" 85 " hrctl -F 0 -D devices/hr0\n" 86 " - marks first extent as FAILED\n" 79 "\t\thrctl --create hr0 --level 5 disk1 disk2 disk3\n" 80 "\t\thrctl -c hr0 -l 5 disk1 disk2 disk3\n" 81 "\t\thrctl -c -f cfg.sif\n" 82 "\t\thrctl --assemble disk1 disk2 disk3\n" 83 "\t\thrctl -a\n" 84 "\t\thrctl -d devices/hr0\n" 85 "\t\thrctl -d\n" 86 "\t\thrctl --modify devices/hr0 --fail 0\n" 87 "\t\thrctl --modify devices/hr0 --hotspare disk4\n" 88 "\t\thrctl -s\n" 89 "\n" 90 "Volume service names are automatically prepended with \"devices/\" prefix.\n" 91 "\n" 87 92 "Limitations:\n" 88 " - device name must be less than 32 characters in size\n"; 89 90 static struct option const long_options[] = { 91 { "help", no_argument, 0, 'h' }, 92 { "status", no_argument, 0, 's' }, 93 { "assemble", no_argument, 0, 'a' }, 94 { "create", required_argument, 0, 'c' }, 95 { "level", required_argument, 0, 'l' }, 96 { "create-file", required_argument, 0, 'C' }, 97 { "auto-assemble", no_argument, 0, 'A' }, 98 { "destroy", required_argument, 0, 'D' }, 99 { "fail-extent", required_argument, 0, 'F' }, 100 { "hotspare", required_argument, 0, 'H' }, 101 { 0, 0, 0, 0 } 102 }; 93 "\t- volume name must be shorter than 32 characters\n"; 103 94 104 95 static void usage(void) … … 107 98 } 108 99 109 static errno_t fill_config_devs(int argc, char **argv, int optind, 110 hr_config_t *cfg) 100 static errno_t fill_config_devs(int argc, char **argv, hr_config_t *cfg) 111 101 { 112 102 errno_t rc; 113 103 size_t i; 114 104 115 for (i = 0; i < cfg->dev_no; i++) {105 for (i = 0; i < HR_MAX_EXTENTS; i++) { 116 106 rc = loc_service_get_id(argv[optind], &cfg->devs[i], 0); 117 107 if (rc == ENOENT) { 118 printf( "hrctl: no device \"%s\", marking as missing\n",108 printf(NAME ": device \"%s\" not found, aborting\n", 119 109 argv[optind]); 120 cfg->devs[i] = 0;110 return ENOENT; 121 111 } else if (rc != EOK) { 122 printf( "hrctl: error resolving device \"%s\", aborting\n",112 printf(NAME ": error resolving device \"%s\", aborting\n", 123 113 argv[optind]); 124 114 return EINVAL; 125 115 } 126 116 127 optind++; 128 } 117 if (++optind >= argc) 118 break; 119 } 120 121 if (optind < argc) { 122 printf(NAME ": too many devices specified, max = %u\n", 123 HR_MAX_EXTENTS); 124 return ELIMIT; 125 } 126 127 cfg->dev_no = i; 129 128 130 129 return EOK; … … 226 225 } 227 226 227 static int handle_create(int argc, char **argv) 228 { 229 if (optind >= argc) { 230 printf(NAME ": no arguments to --create\n"); 231 return EXIT_FAILURE; 232 } 233 234 hr_config_t *vol_config = calloc(1, sizeof(hr_config_t)); 235 if (vol_config == NULL) { 236 printf(NAME ": not enough memory"); 237 return ENOMEM; 238 } 239 240 if (str_cmp(argv[optind], "-f") == 0) { 241 if (++optind >= argc) { 242 printf(NAME ": not enough arguments\n"); 243 goto error; 244 } 245 const char *config_path = argv[optind++]; 246 errno_t rc = load_config(config_path, vol_config); 247 if (rc != EOK) { 248 printf(NAME ": config parsing failed\n"); 249 goto error; 250 } 251 } else { 252 /* we need name + --level + arg + at least one extent */ 253 if (optind + 3 >= argc) { 254 printf(NAME ": not enough arguments\n"); 255 goto error; 256 } 257 258 const char *name = argv[optind++]; 259 if (str_size(name) >= HR_DEVNAME_LEN) { 260 printf(NAME ": devname must be less then 32 bytes.\n"); 261 goto error; 262 } 263 264 str_cpy(vol_config->devname, HR_DEVNAME_LEN, name); 265 266 const char *level_opt = argv[optind++]; 267 if (str_cmp(level_opt, "--level") != 0 && 268 str_cmp(level_opt, "-l") != 0) { 269 printf(NAME ": unknown option \"%s\"\n", level_opt); 270 goto error; 271 } 272 273 vol_config->level = strtol(argv[optind++], NULL, 10); 274 275 errno_t rc = fill_config_devs(argc, argv, vol_config); 276 if (rc != EOK) 277 goto error; 278 } 279 280 if (optind < argc) { 281 printf(NAME ": unexpected arguments\n"); 282 goto error; 283 } 284 285 hr_t *hr; 286 errno_t rc = hr_sess_init(&hr); 287 if (rc != EOK) { 288 printf(NAME ": server session init failed: %s\n", 289 str_error(rc)); 290 goto error; 291 } 292 293 rc = hr_create(hr, vol_config); 294 if (rc != EOK) { 295 printf(NAME ": creation failed: %s\n", 296 str_error(rc)); 297 goto error; 298 } 299 300 hr_sess_destroy(hr); 301 302 free(vol_config); 303 return EXIT_SUCCESS; 304 error: 305 free(vol_config); 306 return EXIT_FAILURE; 307 } 308 309 static int handle_assemble(int argc, char **argv) 310 { 311 if (optind >= argc) { 312 size_t cnt; 313 errno_t rc = hr_auto_assemble(&cnt); 314 if (rc != EOK) { 315 /* XXX: here have own error codes */ 316 printf("hrctl: auto assemble rc: %s\n", str_error(rc)); 317 return EXIT_FAILURE; 318 } 319 320 printf(NAME ": auto assembled %zu volumes\n", cnt); 321 return EXIT_SUCCESS; 322 } 323 324 hr_config_t *vol_config = calloc(1, sizeof(hr_config_t)); 325 if (vol_config == NULL) { 326 printf(NAME ": not enough memory"); 327 return ENOMEM; 328 } 329 330 if (str_cmp(argv[optind], "-f") == 0) { 331 if (++optind >= argc) { 332 printf(NAME ": not enough arguments\n"); 333 goto error; 334 } 335 const char *config_path = argv[optind++]; 336 errno_t rc = load_config(config_path, vol_config); 337 if (rc != EOK) { 338 printf(NAME ": config parsing failed\n"); 339 goto error; 340 } 341 if (optind < argc) { 342 printf(NAME ": unexpected arguments\n"); 343 goto error; 344 } 345 } else { 346 errno_t rc = fill_config_devs(argc, argv, vol_config); 347 if (rc != EOK) 348 goto error; 349 } 350 351 hr_t *hr; 352 errno_t rc = hr_sess_init(&hr); 353 if (rc != EOK) { 354 printf(NAME ": server session init failed: %s\n", 355 str_error(rc)); 356 goto error; 357 } 358 359 size_t cnt; 360 rc = hr_assemble(hr, vol_config, &cnt); 361 if (rc != EOK) { 362 printf(NAME ": assmeble failed: %s\n", str_error(rc)); 363 goto error; 364 } 365 366 printf("hrctl: auto assembled %zu volumes\n", cnt); 367 368 hr_sess_destroy(hr); 369 370 free(vol_config); 371 return EXIT_SUCCESS; 372 error: 373 free(vol_config); 374 return EXIT_FAILURE; 375 } 376 377 static int handle_disassemble(int argc, char **argv) 378 { 379 if (optind >= argc) { 380 errno_t rc = hr_stop_all(); 381 if (rc != EOK) { 382 printf(NAME ": stopping some volumes failed: %s\n", 383 str_error(rc)); 384 return EXIT_FAILURE; 385 } 386 return EXIT_SUCCESS; 387 } 388 389 if (optind + 1 < argc) { 390 printf(NAME ": only 1 device can be manually specified\n"); 391 return EXIT_FAILURE; 392 } 393 394 const char *devname = argv[optind++]; 395 396 errno_t rc = hr_stop(devname); 397 if (rc != EOK) { 398 printf(NAME ": disassembly of device \"%s\" failed: %s\n", 399 devname, str_error(rc)); 400 return EXIT_FAILURE; 401 } 402 403 return EXIT_SUCCESS; 404 } 405 406 static int handle_modify(int argc, char **argv) 407 { 408 if (optind >= argc) { 409 printf(NAME ": no arguments to --modify\n"); 410 return EXIT_FAILURE; 411 } 412 413 const char *volname = argv[optind++]; 414 415 /* at least 1 option and its agument */ 416 if (optind + 1 >= argc) { 417 printf(NAME ": not enough arguments\n"); 418 return EXIT_FAILURE; 419 } 420 421 if (optind + 2 < argc) { 422 printf(NAME ": unexpected arguments\n"); 423 return EXIT_FAILURE; 424 } 425 426 if (str_cmp(argv[optind], "--fail") == 0 || 427 str_cmp(argv[optind], "-f") == 0) { 428 optind++; 429 unsigned long extent = strtol(argv[optind++], NULL, 10); 430 errno_t rc = hr_fail_extent(volname, extent); 431 if (rc != EOK) { 432 printf(NAME ": failing extent failed: %s\n", 433 str_error(rc)); 434 return EXIT_FAILURE; 435 } 436 } else if (str_cmp(argv[optind], "--hotspare") == 0 || 437 str_cmp(argv[optind], "-h") == 0) { 438 optind++; 439 errno_t rc = hr_add_hotspare(volname, argv[optind++]); 440 if (rc != EOK) { 441 printf(NAME ": adding hotspare failed: %s\n", 442 str_error(rc)); 443 return EXIT_FAILURE; 444 } 445 } else { 446 printf(NAME ": unknown argument\n"); 447 return EXIT_FAILURE; 448 } 449 450 return EXIT_SUCCESS; 451 } 452 453 static int handle_status(int argc, char **argv) 454 { 455 (void)argc; 456 (void)argv; 457 458 errno_t rc = hr_print_status(); 459 if (rc != EOK) { 460 printf(NAME ": status printing failed: %s\n", str_error(rc)); 461 return EXIT_FAILURE; 462 } 463 464 return EXIT_SUCCESS; 465 } 466 228 467 int main(int argc, char **argv) 229 468 { 230 errno_t rc; 231 int retval, c; 232 bool create, assemble; 233 long fail_extent = -1; 234 hr_t *hr = NULL; 235 hr_config_t *cfg; 236 237 cfg = calloc(1, sizeof(hr_config_t)); 238 if (cfg == NULL) 239 return 1; 240 241 retval = 0; 242 cfg->level = HR_LVL_UNKNOWN; 243 cfg->dev_no = 0; 244 create = assemble = false; 469 int rc = EXIT_SUCCESS; 470 int c; 245 471 246 472 if (argc < 2) { 247 goto bad; 473 rc = EXIT_FAILURE; 474 goto end; 248 475 } 249 476 … … 252 479 optind = 0; 253 480 481 struct option const top_level_opts[] = { 482 { "help", no_argument, 0, 'h' }, 483 { "create", no_argument, 0, 'c' }, 484 { "assemble", no_argument, 0, 'a' }, 485 { "disassemble", no_argument, 0, 'd' }, 486 { "modify", no_argument, 0, 'm' }, 487 { "status", no_argument, 0, 's' }, 488 { 0, 0, 0, 0 } 489 }; 490 254 491 while (c != -1) { 255 c = getopt_long(argc, argv, "hsC:c:Aal:0145Ln:D:F:H:", 256 long_options, NULL); 492 c = getopt_long(argc, argv, "hcadms", top_level_opts, NULL); 257 493 switch (c) { 494 case 'h': 495 usage(); 496 return EXIT_SUCCESS; 497 case 'c': 498 rc = handle_create(argc, argv); 499 goto end; 500 case 'a': 501 rc = handle_assemble(argc, argv); 502 goto end; 503 case 'd': 504 rc = handle_disassemble(argc, argv); 505 goto end; 506 case 'm': 507 rc = handle_modify(argc, argv); 508 goto end; 258 509 case 's': 259 free(cfg); 260 rc = hr_print_status(); 261 if (rc != EOK) 262 return 1; 263 return 0; 264 case 'C': 265 /* only support 1 array inside config for now XXX */ 266 rc = load_config(optarg, cfg); 267 if (rc != EOK) { 268 printf("hrctl: failed to load config\n"); 269 free(cfg); 270 return 1; 271 } 272 create = true; 273 goto skip; 274 case 'c': 275 if (str_size(optarg) > sizeof(cfg->devname) - 1) { 276 printf("hrctl: device name too long\n"); 277 free(cfg); 278 return 1; 279 } 280 str_cpy(cfg->devname, sizeof(cfg->devname), optarg); 281 create = true; 282 break; 283 case 'A': 284 size_t cnt; 285 rc = hr_auto_assemble(&cnt); 286 if (rc != EOK) { 287 /* XXX: here have own error codes */ 288 printf("hrctl: auto assemble rc: %s\n", 289 str_error(rc)); 290 } else { 291 printf("hrctl: auto assembled %zu volumes\n", 292 cnt); 293 } 294 return rc; 295 case 'a': 296 /* 297 * XXX: redo this, no devname, only svc ids... 298 * 299 * find some other way to rename the arrays..., 300 * 301 * some metadata editation tool... something like 302 * fdisk but can only change devnames on inactive 303 * extents... 304 */ 305 306 /* 307 * XXX: remake whole parsing, don't allow -a 308 * to have any levels set or anything 309 */ 310 assemble = true; 311 break; 312 case 'D': 313 rc = hr_stop(optarg, fail_extent); 314 free(cfg); 315 if (rc != EOK) { 316 printf("hrctl: got %s\n", str_error(rc)); 317 return rc; 318 } 319 return 0; 320 case 'F': 321 fail_extent = strtol(optarg, NULL, 10); 322 break; 323 case 'l': 324 if (cfg->level != HR_LVL_UNKNOWN) 325 goto bad; 326 cfg->level = strtol(optarg, NULL, 10); 327 break; 328 case '0': 329 if (cfg->level != HR_LVL_UNKNOWN) 330 goto bad; 331 cfg->level = HR_LVL_0; 332 break; 333 case '1': 334 if (cfg->level != HR_LVL_UNKNOWN) 335 goto bad; 336 cfg->level = HR_LVL_1; 337 break; 338 case '4': 339 if (cfg->level != HR_LVL_UNKNOWN) 340 goto bad; 341 cfg->level = HR_LVL_4; 342 break; 343 case '5': 344 if (cfg->level != HR_LVL_UNKNOWN) 345 goto bad; 346 cfg->level = HR_LVL_5; 347 break; 348 case 'n': 349 cfg->dev_no = strtol(optarg, NULL, 10); 350 if ((int)cfg->dev_no + optind != argc) 351 goto bad; 352 rc = fill_config_devs(argc, argv, optind, cfg); 353 if (rc != EOK) { 354 free(cfg); 355 return 1; 356 } 357 goto skip; 358 case 'H': 359 if (optind != 3 && argc != 4) 360 goto bad; 361 362 service_id_t hotspare; 363 service_id_t vol_svc_id; 364 365 rc = loc_service_get_id(argv[1], &vol_svc_id, 0); 366 if (rc != EOK) { 367 printf("hrctl: error resolving volume \"%s\", " 368 "aborting extent addition\n", argv[1]); 369 goto bad; 370 } 371 372 rc = loc_service_get_id(optarg, &hotspare, 0); 373 if (rc != EOK) { 374 printf("hrctl: error resolving device \"%s\", " 375 "aborting extent addition\n", optarg); 376 goto bad; 377 } 378 379 rc = hr_add_hotspare(vol_svc_id, hotspare); 380 if (rc != EOK) 381 printf("hrctl: hr_add_hotspare() rc: %s\n", 382 str_error(rc)); 383 384 free(cfg); 385 if (rc != EOK) 386 return 1; 387 else 388 return 0; 389 case 'h': 510 rc = handle_status(argc, argv); 511 goto end; 390 512 default: 391 usage(); 392 free(cfg); 393 return 0; 394 } 395 } 396 397 skip: 398 if ((create && assemble) || (!create && !assemble)) 399 goto bad; 400 401 if (create && cfg->level == HR_LVL_UNKNOWN) { 402 printf("hrctl: invalid level, exiting\n"); 403 goto bad; 404 } 405 406 if (cfg->dev_no > HR_MAX_EXTENTS) { 407 printf("hrctl: too many devices, exiting\n"); 408 goto bad; 409 } 410 411 if (cfg->dev_no == 0) { 412 printf("hrctl: invalid number of devices, exiting\n"); 413 goto bad; 414 } 415 416 rc = hr_sess_init(&hr); 417 if (rc != EOK) { 418 printf("hrctl: hr_sess_init() rc: %s\n", str_error(rc)); 419 retval = 1; 420 goto end; 421 } 422 423 if (create) { 424 rc = hr_create(hr, cfg); 425 printf("hrctl: hr_create() rc: %s\n", str_error(rc)); 426 } else if (assemble) { 427 size_t assembled_cnt = 0; 428 rc = hr_assemble(hr, cfg, &assembled_cnt); 429 if (rc != EOK) { 430 /* XXX: here have own error codes */ 431 printf("hrctl: auto assemble rc: %s\n", str_error(rc)); 432 } else { 433 printf("hrctl: auto assembled %zu volumes\n", 434 assembled_cnt); 435 } 436 513 goto end; 514 } 437 515 } 438 516 439 517 end: 440 free(cfg); 441 hr_sess_destroy(hr); 442 return retval; 443 bad: 444 free(cfg); 445 printf("hrctl: bad usage, try hrctl --help\n"); 446 return 1; 518 if (rc != EXIT_SUCCESS) 519 printf(NAME ": use --help to see usage\n"); 520 return rc; 447 521 } 448 522
Note:
See TracChangeset
for help on using the changeset viewer.