1 /* $NetBSD: ccdconfig.c,v 1.61 2026/02/22 17:11:23 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 __COPYRIGHT("@(#) Copyright (c) 1996, 1997\ 35 The NetBSD Foundation, Inc. All rights reserved."); 36 __RCSID("$NetBSD: ccdconfig.c,v 1.61 2026/02/22 17:11:23 christos Exp $"); 37 #endif 38 39 #include <sys/param.h> 40 #include <sys/ioctl.h> 41 #include <sys/disklabel.h> 42 #include <sys/disk.h> 43 #include <sys/stat.h> 44 #include <sys/sysctl.h> 45 #include <ctype.h> 46 #include <err.h> 47 #include <errno.h> 48 #include <fcntl.h> 49 #include <inttypes.h> 50 #include <limits.h> 51 #include <nlist.h> 52 #include <stdio.h> 53 #include <stdlib.h> 54 #include <string.h> 55 #include <unistd.h> 56 #include <util.h> 57 58 #include <dev/ccdvar.h> 59 60 #include "pathnames.h" 61 62 63 static gid_t egid; 64 static size_t lineno; 65 static int human_sz; 66 static u_int sector_size; 67 static int string_flags; 68 static int verbose; 69 static int wedge_names; 70 71 static const char *ccdconf = _PATH_CCDCONF; 72 73 static struct flagval { 74 const char *fv_flag; 75 int fv_val; 76 } flagvaltab[] = { 77 { "uniform", CCDF_UNIFORM }, 78 { "CCDF_UNIFORM", CCDF_UNIFORM }, 79 { "nolabel", CCDF_NOLABEL }, 80 { "CCDF_NOLABEL", CCDF_NOLABEL }, 81 { NULL, 0 }, 82 }; 83 84 #define CCD_CONFIG 0 /* configure a device */ 85 #define CCD_CONFIGALL 1 /* configure all devices */ 86 #define CCD_UNCONFIG 2 /* unconfigure a device */ 87 #define CCD_UNCONFIGALL 3 /* unconfigure all devices */ 88 #define CCD_DUMP 4 /* dump a ccd's configuration */ 89 #define CCD_PRINT_INFO 5 /* print ccd configuration info */ 90 91 static int checkdev(char *); 92 static int do_io(char *, u_long, struct ccd_ioctl *); 93 static int do_single(int, char **, int); 94 static int do_all(int); 95 static int dump_ccd(int, char **, int); 96 static int flags_to_val(char *); 97 static int pathtounit(char *, int *); 98 static const char *print_name(const char *); 99 static char *resolve_ccdname(char *); 100 __dead static void usage(void); 101 102 int 103 main(int argc, char *argv[]) 104 { 105 int ch, options = 0, action = CCD_CONFIG; 106 char *ev = getenv("CCDCONFIG"); 107 108 if (ev != NULL) { 109 while ((ch = *ev++) != '\0') 110 switch (ch) { 111 case 'h': human_sz = 1; break; 112 case 's': string_flags = 1; break; 113 case 'V': verbose = 2; break; 114 case 'v': verbose = 1; break; 115 case 'W': wedge_names = 2; break; 116 case 'w': wedge_names = 1; break; 117 } 118 } 119 120 egid = getegid(); 121 setegid(getgid()); 122 while ((ch = getopt(argc, argv, "cCDf:ghnpqSsuUvVWw")) != -1) { 123 switch (ch) { 124 case 'c': 125 action = CCD_CONFIG; 126 ++options; 127 break; 128 129 case 'C': 130 action = CCD_CONFIGALL; 131 ++options; 132 break; 133 134 case 'D': 135 wedge_names = 0; 136 break; 137 138 case 'f': 139 ccdconf = optarg; 140 break; 141 142 case 'g': 143 action = CCD_DUMP; 144 ++options; 145 break; 146 147 case 'h': 148 human_sz = 1; 149 break; 150 151 case 'n': 152 human_sz = 0; 153 break; 154 155 case 'p': 156 action = CCD_PRINT_INFO; 157 ++options; 158 break; 159 160 case 'q': 161 verbose = 0; 162 break; 163 164 case 'S': 165 string_flags = 0; 166 break; 167 168 case 's': 169 string_flags = 1; 170 break; 171 172 case 'u': 173 action = CCD_UNCONFIG; 174 ++options; 175 break; 176 177 case 'U': 178 action = CCD_UNCONFIGALL; 179 ++options; 180 break; 181 182 case 'V': 183 verbose = 2; 184 break; 185 186 case 'v': 187 verbose = 1; 188 break; 189 190 case 'W': 191 wedge_names = 2; 192 break; 193 194 case 'w': 195 wedge_names = 1; 196 break; 197 198 default: 199 usage(); 200 } 201 } 202 argc -= optind; 203 argv += optind; 204 205 if (options > 1) 206 usage(); 207 208 switch (action) { 209 case CCD_CONFIG: 210 case CCD_UNCONFIG: 211 exit(do_single(argc, argv, action)); 212 /* NOTREACHED */ 213 214 case CCD_CONFIGALL: 215 case CCD_UNCONFIGALL: 216 exit(do_all(action)); 217 /* NOTREACHED */ 218 219 case CCD_PRINT_INFO: 220 case CCD_DUMP: 221 default: 222 exit(dump_ccd(argc, argv, action)); 223 /* NOTREACHED */ 224 } 225 /* NOTREACHED */ 226 } 227 228 static int 229 do_single(int argc, char **argv, int action) 230 { 231 struct ccd_ioctl ccio; 232 char *ccd, *cp, *cp2, **disks; 233 char buf[MAXPATHLEN]; 234 int noflags = 0, i, ileave, flags, j; 235 unsigned int ndisks, ui; 236 int ret = 1; 237 238 if (argc == 0) 239 usage(); 240 241 flags = 0; 242 memset(&ccio, 0, sizeof(ccio)); 243 244 /* 245 * If unconfiguring, all arguments are treated as ccds. 246 */ 247 if (action == CCD_UNCONFIG || action == CCD_UNCONFIGALL) { 248 for (i = 0; argc != 0; ) { 249 cp = *argv++; --argc; 250 if ((ccd = resolve_ccdname(cp)) == NULL) { 251 warnx("invalid ccd name: %s", cp); 252 i = 1; 253 continue; 254 } 255 if (do_io(ccd, CCDIOCCLR, &ccio)) 256 i = 1; 257 else 258 if (verbose) 259 printf("%s unconfigured\n", cp); 260 free(ccd); 261 } 262 return (i); 263 } 264 265 /* Make sure there are enough arguments. */ 266 if (argc < 4) { 267 if (argc == 3) { 268 /* Assume that no flags are specified. */ 269 noflags = 1; 270 } else { 271 if (action == CCD_CONFIGALL) { 272 warnx("%s: bad line: %zu", ccdconf, lineno); 273 return (1); 274 } else 275 usage(); 276 } 277 } 278 279 /* First argument is the ccd to configure. */ 280 cp = *argv++; --argc; 281 if ((ccd = resolve_ccdname(cp)) == NULL) { 282 warnx("invalid ccd name: %s", cp); 283 return (1); 284 } 285 286 /* Next argument is the interleave factor. */ 287 cp = *argv++; --argc; 288 errno = 0; /* to check for ERANGE */ 289 ileave = (int)strtol(cp, &cp2, 10); 290 if ((errno == ERANGE) || (ileave < 0) || (*cp2 != '\0')) { 291 warnx("invalid interleave factor: %s", cp); 292 free(ccd); 293 return (1); 294 } 295 296 if (noflags == 0) { 297 /* Next argument might be the ccd configuration flags. */ 298 if ((flags = flags_to_val(*argv)) < 0) 299 flags = 0; /* It wasn't */ 300 else 301 argv++, --argc; 302 } 303 304 /* Next is the list of disks to make the ccd from. */ 305 disks = emalloc(argc * sizeof(char *)); 306 for (ndisks = 0; argc != 0; ++argv, --argc) { 307 if (getfsspecname(buf, sizeof(buf), *argv) == NULL) { 308 warn("%s", *argv); 309 goto error; 310 } 311 312 cp = strdup(buf); 313 if (cp == NULL) { 314 warn("strdup failed"); 315 goto error; 316 } 317 318 if ((j = checkdev(cp)) == 0) 319 disks[ndisks++] = cp; 320 else { 321 warnx("%s: %s", cp, strerror(j)); 322 goto error; 323 } 324 } 325 326 /* Fill in the ccio. */ 327 ccio.ccio_disks = disks; 328 ccio.ccio_ndisks = ndisks; 329 ccio.ccio_ileave = ileave; 330 ccio.ccio_flags = flags; 331 332 if (do_io(ccd, CCDIOCSET, &ccio)) 333 goto error; 334 335 if (verbose) { 336 printf("ccd%d: %d components ", ccio.ccio_unit, 337 ccio.ccio_ndisks); 338 for (ui = 0; ui < ccio.ccio_ndisks; ++ui) { 339 if ((cp2 = strrchr(disks[ui], '/')) != NULL) 340 ++cp2; 341 else 342 cp2 = disks[ui]; 343 printf("%c%s%c", 344 ui == 0 ? '(' : ' ', cp2, 345 ui == ccio.ccio_ndisks - 1 ? ')' : ','); 346 } 347 printf(", %ju blocks ", (uintmax_t)ccio.ccio_size); 348 if (ccio.ccio_ileave != 0) 349 printf("interleaved at %d blocks\n", ccio.ccio_ileave); 350 else 351 printf("concatenated\n"); 352 } 353 354 ret = 0; 355 356 error:; 357 free(ccd); 358 while (ndisks > 0) 359 free(disks[--ndisks]); 360 free(disks); 361 return (ret); 362 } 363 364 static int 365 do_all(int action) 366 { 367 FILE *f; 368 char *line, *cp, *vp, **argv; 369 int argc, rval; 370 size_t len; 371 372 rval = 0; 373 374 (void)setegid(getgid()); 375 if ((f = fopen(ccdconf, "r")) == NULL) { 376 (void)setegid(egid); 377 warn("fopen: %s", ccdconf); 378 return (1); 379 } 380 (void)setegid(egid); 381 382 while ((line = fparseln(f, &len, &lineno, "\\\\#", FPARSELN_UNESCALL)) 383 != NULL) { 384 argc = 0; 385 argv = NULL; 386 if (len == 0) 387 goto end_of_line; 388 389 for (cp = line; cp != NULL; ) { 390 while ((vp = strsep(&cp, "\t ")) != NULL && *vp == '\0') 391 ; 392 if (vp == NULL) 393 continue; 394 395 argv = erealloc(argv, sizeof(char *) * (argc + 2)); 396 argv[argc++] = vp; 397 argv[argc] = NULL; 398 399 /* 400 * If our action is to unconfigure all, then pass 401 * just the first token to do_single() and ignore 402 * the rest. Since this will be encountered on 403 * our first pass through the line, the Right 404 * Thing will happen. 405 */ 406 if (action == CCD_UNCONFIGALL) { 407 if (do_single(argc, argv, action)) 408 rval = 1; 409 goto end_of_line; 410 } 411 } 412 if (argc != 0) 413 if (do_single(argc, argv, action)) 414 rval = 1; 415 416 end_of_line:; 417 if (argv != NULL) 418 free(argv); 419 free(line); 420 } 421 422 (void)fclose(f); 423 return (rval); 424 } 425 426 static int 427 checkdev(char *path) 428 { 429 struct stat st; 430 431 if (stat(path, &st) != 0) 432 return (errno); 433 434 if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) 435 return (EINVAL); 436 437 return (0); 438 } 439 440 static int 441 pathtounit(char *path, int *unitp) 442 { 443 struct stat st; 444 445 if (stat(path, &st) != 0) 446 return (errno); 447 448 if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) 449 return (EINVAL); 450 451 *unitp = DISKUNIT(st.st_rdev); 452 453 return (0); 454 } 455 456 static char * 457 resolve_ccdname(char *name) 458 { 459 char *path, *buf; 460 const char *p; 461 char c; 462 size_t len; 463 int rawpart; 464 465 if (name[0] == '/' || name[0] == '.') { 466 /* Assume they gave the correct pathname. */ 467 path = estrdup(name); 468 } else { 469 470 len = strlen(name); 471 c = name[len - 1]; 472 473 if (isdigit((unsigned char)c)) { 474 if ((rawpart = getrawpartition()) < 0) 475 return NULL; 476 easprintf(&path, "/dev/%s%c", name, 'a' + rawpart); 477 } else 478 easprintf(&path, "/dev/%s", name); 479 } 480 481 /* 482 * Convert to raw device if possible. 483 */ 484 buf = emalloc(MAXPATHLEN); 485 p = getdiskrawname(buf, MAXPATHLEN, path); 486 if (p) { 487 free(path); 488 path = estrdup(p); 489 } 490 free(buf); 491 492 return path; 493 } 494 495 static int 496 do_io(char *path, u_long cmd, struct ccd_ioctl *cciop) 497 { 498 int fd; 499 const char *cp; 500 501 if ((fd = open(path, O_RDWR, 0640)) < 0) { 502 warn("open: %s", path); 503 return (1); 504 } 505 506 if (ioctl(fd, cmd, cciop) < 0) { 507 switch (cmd) { 508 case CCDIOCSET: 509 cp = "CCDIOCSET"; 510 break; 511 512 case CCDIOCCLR: 513 cp = "CCDIOCCLR"; 514 break; 515 516 default: 517 cp = "unknown"; 518 } 519 warn("ioctl (%s): %s", cp, path); 520 (void)close(fd); 521 return (1); 522 } 523 524 (void)close(fd); 525 return (0); 526 } 527 528 static const char * 529 print_name(const char * dev) 530 { 531 int fd; 532 ssize_t len; 533 struct dkwedge_info dkw; 534 static char nbuf[MAXPATHLEN]; 535 536 sector_size = DEV_BSIZE; 537 538 if (!wedge_names) 539 return dev; 540 541 if (strncmp(dev, "/dev/", 5) == 0) 542 fd = opendisk(dev + 5, O_RDONLY, nbuf, sizeof nbuf, 0); 543 else if (strchr(dev, '/') == NULL) 544 fd = opendisk(dev, O_RDONLY, nbuf, sizeof nbuf, 0); 545 else 546 fd = open(dev, O_RDONLY); 547 548 if (fd < 0) 549 return dev; 550 551 if (ioctl(fd, DIOCGWEDGEINFO, &dkw) == -1) { 552 close(fd); 553 return dev; 554 } 555 close(fd); 556 557 if (dkw.dkw_wname[0] == '\0') 558 return dev; 559 560 if (wedge_names < 2) { 561 if (strchr((char *)dkw.dkw_wname, '\n') != NULL || 562 strchr((char *)dkw.dkw_wname, ' ') != NULL || 563 strchr((char *)dkw.dkw_wname, '\t') != NULL) 564 return dev; 565 } 566 567 len = snprintf(nbuf, sizeof nbuf, "NAME=%s", dkw.dkw_wname); 568 if (len < 0) 569 return dev; 570 if ((size_t)len > sizeof nbuf) 571 return dev; 572 if (len > 35) /* don't return GUIDS */ 573 return dev; 574 575 return nbuf; 576 } 577 578 static void 579 config_info(int u, struct ccddiskinfo *ccd, char *str) 580 { 581 int i; 582 static int header_printed = 0; 583 584 if (header_printed == 0 && verbose) { 585 printf("# ccd\t\tileave\tflags\tcomponent devices\n"); 586 header_printed = 1; 587 } 588 589 /* Dump out softc information. */ 590 printf("ccd%d\t\t%d\t0x%x\t", u, ccd->ccd_ileave, 591 ccd->ccd_flags & CCDF_USERMASK); 592 593 /* Read component pathname and display component info. */ 594 for (i = ccd->ccd_ndisks; --i >= 0; ) { 595 printf("%s%s", print_name(str), i ? " " : "\n"); 596 str += strlen(str) + 1; 597 } 598 fflush(stdout); 599 } 600 601 static void 602 get_sec_size(int u) 603 { 604 int fd; 605 char ccdname[32]; 606 char buf[MAXPATHLEN]; 607 608 sector_size = DEV_BSIZE; 609 610 if (snprintf(ccdname, sizeof ccdname, "ccd%d", u) >= 611 (ssize_t)sizeof ccdname) /* very unlikely */ 612 return; 613 614 fd = opendisk(ccdname, O_RDONLY, buf, sizeof buf, 0); 615 if (fd < 0) 616 return; 617 618 if (ioctl(fd, DIOCGSECTORSIZE, §or_size) == -1) 619 sector_size = DEV_BSIZE; 620 621 (void) close(fd); 622 } 623 624 static void 625 ccd_info(int u, struct ccddiskinfo *ccd, char *names) 626 { 627 const char *sep; 628 char *p; 629 size_t len; 630 u_int n; 631 static int header_printed = 0; 632 633 if (verbose && !header_printed) { 634 printf("ccd\t%11s%18s%15s\t%s\n", "ileave", "flags", "size", 635 "component devices"); 636 if (verbose > 1) 637 printf("----\t%11s%18s%15s\t%s\n", "------", "-----", 638 "----", "--------- -------"); 639 header_printed = 1; 640 } else if (verbose > 1) 641 putchar('\n'); 642 643 printf("ccd%d\t%11d", u, ccd->ccd_ileave); 644 645 if (string_flags) { 646 u_int f = ccd->ccd_flags & CCDF_USERMASK; 647 648 if (f == 0) 649 printf("%18s", "none"); 650 else { 651 for (len = n = 0; flagvaltab[n].fv_flag != NULL; n++) 652 if (f & flagvaltab[n].fv_val) { 653 len += strlen(flagvaltab[n].fv_flag)+1; 654 f &= ~flagvaltab[n].fv_val; 655 } 656 657 if (len > 0) 658 len--; 659 if (len < 18) 660 printf("%*s", (int)(18 - len), ""); 661 else 662 putchar(' '); 663 664 f = ccd->ccd_flags & CCDF_USERMASK; 665 for (len = 1, n = 0; flagvaltab[n].fv_flag != NULL; n++) 666 if (f & flagvaltab[n].fv_val) { 667 printf("%s%s", &","[len], 668 flagvaltab[n].fv_flag); 669 len = 0; 670 f &= ~flagvaltab[n].fv_val; 671 } 672 } 673 } else 674 printf(" %#16x", ccd->ccd_flags & CCDF_USERMASK); 675 676 if (human_sz) { 677 char szbuf[6]; 678 679 get_sec_size(u); 680 681 if (humanize_number(szbuf, sizeof szbuf, 682 (intmax_t)ccd->ccd_size * sector_size, 683 NULL, HN_AUTOSCALE, HN_DECIMAL | HN_B) == -1) 684 goto just_number; 685 686 printf("%15s", szbuf); 687 688 } else { 689 just_number:; 690 printf("%15ju", (uintmax_t)ccd->ccd_size); 691 } 692 693 sep = "\t"; 694 for (p = names, n = ccd->ccd_ndisks; n > 0; n--) { 695 printf("%-*s%s", verbose > 1 && p != names ? 57 : 1, 696 sep, print_name(p)); 697 698 sep = verbose > 1 ? "\n" : " "; 699 700 p += strlen(p) + 1; 701 } 702 putchar('\n'); 703 } 704 705 static int 706 dumpccdinfo(int u, int action) 707 { 708 struct ccddiskinfo ccd; 709 size_t s = sizeof(ccd); 710 const char *str; 711 char *names; 712 size_t len; 713 714 str = "kern.ccd.info"; 715 if (sysctlbyname(str, &ccd, &s, &u, sizeof(u)) == -1) { 716 if (errno == ENOENT) 717 warnx("ccd%d is not configured", u); 718 else 719 warn("cannot get %s for ccd%d",str,u); 720 return 1; 721 } 722 723 str = "kern.ccd.components"; 724 if (sysctlbyname(str, NULL, &len, &u, sizeof(u)) == -1) { 725 warn("error getting %s (length) for ccd%d", str, u); 726 return 1; 727 } 728 names = emalloc(len); 729 if (sysctlbyname(str, names, &len, &u, sizeof(u)) == -1) { 730 warn("error getting %s (data) for ccd%d", str, u); 731 free(names); 732 return 1; 733 } 734 735 if (action == CCD_PRINT_INFO) 736 ccd_info(u, &ccd, names); 737 else 738 config_info(u, &ccd, names); 739 740 free(names); 741 742 return 0; 743 } 744 745 static int 746 cmp_unit(const void *a, const void *b) 747 { 748 return *(const int *)a - *(const int *)b; 749 } 750 751 static int 752 dump_ccd(int argc, char **argv, int action) 753 { 754 const char *sys; 755 int errs = 0; 756 757 if (argc == 0) { 758 int *units; 759 size_t nunits = 0; 760 761 sys = "kern.ccd.units"; 762 if (sysctlbyname(sys, NULL, &nunits, NULL, 0) == -1) { 763 switch (errno) { 764 case ENOENT: 765 warnx("no ccd driver in the kernel"); 766 return 1; 767 case ENOMEM: 768 break; /* XXX ??? Huh, why? */ 769 default: 770 err(EXIT_FAILURE, 771 "error getting %s (length)", sys); 772 /* NOTREACHED */ 773 } 774 } 775 776 if (nunits == 0) { 777 warnx("no concatenated disks configured"); 778 return 1; 779 } 780 781 units = emalloc(nunits); 782 783 if (sysctlbyname(sys, units, &nunits, NULL, 0) == -1) 784 err(EXIT_FAILURE, "error getting %s (data)", sys); 785 786 nunits /= sizeof(*units); 787 if (nunits > 1) 788 qsort(units, nunits, sizeof units[0], cmp_unit); 789 for (size_t i = 0; i < nunits; i++) 790 errs += dumpccdinfo(units[i], action); 791 free(units); 792 return errs; 793 } 794 795 /* Dump ccd configuration to stdout. */ 796 while (argc) { 797 int i = 0; /* XXX: vax gcc */ 798 int error; 799 char *cp = *argv++; --argc; 800 char *ccd; 801 802 if ((ccd = resolve_ccdname(cp)) == NULL) { 803 warnx("invalid ccd name: %s", cp); 804 errs++; 805 continue; 806 } 807 if ((error = pathtounit(ccd, &i)) != 0) { 808 errno = error; 809 warn("%s", ccd); 810 free(ccd); 811 errs++; 812 continue; 813 } 814 errs += dumpccdinfo(i, action); 815 free(ccd); 816 } 817 return errs; 818 } 819 820 821 static int 822 flags_to_val(char *flags) 823 { 824 char *cp, *tok; 825 int i, tmp, val = ~CCDF_USERMASK; 826 827 /* 828 * The most common case is that of NIL flags, so check for 829 * those first. 830 */ 831 if (strcasecmp("none", flags) == 0 || strcasecmp("0x0", flags) == 0 || 832 strcmp("0", flags) == 0) 833 return (0); 834 835 /* Check for values represented by strings. */ 836 cp = estrdup(flags); 837 tmp = 0; 838 for (tok = cp; (tok = strtok(tok, ",")) != NULL; tok = NULL) { 839 for (i = 0; flagvaltab[i].fv_flag != NULL; ++i) 840 if (strcasecmp(tok, flagvaltab[i].fv_flag) == 0) 841 break; 842 if (flagvaltab[i].fv_flag == NULL) { 843 free(cp); 844 goto bad_string; 845 } 846 tmp |= flagvaltab[i].fv_val; 847 } 848 849 /* If we get here, the string was ok. */ 850 free(cp); 851 val = tmp; 852 goto out; 853 854 bad_string:; 855 856 #if CCDF_NOLABEL > CCDF_UNIFORM 857 #define MAX_FLAG CCDF_NOLABEL 858 #else 859 #define MAX_FLAG CCDF_UNIFORM 860 #endif 861 862 val = (int)strtoi(flags, &cp, 0, 0, MAX_FLAG, &tmp); 863 if (tmp != 0 || cp == flags || *cp != '\0') 864 return -1; 865 out:; 866 return (((val & ~CCDF_USERMASK) == 0) ? val : -1); 867 } 868 869 static void 870 usage(void) 871 { 872 const char *progname = getprogname(); 873 874 fprintf(stderr, "usage: %s [-cv] ccd ileave [flags] dev...\n", 875 progname); 876 fprintf(stderr, " %s -C [-v] [-f config_file]\n", progname); 877 fprintf(stderr, " %s -g [-vWw] [ccd...]\n", progname); 878 fprintf(stderr, " %s -p [-hsVvWw] [ccd...]\n", progname); 879 fprintf(stderr, " %s -u [-v] ccd...\n", progname); 880 fprintf(stderr, " %s -U [-v] [-f config_file]\n", progname); 881 exit(1); 882 } 883