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