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 1992-2003 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 * patch system files for root on metadevice 31 */ 32 33 #include <meta.h> 34 #include <stdlib.h> 35 #include <sdssc.h> 36 37 #define METAROOT_OK 0 38 #define METAROOT_ERR -1 39 #define METAROOT_NOTFOUND -2 40 41 struct def_map { 42 char **dm_fname; /* Location of file name */ 43 char *dm_default; /* Default name */ 44 }; 45 46 /* 47 * options 48 */ 49 static char *cname = NULL; /* take default */ 50 static char *sname = NULL; /* take default */ 51 static char *vname = NULL; /* take default */ 52 static char *dbname = NULL; /* take default bootlist location */ 53 static int doit = 1; 54 static int verbose = 0; 55 56 /* 57 * Map of default system file names to the place where they are stored. 58 * This is used if the -R option is specified. Note that the members of 59 * the map point to the cname, sname, vname and dbname global variables 60 * above. These global variables are used in the call to 61 * meta_patch_rootdev() in main(). 62 */ 63 static struct def_map default_names[] = { 64 &cname, META_DBCONF, 65 &sname, "/etc/system", 66 &vname, "/etc/vfstab", 67 &dbname, "/kernel/drv/md.conf" 68 }; 69 70 static int validate_stripe_root(); 71 72 /* 73 * print usage message, md_exit 74 */ 75 static void 76 usage( 77 mdsetname_t *sp, 78 int eval 79 ) 80 { 81 (void) fprintf(stderr, gettext("\ 82 usage:\t%s [-n] [-k system-name] [-m md.conf-name] [-v vfstab-name] \\\n\ 83 \t\t[-c mddb.cf-name] device\n\ 84 \t%s [-n] [-R root-path] device\n"), 85 myname, myname); 86 md_exit(sp, eval); 87 } 88 89 static void 90 free_mem() 91 { 92 int i; 93 struct def_map *map; 94 95 for (i = 0, map = default_names; 96 i < sizeof (default_names) / sizeof (struct def_map); 97 i++, map++) { 98 if (*map->dm_fname != NULL) { 99 free((void *) *map->dm_fname); 100 *map->dm_fname = NULL; 101 } 102 } 103 } 104 105 /* 106 * Check if mirror, mirnp, is a valid root filesystem, ie all 107 * submirrors must be single disk stripe, and that the slice, slicenp, 108 * if not NULL, is a component of one of the submirrors. 109 * The arg metaroot is TRUE if mirnp is the current root filesystem. 110 * Returns: 111 * METAROOT_OK if mirror is valid and slicenp is a component 112 * METAROOT_NOTFOUND if mirror valid but slicenp not a component 113 * METAROOT_ERR if mirror not a valid root 114 */ 115 static int 116 validate_mirror_root( 117 mdsetname_t *sp, 118 mdname_t *mirnp, 119 mdname_t *slicenp, 120 int metaroot, 121 md_error_t *ep 122 ) 123 { 124 int smi; 125 md_mirror_t *mirrorp; 126 char *miscname; 127 int found = 0; 128 int rval; 129 int err = 0; 130 131 if ((mirrorp = meta_get_mirror(sp, mirnp, ep)) == NULL) { 132 mde_perror(ep, ""); 133 return (METAROOT_ERR); 134 } 135 136 for (smi = 0; (smi < NMIRROR); ++smi) { 137 /* Check all submirrors */ 138 md_submirror_t *mdsp = &mirrorp->submirrors[smi]; 139 mdname_t *submirnamep = mdsp->submirnamep; 140 141 /* skip unused submirrors */ 142 if (submirnamep == NULL) { 143 assert(mdsp->state == SMS_UNUSED); 144 continue; 145 } 146 if ((miscname = metagetmiscname(submirnamep, ep)) == NULL) { 147 return (mdmderror(ep, MDE_UNKNOWN_TYPE, 148 meta_getminor(submirnamep->dev), 149 submirnamep->cname)); 150 } 151 if (strcmp(miscname, MD_STRIPE) != 0) { 152 md_eprintf(gettext("Submirror is not a stripe\n")); 153 return (METAROOT_ERR); 154 } 155 rval = validate_stripe_root(sp, submirnamep, slicenp, 156 metaroot, ep); 157 switch (rval) { 158 case METAROOT_OK: 159 found = 1; 160 break; 161 case METAROOT_ERR: 162 err++; 163 break; 164 case METAROOT_NOTFOUND: 165 default: 166 break; 167 } 168 } 169 if (err > 0) 170 return (METAROOT_ERR); 171 if (!found) 172 return (METAROOT_NOTFOUND); 173 return (METAROOT_OK); 174 } 175 176 /* 177 * Check if stripe, strnp, is a valid root filesystem, ie must 178 * be single disk stripe, and the the slice, slicenp, if not NULL, must 179 * be a component of this stripe. 180 * The arg metaroot is TRUE if strnp is the current root filesystem. 181 * Returns: 182 * METAROOT_OK if stripe is valid and slicenp is a component 183 * METAROOT_NOTFOUND if stripe valid but slicenp not a component 184 * METAROOT_ERR if stripe not a valid root 185 */ 186 static int 187 validate_stripe_root( 188 mdsetname_t *sp, 189 mdname_t *strnp, 190 mdname_t *slicenp, 191 int metaroot, 192 md_error_t *ep 193 ) 194 { 195 md_stripe_t *stripep; 196 md_row_t *rp; 197 md_comp_t *cp; 198 199 if ((stripep = meta_get_stripe(sp, strnp, ep)) == NULL) { 200 mde_perror(ep, ""); 201 return (METAROOT_ERR); 202 } 203 if (stripep->rows.rows_len != 1) { 204 md_eprintf(gettext( 205 "Concat %s has more than 1 slice\n"), strnp->cname); 206 return (METAROOT_ERR); 207 } 208 rp = &stripep->rows.rows_val[0]; 209 210 if (rp->comps.comps_len != 1) { 211 md_eprintf(gettext( 212 "Stripe %s has more than 1 slice\n"), strnp->cname); 213 return (METAROOT_ERR); 214 } 215 cp = &rp->comps.comps_val[0]; 216 if (!metaismeta(cp->compnamep)) { 217 if (slicenp == NULL) 218 return (METAROOT_OK); 219 if (strcmp(slicenp->cname, cp->compnamep->cname) == 0) 220 return (METAROOT_OK); 221 if (!metaroot) { 222 md_eprintf(gettext( 223 "Root %s is not a component of metadevice %s\n"), 224 slicenp->cname, strnp->cname); 225 } 226 return (METAROOT_NOTFOUND); 227 } 228 md_eprintf(gettext( 229 "Component %s is not a stripe\n"), cp->compnamep->cname); 230 return (METAROOT_ERR); 231 } 232 233 /* 234 * Check if the device devnp is valid. It must be a component of the 235 * metadevice that contains the root filesystem 236 */ 237 238 static int 239 validate_root_device( 240 mdsetname_t *sp, 241 mdname_t *devnp, 242 md_error_t *ep 243 ) 244 { 245 mdname_t *rootnp; 246 char *curroot; 247 char *miscname; 248 int rval; 249 250 if ((curroot = meta_get_current_root(ep)) == NULL) { 251 mde_perror(ep, ""); 252 return (METAROOT_ERR); 253 } 254 if ((rootnp = metaname(&sp, curroot, ep)) == NULL) { 255 mde_perror(ep, ""); 256 return (METAROOT_ERR); 257 } 258 259 if (metaismeta(rootnp)) { 260 /* get type */ 261 if ((miscname = metagetmiscname(rootnp, ep)) == NULL) { 262 mde_perror(ep, ""); 263 return (METAROOT_ERR); 264 } 265 if (strcmp(miscname, MD_MIRROR) == 0) { 266 if ((rval = validate_mirror_root(sp, rootnp, 267 devnp, 1, ep)) == METAROOT_OK) 268 return (METAROOT_OK); 269 if (rval == METAROOT_NOTFOUND) { 270 md_eprintf(gettext( 271 "Slice %s is not a component of root %s\n"), 272 devnp->cname, rootnp->cname); 273 } 274 return (METAROOT_ERR); 275 } else if (strcmp(miscname, MD_STRIPE) == 0) { 276 if ((rval = validate_stripe_root(sp, rootnp, 277 devnp, 1, ep)) == METAROOT_OK) 278 return (METAROOT_OK); 279 if (rval == METAROOT_NOTFOUND) { 280 md_eprintf(gettext( 281 "Slice %s is not a component of root %s\n"), 282 devnp->cname, rootnp->cname); 283 } 284 return (METAROOT_ERR); 285 } else { 286 md_eprintf(gettext( 287 "Root metadevice, %s, is not a Slice or Mirror\n"), 288 rootnp->cname); 289 return (METAROOT_ERR); 290 } 291 } else { 292 md_eprintf(gettext( 293 "Current Root %s is not a metadevice\n"), rootnp->cname); 294 return (METAROOT_ERR); 295 } 296 } 297 298 /* 299 * What we're going to do: 300 * 301 * 1) Check if the device is a metadevice or not. 302 * 303 * 2) If a metadevice, and it is valid, ie a stripe or a mirror containing 304 * a single slice, add "forceload:{drv,misc}/<modname>" of 305 * underlying drivers for the meta-root and the metadevice 306 * database to system. Otherwise, remove forceloads from system if the 307 * slice is a component of the current root metadevice. 308 * 309 * 3) Add "rootdev:/devices/..." to system. 310 * 311 * 4) Replace / mount in vfstab. 312 * 313 * 5) Repatch database locations, just to be safe. 314 */ 315 int 316 main( 317 int argc, 318 char *argv[] 319 ) 320 { 321 int i; 322 mdsetname_t *sp = NULL; 323 mdname_t *rootnp; 324 int c; 325 int ckmv_flag = 0; /* non-zero if -c, -k, -m or -v */ 326 md_error_t status = mdnullerror; 327 md_error_t *ep = &status; 328 char *miscname; 329 char *curroot; 330 mdname_t *currootnp; 331 mdname_t *currootdevnp; 332 char *root_path = NULL; 333 struct def_map *map; 334 size_t root_path_size; 335 size_t path_buf_size; 336 int error; 337 338 /* 339 * Get the locale set up before calling any other routines 340 * with messages to ouput. Just in case we're not in a build 341 * environment, make sure that TEXT_DOMAIN gets set to 342 * something. 343 */ 344 #if !defined(TEXT_DOMAIN) 345 #define TEXT_DOMAIN "SYS_TEST" 346 #endif 347 (void) setlocale(LC_ALL, ""); 348 (void) textdomain(TEXT_DOMAIN); 349 350 if ((sdssc_bind_library() == SDSSC_OKAY) && 351 (sdssc_cmd_proxy(argc, argv, SDSSC_PROXY_PRIMARY, 352 &error) == SDSSC_PROXY_DONE)) 353 exit(error); 354 355 /* initialize */ 356 if (md_init(argc, argv, 0, 1, ep) != 0 || 357 meta_check_root(ep) != 0) { 358 mde_perror(ep, ""); 359 md_exit(sp, 1); 360 } 361 362 /* parse options */ 363 optind = 1; 364 opterr = 1; 365 while ((c = getopt(argc, argv, "hnk:m:v:c:R:?")) != -1) { 366 switch (c) { 367 case 'h': 368 usage(sp, 0); 369 break; 370 case 'm': 371 dbname = optarg; 372 ckmv_flag = 1; 373 break; 374 case 'n': 375 doit = 0; 376 verbose = 1; 377 break; 378 case 'k': 379 sname = optarg; 380 ckmv_flag = 1; 381 break; 382 case 'v': 383 vname = optarg; 384 ckmv_flag = 1; 385 break; 386 case 'c': 387 cname = optarg; 388 ckmv_flag = 1; 389 break; 390 case 'R': 391 root_path = optarg; 392 break; 393 case '?': 394 if (optopt == '?') 395 usage(sp, 0); 396 /*FALLTHROUGH*/ 397 default: 398 usage(sp, 1); 399 break; 400 } 401 } 402 argc -= optind; 403 argv += optind; 404 if (argc != 1) 405 usage(sp, 1); 406 407 /* Can't use -R with any of -c, -k, -m or -v */ 408 if ((ckmv_flag != 0) && (root_path != NULL)) { 409 md_eprintf( 410 gettext("-R invalid with any of -c, -k, -m or -v\n")); 411 usage(sp, 1); 412 } 413 414 /* get device name */ 415 if ((rootnp = metaname(&sp, argv[0], ep)) == NULL) { 416 mde_perror(ep, ""); 417 md_exit(sp, 1); 418 } 419 if ((curroot = meta_get_current_root(ep)) == NULL) { 420 mde_perror(ep, ""); 421 md_exit(sp, 1); 422 } 423 /* 424 * Get device name of current root metadevice. If root is net 425 * mounted as happens if this command is part of the install 426 * process, currootnp will be set to NULL. 427 */ 428 currootnp = metaname(&sp, curroot, ep); 429 /* 430 * If the argument is the name of the current root filesystem, then 431 * the command is allowed, otherwise check that the argument is 432 * valid. 433 */ 434 if ((currootnp == NULL) || 435 (strcmp(currootnp->cname, rootnp->cname) != 0)) { 436 if (metaismeta(rootnp)) { 437 /* 438 * Validate that the metadevice is based on a 439 * single slice. If none of the -k, -m, -v, -c or 440 * -R options are specified, then the default 441 * system files are being modified and hence the 442 * current root slice must be a component of the 443 * metadevice. If any of the previously mentioned 444 * options are used don't check that the current 445 * root is a component. 446 */ 447 if ((ckmv_flag == 0) && (root_path == NULL)) { 448 /* Get device name of current root slice */ 449 if ((currootdevnp = 450 meta_get_current_root_dev(sp, ep)) 451 == NULL) { 452 mde_perror(ep, ""); 453 md_exit(sp, 1); 454 } 455 } else currootdevnp = NULL; 456 457 if ((miscname = metagetmiscname(rootnp, ep)) == NULL) { 458 mde_perror(ep, ""); 459 md_exit(sp, 1); 460 } 461 /* Check that metadevice is a mirror or a stripe */ 462 if (strcmp(miscname, MD_MIRROR) == 0) { 463 if (validate_mirror_root(sp, rootnp, 464 currootdevnp, 0, ep) != METAROOT_OK) { 465 md_exit(sp, 1); 466 } 467 } else if (strcmp(miscname, MD_STRIPE) == 0) { 468 if (validate_stripe_root(sp, rootnp, 469 currootdevnp, 0, ep) != METAROOT_OK) { 470 md_exit(sp, 1); 471 } 472 } else { 473 md_eprintf(gettext( 474 "%s is not a mirror or stripe\n"), 475 rootnp->cname); 476 md_exit(sp, 1); 477 } 478 } else { 479 /* 480 * Check that the root device is a component of the 481 * current root filesystem only if the default system 482 * files are being modified 483 */ 484 if ((ckmv_flag == 0) && (root_path == NULL)) { 485 if (validate_root_device(sp, rootnp, ep) != 0) { 486 md_exit(sp, 1); 487 } 488 } 489 } 490 } 491 492 if (meta_lock(sp, TRUE, ep)) { 493 mde_perror(ep, ""); 494 md_exit(sp, 1); 495 } 496 497 /* 498 * If -R is specified, use the default system file names relative 499 * to the new root location. 500 */ 501 if (root_path != NULL) { 502 root_path_size = strlen(root_path); 503 for (i = 0, map = default_names; 504 i < sizeof (default_names) / sizeof (struct def_map); 505 i++, map++) { 506 /* Add 1 for null terminator */ 507 path_buf_size = root_path_size + 508 strlen(map->dm_default) + 1; 509 *map->dm_fname = malloc(path_buf_size); 510 if (*map->dm_fname == NULL) { 511 md_eprintf(gettext("Cannot allocate memory \ 512 for system file path relocation\n")); 513 md_exit(sp, 1); 514 } 515 (void) snprintf(*map->dm_fname, path_buf_size, 516 "%s%s", root_path, map->dm_default); 517 } 518 } 519 520 /* patch system and vfstab for root and mddb locations */ 521 if (meta_patch_rootdev(rootnp, sname, vname, cname, dbname, doit, 522 verbose, ep) != 0) { 523 if (root_path != NULL) { 524 free_mem(); 525 } 526 mde_perror(ep, ""); 527 md_exit(sp, 1); 528 } 529 if (root_path != NULL) { 530 free_mem(); 531 } 532 533 /* return success */ 534 md_exit(sp, 0); 535 /*NOTREACHED*/ 536 return (0); 537 } 538