1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * initialize metadevices 31 */ 32 33 #include <meta.h> 34 35 #include <sdssc.h> 36 #include <sys/lvm/md_mirror.h> 37 #include <syslog.h> 38 #include "meta_set_prv.h" 39 40 /* 41 * try to initialize devices 42 */ 43 #define DO_AGAIN 0 44 #define DONT_DO 1 45 #define IS_DONE 2 46 47 /* 48 * mn_send_command 49 * 50 * generate a command of the form "metainit -s setname [-n] [-f] ....." 51 * 52 * If -n option is *not* set, send the metainit command *with -n set* to 53 * all nodes first. Do this with MD_MSGF_STOP_ON_ERROR set. 54 * That means if it fails on one node, it'll return immediately, 55 * reporting the error. 56 * By doing so, we have a dryrun first that has to succeed on every node 57 * before we start the command for real. 58 * This saves us from backing out a metainit command that succeeded on 59 * some nodes but failed on one. 60 */ 61 static int 62 mn_send_command( 63 mdsetname_t **spp, 64 int argc, 65 char **argv, 66 mdcmdopts_t options, 67 int flags, 68 char *context, 69 md_error_t *ep 70 ) 71 { 72 int newargc; 73 char **newargv; 74 int i; 75 int ret; 76 int dryrun_only = 0; 77 78 79 newargv = calloc(argc+5, sizeof (char *)); 80 newargv[0] = "metainit"; 81 newargv[1] = "-s"; 82 newargv[2] = (*spp)->setname; 83 newargv[3] = "-n"; /* always do "-n" first */ 84 newargc = 4; 85 if ((options & MDCMD_DOIT) == 0) { 86 dryrun_only = 1; 87 } 88 if ((options & MDCMD_FORCE) != 0) { 89 newargv[newargc] = "-f"; 90 newargc++; 91 } 92 for (i = 0; i < argc; i++, newargc++) 93 newargv[newargc] = argv[i]; 94 ret = meta_mn_send_command(*spp, newargc, newargv, 95 flags | MD_DRYRUN | MD_NOLOG, context, ep); 96 97 if ((dryrun_only == 0) && (ret == 0)) { 98 /* 99 * Do it for real now. Remove "-n" from the arguments and 100 * MD_DRYRUN from the flags. If we fail this time the master 101 * must panic as the mddbs may be inconsistent. 102 */ 103 newargv[3] = ""; /* this was "-n" before */ 104 ret = meta_mn_send_command(*spp, newargc, newargv, 105 flags | MD_RETRY_BUSY | MD_PANIC_WHEN_INCONSISTENT, 106 context, ep); 107 } 108 109 free(newargv); 110 return (ret); 111 } 112 113 static int 114 init_entries( 115 mdsetname_t **spp, 116 md_tab_t *tabp, 117 mdcmdopts_t options, 118 uint_t flags, 119 bool_t called_thru_rpc, 120 md_error_t *ep 121 ) 122 { 123 uint_t cnt = 0; 124 uint_t line; 125 int rval = 0; 126 int ret; 127 128 /* for all matching entries, which haven't already been done */ 129 for (line = 0; (line < tabp->nlines); ++line) { 130 md_tab_line_t *linep = &tabp->lines[line]; 131 132 /* see if already done */ 133 if (linep->flags != DO_AGAIN) 134 continue; 135 136 /* try it */ 137 if ((called_thru_rpc == FALSE) && 138 meta_is_mn_name(spp, linep->argv[0], ep)) { 139 /* 140 * MN set, send command to all nodes 141 * Note that is sp is NULL, meta_is_mn_name() derives 142 * sp from linep->argv which is the metadevice arg 143 */ 144 ret = mn_send_command(spp, linep->argc, linep->argv, 145 options, flags, linep->context, ep); 146 } else { 147 ret = meta_init_name(spp, linep->argc, linep->argv, 148 options, ep); 149 if (ret != 0) { 150 if (!(flags & MD_IGNORE_STDERR)) { 151 mderrorextra(ep, linep->context); 152 mde_perror(ep, ""); 153 rval = -1; 154 } 155 mdclrerror(ep); 156 } 157 } 158 if (ret == 0) { 159 linep->flags = IS_DONE; 160 ++cnt; 161 } 162 } 163 164 /* return success */ 165 if (rval != 0) 166 return (rval); 167 return (cnt); 168 } 169 170 /* 171 * initialize all devices in set 172 */ 173 static int 174 init_all( 175 mdsetname_t **spp, 176 mdcmdopts_t options, 177 bool_t called_thru_rpc, 178 md_error_t *ep 179 ) 180 { 181 md_tab_t *tabp = NULL; 182 size_t setlen; 183 uint_t more; 184 int done; 185 int eval = -1; 186 187 /* create local set, if necessary */ 188 if (*spp == NULL) { 189 if ((*spp = metasetname(MD_LOCAL_NAME, ep)) == NULL) { 190 mde_perror(ep, ""); 191 mdclrerror(ep); 192 return (eval); 193 } 194 } 195 setlen = strlen((*spp)->setname); 196 197 /* 198 * Only take the lock if this is not a MN set 199 * We can only enter this code for a MN set if we are the initiator 200 * and in this case, we don't want to take locks. 201 */ 202 if (meta_is_mn_set((*spp), ep) == 0) { 203 /* grab set lock */ 204 if (meta_lock(*spp, TRUE, ep)) { 205 mde_perror(ep, ""); 206 mdclrerror(ep); 207 return (eval); 208 } 209 210 /* check for ownership */ 211 if (meta_check_ownership(*spp, ep) != 0) { 212 mde_perror(ep, ""); 213 mdclrerror(ep); 214 return (eval); 215 } 216 217 /* lock is held across init_entries */ 218 options |= MDCMD_NOLOCK; 219 } 220 221 /* get md.tab, preen entries */ 222 if ((tabp = meta_tab_parse(NULL, ep)) == NULL) { 223 mde_perror(ep, ""); 224 mdclrerror(ep); 225 return (eval); 226 } 227 228 for (more = 0; (more < tabp->nlines); ++more) { 229 md_tab_line_t *linep = &tabp->lines[more]; 230 char *cname = linep->cname; 231 char *p; 232 size_t len; 233 234 /* better have args */ 235 assert((linep->argc > 0) && (linep->argv[0] != NULL)); 236 237 /* only do metadevices and hotspare pools in set */ 238 if (linep->type & TAB_MD_HSP) { 239 if ((p = strrchr(cname, '/')) == NULL) { 240 len = 0; 241 } else { 242 len = p - cname; 243 } 244 if ((len == setlen) && 245 (strncmp(cname, (*spp)->setname, len) == 0)) { 246 linep->flags = DO_AGAIN; 247 } else { 248 linep->flags = DONT_DO; 249 } 250 251 } else { 252 linep->flags = DONT_DO; 253 } 254 } 255 256 eval = 1; 257 258 /* while more devices get made */ 259 do { 260 done = init_entries(spp, tabp, options, 261 MD_IGNORE_STDERR|MD_RETRY_BUSY, called_thru_rpc, ep); 262 } while (done > 0); 263 264 /* now do it and report errors */ 265 if (init_entries(spp, tabp, options, MD_RETRY_BUSY, 266 called_thru_rpc, ep) >= 0) 267 eval = 0; /* success */ 268 mdclrerror(ep); 269 270 /* cleanup, return success */ 271 out: 272 meta_tab_free(tabp); 273 return (eval); 274 } 275 276 /* 277 * initialize named device or hotspare pool 278 */ 279 static int 280 init_name( 281 mdsetname_t **spp, 282 int argc, 283 char *argv[], 284 mdcmdopts_t options, 285 int called_thru_rpc, 286 md_error_t *ep 287 ) 288 { 289 md_tab_t *tabp = NULL; 290 md_tab_line_t *linep = NULL; 291 int rval = -1; 292 int ret; 293 294 /* look in md.tab */ 295 if (argc == 1) { 296 char *name = argv[0]; 297 298 /* get md.tab entries */ 299 if ((tabp = meta_tab_parse(NULL, ep)) == NULL) { 300 if (! mdissyserror(ep, ENOENT)) 301 return (-1); 302 } 303 304 /* look in md.tab */ 305 if ((linep = meta_tab_find(*spp, tabp, name, TAB_MD_HSP)) 306 != NULL) { 307 argc = linep->argc; 308 argv = linep->argv; 309 } 310 } 311 312 if ((called_thru_rpc == FALSE) && 313 meta_is_mn_name(spp, argv[0], ep)) { 314 /* 315 * MN set, send command to all nodes 316 */ 317 ret = mn_send_command(spp, argc, argv, options, 318 MD_DISP_STDERR, NO_CONTEXT_STRING, ep); 319 } else 320 ret = meta_init_name(spp, argc, argv, options, ep); 321 322 if (ret != 0) { 323 if (linep != NULL) 324 mderrorextra(ep, linep->context); 325 goto out; 326 } 327 rval = 0; /* success */ 328 329 /* cleanup, return error */ 330 out: 331 if (tabp != NULL) 332 meta_tab_free(tabp); 333 return (rval); 334 } 335 336 /* 337 * print usage message 338 */ 339 static void 340 usage( 341 mdsetname_t *sp, 342 int eval 343 ) 344 { 345 #ifndef lint 346 (void) fprintf(stderr, gettext("\ 347 usage: %s [-s setname] [-n] [-f] concat/stripe numstripes\n\ 348 width component... [-i interlace]\n\ 349 [width component... [-i interlace]] [-h hotspare_pool]\n\ 350 %s [-s setname] [-n] [-f] mirror -m submirror...\n\ 351 [read_options] [write_options] [pass_num]\n\ 352 %s [-s setname] [-n] [-f] RAID -r component...\n\ 353 [-i interlace] [-h hotspare_pool]\n\ 354 [-k] [-o original_column_count]\n\ 355 %s [-s setname] [-n] [-f] hotspare_pool [hotspare...]\n\ 356 %s [-s setname] [-n] [-f] softpart -p [-A alignment]\n\ 357 [-e] device size|all\n\ 358 %s [-s setname] [-n] [-f] md.tab_entry\n\ 359 %s [-s setname] [-n] [-f] -a\n\ 360 %s -r\n"), myname, myname, myname, myname, myname, myname, myname, 361 myname); 362 #endif /* ! lint */ 363 md_exit(sp, eval); 364 } 365 366 /* 367 * If we fail during the attempt to take the auto-take disksets 368 * we need to tell the kernel to cleanup the in-core set struct 369 * so that we have a chance to take the set again later. 370 */ 371 static void 372 auto_take_cleanup(mdsetname_t *sp, side_t sideno) 373 { 374 mddb_config_t c; 375 376 (void) memset(&c, 0, sizeof (c)); 377 c.c_setno = sp->setno; 378 c.c_sideno = sideno; 379 380 if (metaioctl(MD_RELEASE_SET, &c, &c.c_mde, NULL) != 0) { 381 mde_perror(&c.c_mde, "auto_take_cleanup"); 382 return; 383 } 384 } 385 386 /* 387 * Take the diskset. 388 * 389 * This is a clean auto-take set, so do the work to take it. 390 * This is a streamlined version of the code in meta_set_take. We avoid the 391 * need for talking to the rpc.metad since that can't run this early during the 392 * boot. We don't need to talk to the metad for this diskset since we're the 393 * only host in the set. 394 */ 395 static void 396 take_set(md_set_record *sr) 397 { 398 mdsetname_t sn; 399 md_drive_desc *dd; 400 md_error_t error = mdnullerror; 401 md_replicalist_t *rlp = NULL; 402 md_replicalist_t *rl; 403 daddr_t nblks = 0; 404 md_drive_record *dr; 405 side_t sideno; 406 407 /* 408 * Several of the functions we call take a sp param so 409 * construct one from the set record. 410 */ 411 sn.setname = sr->sr_setname; 412 sn.setno = sr->sr_setno; 413 sn.setdesc = sr2setdesc(sr); 414 sn.lockfd = MD_NO_LOCK; 415 416 if (sr->sr_flags & MD_SR_MB_DEVID) 417 dd = metaget_drivedesc(&sn, MD_BASICNAME_OK | PRINT_FAST, 418 &error); 419 else 420 dd = metaget_drivedesc(&sn, MD_BASICNAME_OK, &error); 421 422 if (dd == NULL) { 423 mde_perror(&error, ""); 424 mdclrerror(&error); 425 return; 426 } 427 428 /* 429 * Skip call to tk_own_bydd. This talks to rpc.metamhd (which we can't 430 * do yet) and is not needed for auto-take disksets since we are not 431 * doing SCSI reservations on these drives. 432 */ 433 434 if (setup_db_bydd(&sn, dd, 0, &error) != 0) { 435 if (! mdismddberror(&error, MDE_DB_ACCOK) && 436 ! mdismddberror(&error, MDE_DB_TAGDATA)) { 437 /* 438 * Skip call to rel_own_bydd since that really just 439 * calls rpc.metamhd which we don't need to do, 440 * so there really isn't anything to rollback here. 441 */ 442 mde_perror(&error, ""); 443 mdclrerror(&error); 444 return; 445 } 446 mdclrerror(&error); 447 } 448 449 if ((sideno = getmyside(&sn, &error)) == MD_SIDEWILD) { 450 mde_perror(&error, ""); 451 return; 452 } 453 454 if (snarf_set(&sn, FALSE, &error) != 0) { 455 if (mdismddberror(&error, MDE_DB_STALE) || 456 mdismddberror(&error, MDE_DB_TAGDATA) || 457 ! mdismddberror(&error, MDE_DB_NODB) && 458 ! mdismddberror(&error, MDE_DB_NOTOWNER)) { 459 /* 460 * rollback 461 * Normally MDE_DB_STALE or MDE_DB_TAGDATA 462 * would still keep the set but in this case we don't 463 * want to do that. This will probably result in the 464 * boot going in to single-user since we won't have the 465 * set so any attempted mounts using the set's metadevices 466 * will fail. However, that is a "good thing" so the 467 * sysadmin can fix the set. Normally they would see 468 * all of these problems when they ran the take and be 469 * able to immediately fix the problem. 470 */ 471 mde_perror(&error, ""); 472 auto_take_cleanup(&sn, sideno); 473 return; 474 } 475 } 476 477 /* 478 * Call metareplicalist and upd_dr_dbinfo. 479 * Most of that code is only needed to synchronize amongst the multiple 480 * hosts in a set, which is not applicable in our case. But we do a 481 * subset here to handle the case when the user had been 482 * adding/deleting/balancing mddbs when this node panic'd. We are 483 * synchronizing the ondisk mddbs to the list of drive records stored 484 * in the local mddb. 485 */ 486 if (metareplicalist(&sn, (MD_BASICNAME_OK | PRINT_FAST), &rlp, &error) 487 < 0) { 488 /* rollback */ 489 mde_perror(&error, ""); 490 auto_take_cleanup(&sn, sideno); 491 return; 492 } 493 494 /* 495 * The following code is equivalent to upd_dr_dbinfo for syncronizing 496 * the local host only. That function is normally run through the 497 * metad with a local and daemon side but we'll do all of the work 498 * here. 499 */ 500 501 /* find the smallest existing replica */ 502 for (rl = rlp; rl != NULL; rl = rl->rl_next) { 503 md_replica_t *r; 504 505 r = rl->rl_repp; 506 nblks = ((nblks == 0) ? r->r_nblk : min(r->r_nblk, nblks)); 507 } 508 509 if (nblks <= 0) 510 nblks = MD_DBSIZE; 511 512 for (dr = sr->sr_drivechain; dr; dr = dr->dr_next) { 513 int dbcnt; 514 mddrivename_t *dnp; 515 md_replicalist_t *rl; 516 517 /* 518 * The cname style for dnp and replica list will be same since 519 * both use the the same flags MD_BASICNAME_OK|PRINT_FAST which 520 * will always provide the cached value. 521 */ 522 if ((dnp = metadrivename_withdrkey(&sn, sideno, dr->dr_key, 523 MD_BASICNAME_OK | PRINT_FAST, &error)) == NULL) { 524 mde_perror(&error, ""); 525 metafreereplicalist(rlp); 526 auto_take_cleanup(&sn, sideno); 527 return; 528 } 529 530 dbcnt = 0; 531 /* see how many replicas are on this drive */ 532 for (rl = rlp; rl != NULL; rl = rl->rl_next) { 533 if (strcmp(rl->rl_repp->r_namep->drivenamep->cname, dnp->cname) 534 == 0) 535 dbcnt++; 536 } 537 538 /* Adjust the fields in the copy */ 539 dr->dr_dbcnt = dbcnt; 540 dr->dr_dbsize = dbcnt > 0 ? nblks : 0; 541 } 542 543 /* 544 * If the set doesn't have the MD_SR_MB_DEVID bit set, i.e 545 * the drives in the set don't have the device id information, 546 * then stick it in if possible. 547 * 548 * If updating the master block fails for whatever reason, it's 549 * okay. It just means the disk(s) in the diskset won't be self 550 * identifying. 551 */ 552 if (!(sr->sr_flags & MD_SR_MB_DEVID)) { 553 if (meta_update_mb(&sn, dd, &error) == 0) { 554 sr->sr_flags |= MD_SR_MB_DEVID; 555 mdclrerror(&error); 556 } 557 } 558 559 commitset(sr, FALSE, &error); 560 561 metafreereplicalist(rlp); 562 563 /* 564 * This finishes up the logical equivalent of meta_set_take. 565 */ 566 if (meta_resync_all(&sn, MD_DEF_RESYNC_BUF_SIZE, &error) != 0) { 567 mde_perror(&error, ""); 568 mdclrerror(&error); 569 } 570 } 571 572 /* 573 * Take the disksets that are marked to be taken at boot time. 574 */ 575 static void 576 auto_take_sets() 577 { 578 int max_sets; 579 int i; 580 md_error_t error = mdnullerror; 581 char *hostname; 582 583 if ((max_sets = get_max_sets(&error)) == 0) 584 return; 585 586 if (!mdisok(&error)) { 587 mde_perror(&error, ""); 588 return; 589 } 590 591 /* set up so auto-take errors also go to syslog */ 592 openlog("metainit", LOG_ODELAY, LOG_USER); 593 metasyslog = 1; 594 595 hostname = mynode(); 596 597 /* 598 * For each possible set number (skip set 0 which is the unnamed local 599 * set), see if we really have a diskset. If so, check if auto-take 600 * is enabled. 601 * 602 * In order to take the set it must have drives and it must not be 603 * stuck in mid-add. The sr_validate routine within rpc.metad will 604 * delete sets that are in mid-add when it runs. 605 */ 606 for (i = 1; i < max_sets; i++) { 607 md_set_record *sr; 608 609 if ((sr = metad_getsetbynum(i, &error)) == NULL) { 610 mdclrerror(&error); 611 continue; 612 } 613 614 if (sr->sr_flags & MD_SR_AUTO_TAKE && !(sr->sr_flags & MD_SR_ADD)) { 615 int j; 616 int cnt = 0; 617 int host_mismatch = 0; 618 int take = 0; 619 md_drive_record *dr; 620 621 /* check for host renames or multiple hosts in set */ 622 for (j = 0; j < MD_MAXSIDES; j++) { 623 /* Skip empty slots */ 624 if (sr->sr_nodes[j][0] == '\0') 625 continue; 626 627 cnt++; 628 if (strcmp(sr->sr_nodes[j], hostname) != 0) 629 host_mismatch = 1; 630 } 631 632 /* paranoid check that we're the only host in the set */ 633 if (cnt > 1) { 634 md_eprintf(gettext( 635 "diskset %s: auto-take enabled and multiple hosts in set\n"), 636 sr->sr_setname); 637 continue; 638 } 639 640 if (host_mismatch) { 641 /* The host was renamed, repair the set. */ 642 for (j = 0; j < MD_MAXSIDES; j++) { 643 /* Skip empty slots */ 644 if (sr->sr_nodes[j][0] == '\0') 645 continue; 646 647 (void) strncpy(sr->sr_nodes[j], hostname, 648 sizeof (sr->sr_nodes[j])); 649 commitset(sr, FALSE, &error); 650 if (!mdisok(&error)) { 651 mde_perror(&error, ""); 652 mdclrerror(&error); 653 } else { 654 md_eprintf(gettext( 655 "new hostname %s, update auto-take diskset %s\n"), 656 hostname, sr->sr_setname); 657 } 658 break; 659 } 660 } 661 662 /* set must have at least one drive to be taken */ 663 for (dr = sr->sr_drivechain; dr != NULL; dr = dr->dr_next) { 664 /* ignore drives in mid-add */ 665 if (!(dr->dr_flags & MD_DR_ADD)) { 666 take = 1; 667 break; 668 } 669 } 670 671 if (take) 672 take_set(sr); 673 else 674 md_eprintf(gettext( 675 "diskset %s: auto-take enabled but set has no drives\n"), 676 sr->sr_setname); 677 } 678 } 679 } 680 681 /* 682 * mainline. crack command line arguments. 683 */ 684 int 685 main( 686 int argc, 687 char *argv[] 688 ) 689 { 690 char *sname = NULL; 691 mdsetname_t *sp = NULL; 692 enum action { 693 NONE, 694 INIT, 695 ALL 696 } todo = NONE; 697 mdcmdopts_t options = (MDCMD_DOIT | MDCMD_PRINT); 698 int c; 699 md_error_t status = mdnullerror; 700 md_error_t *ep = &status; 701 702 md_error_t dummystatus = mdnullerror; 703 md_error_t *dummyep = &dummystatus; 704 int eval = 1; 705 int error; 706 bool_t called_thru_rpc = FALSE; 707 char *cp; 708 709 /* 710 * Get the locale set up before calling any other routines 711 * with messages to ouput. Just in case we're not in a build 712 * environment, make sure that TEXT_DOMAIN gets set to 713 * something. 714 */ 715 #if !defined(TEXT_DOMAIN) 716 #define TEXT_DOMAIN "SYS_TEST" 717 #endif 718 (void) setlocale(LC_ALL, ""); 719 (void) textdomain(TEXT_DOMAIN); 720 if ((cp = strstr(argv[0], ".rpc_call")) != NULL) { 721 *cp = '\0'; /* cut off ".rpc_call" */ 722 called_thru_rpc = TRUE; 723 } else { 724 if (sdssc_bind_library() == SDSSC_OKAY) 725 if (sdssc_cmd_proxy(argc, argv, SDSSC_PROXY_PRIMARY, 726 &error) == SDSSC_PROXY_DONE) 727 exit(error); 728 } 729 730 /* initialize */ 731 if (md_init(argc, argv, 0, 1, ep) != 0 || 732 meta_check_root(ep) != 0) { 733 mde_perror(ep, ""); 734 md_exit(sp, 1); 735 } 736 737 /* parse args */ 738 optind = 1; 739 opterr = 1; 740 while ((c = getopt(argc, argv, "afhnrs:?")) != -1) { 741 switch (c) { 742 743 /* help */ 744 case 'h': 745 usage(sp, 0); 746 break; 747 748 /* set name */ 749 case 's': 750 sname = optarg; 751 break; 752 753 /* all devices in md.tab */ 754 case 'a': 755 if (todo != NONE) 756 usage(sp, 1); 757 todo = ALL; 758 options |= MDCMD_ALLOPTION; 759 break; 760 /* check for validity, but don't really init */ 761 case 'n': 762 options &= ~MDCMD_DOIT; 763 break; 764 765 /* for recovery */ 766 case 'r': 767 if (todo != NONE) 768 usage(sp, 1); 769 todo = INIT; 770 break; 771 772 /* mounted and swapped components are OK */ 773 case 'f': 774 options |= MDCMD_FORCE; 775 break; 776 777 case '?': 778 if (optopt == '?') 779 usage(sp, 0); 780 /*FALLTHROUGH*/ 781 default: 782 usage(sp, 1); 783 break; 784 } 785 } 786 787 if (sname != NULL) { 788 if ((sp = metasetname(sname, ep)) == NULL) { 789 mde_perror(ep, ""); 790 md_exit(sp, 1); 791 } 792 } 793 argc -= optind; 794 argv += optind; 795 if (todo == NONE) { 796 if (argc <= 0) { 797 usage(sp, 1); 798 } 799 } else if (argc > 0) { 800 usage(sp, 1); 801 } 802 803 804 /* setup database locations */ 805 if (meta_setup_db_locations(ep) != 0) { 806 mde_perror(ep, ""); 807 if (mdismddberror(ep, MDE_DB_STALE)) 808 md_exit(sp, 66); 809 if (! mdiserror(ep, MDE_MDDB_CKSUM)) /* relatively benign */ 810 md_exit(sp, 1); 811 } 812 if (todo == INIT) { /* load and take auto-take sets */ 813 auto_take_sets(); 814 md_exit(sp, 0); 815 } else if (todo == ALL) { /* initialize all devices in md.tab */ 816 eval = init_all(&sp, options, called_thru_rpc, ep); 817 } else { /* initialize the named device */ 818 eval = 0; 819 if (init_name(&sp, argc, argv, options, called_thru_rpc, 820 ep) != 0) { 821 /* 822 * If we're dealing with MN metadevices and we are 823 * directly called, then the appropriate error message 824 * has already been displayed. So just exit. 825 */ 826 if (meta_is_mn_set(sp, dummyep) && (!called_thru_rpc)) { 827 md_exit(sp, 1); 828 } 829 mde_perror(ep, ""); 830 mdclrerror(ep); 831 eval = 1; 832 goto nomdcf; 833 } 834 } 835 836 domdcf: 837 /* update md.cf, return success */ 838 if (meta_update_md_cf(sp, ep) != 0) { 839 mde_perror(ep, ""); 840 eval = 1; 841 } 842 843 nomdcf: 844 md_exit(sp, eval); 845 /*NOTREACHED*/ 846 return (eval); 847 } 848