/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" /* * patch system files for root on metadevice */ #include #include #include #define METAROOT_OK 0 #define METAROOT_ERR -1 #define METAROOT_NOTFOUND -2 struct def_map { char **dm_fname; /* Location of file name */ char *dm_default; /* Default name */ }; /* * options */ static char *cname = NULL; /* take default */ static char *sname = NULL; /* take default */ static char *vname = NULL; /* take default */ static char *dbname = NULL; /* take default bootlist location */ static int doit = 1; static int verbose = 0; /* * Map of default system file names to the place where they are stored. * This is used if the -R option is specified. Note that the members of * the map point to the cname, sname, vname and dbname global variables * above. These global variables are used in the call to * meta_patch_rootdev() in main(). */ static struct def_map default_names[] = { &cname, META_DBCONF, &sname, "/etc/system", &vname, "/etc/vfstab", &dbname, "/kernel/drv/md.conf" }; static int validate_stripe_root(); /* * print usage message, md_exit */ static void usage( mdsetname_t *sp, int eval ) { (void) fprintf(stderr, gettext("\ usage:\t%s [-n] [-k system-name] [-m md.conf-name] [-v vfstab-name] \\\n\ \t\t[-c mddb.cf-name] device\n\ \t%s [-n] [-R root-path] device\n"), myname, myname); md_exit(sp, eval); } static void free_mem() { int i; struct def_map *map; for (i = 0, map = default_names; i < sizeof (default_names) / sizeof (struct def_map); i++, map++) { if (*map->dm_fname != NULL) { free((void *) *map->dm_fname); *map->dm_fname = NULL; } } } /* * Check if mirror, mirnp, is a valid root filesystem, ie all * submirrors must be single disk stripe, and that the slice, slicenp, * if not NULL, is a component of one of the submirrors. * The arg metaroot is TRUE if mirnp is the current root filesystem. * Returns: * METAROOT_OK if mirror is valid and slicenp is a component * METAROOT_NOTFOUND if mirror valid but slicenp not a component * METAROOT_ERR if mirror not a valid root */ static int validate_mirror_root( mdsetname_t *sp, mdname_t *mirnp, mdname_t *slicenp, int metaroot, md_error_t *ep ) { int smi; md_mirror_t *mirrorp; char *miscname; int found = 0; int rval; int err = 0; if ((mirrorp = meta_get_mirror(sp, mirnp, ep)) == NULL) { mde_perror(ep, ""); return (METAROOT_ERR); } for (smi = 0; (smi < NMIRROR); ++smi) { /* Check all submirrors */ md_submirror_t *mdsp = &mirrorp->submirrors[smi]; mdname_t *submirnamep = mdsp->submirnamep; /* skip unused submirrors */ if (submirnamep == NULL) { assert(mdsp->state == SMS_UNUSED); continue; } if ((miscname = metagetmiscname(submirnamep, ep)) == NULL) { return (mdmderror(ep, MDE_UNKNOWN_TYPE, meta_getminor(submirnamep->dev), submirnamep->cname)); } if (strcmp(miscname, MD_STRIPE) != 0) { md_eprintf(gettext("Submirror is not a stripe\n")); return (METAROOT_ERR); } rval = validate_stripe_root(sp, submirnamep, slicenp, metaroot, ep); switch (rval) { case METAROOT_OK: found = 1; break; case METAROOT_ERR: err++; break; case METAROOT_NOTFOUND: default: break; } } if (err > 0) return (METAROOT_ERR); if (!found) return (METAROOT_NOTFOUND); return (METAROOT_OK); } /* * Check if stripe, strnp, is a valid root filesystem, ie must * be single disk stripe, and the the slice, slicenp, if not NULL, must * be a component of this stripe. * The arg metaroot is TRUE if strnp is the current root filesystem. * Returns: * METAROOT_OK if stripe is valid and slicenp is a component * METAROOT_NOTFOUND if stripe valid but slicenp not a component * METAROOT_ERR if stripe not a valid root */ static int validate_stripe_root( mdsetname_t *sp, mdname_t *strnp, mdname_t *slicenp, int metaroot, md_error_t *ep ) { md_stripe_t *stripep; md_row_t *rp; md_comp_t *cp; if ((stripep = meta_get_stripe(sp, strnp, ep)) == NULL) { mde_perror(ep, ""); return (METAROOT_ERR); } if (stripep->rows.rows_len != 1) { md_eprintf(gettext( "Concat %s has more than 1 slice\n"), strnp->cname); return (METAROOT_ERR); } rp = &stripep->rows.rows_val[0]; if (rp->comps.comps_len != 1) { md_eprintf(gettext( "Stripe %s has more than 1 slice\n"), strnp->cname); return (METAROOT_ERR); } cp = &rp->comps.comps_val[0]; if (!metaismeta(cp->compnamep)) { if (slicenp == NULL) return (METAROOT_OK); if (strcmp(slicenp->cname, cp->compnamep->cname) == 0) return (METAROOT_OK); if (!metaroot) { md_eprintf(gettext( "Root %s is not a component of metadevice %s\n"), slicenp->cname, strnp->cname); } return (METAROOT_NOTFOUND); } md_eprintf(gettext( "Component %s is not a stripe\n"), cp->compnamep->cname); return (METAROOT_ERR); } /* * Check if the device devnp is valid. It must be a component of the * metadevice that contains the root filesystem */ static int validate_root_device( mdsetname_t *sp, mdname_t *devnp, md_error_t *ep ) { mdname_t *rootnp; char *curroot; char *miscname; int rval; if ((curroot = meta_get_current_root(ep)) == NULL) { mde_perror(ep, ""); return (METAROOT_ERR); } if ((rootnp = metaname(&sp, curroot, UNKNOWN, ep)) == NULL) { mde_perror(ep, ""); return (METAROOT_ERR); } if (metaismeta(rootnp)) { /* get type */ if ((miscname = metagetmiscname(rootnp, ep)) == NULL) { mde_perror(ep, ""); return (METAROOT_ERR); } if (strcmp(miscname, MD_MIRROR) == 0) { if ((rval = validate_mirror_root(sp, rootnp, devnp, 1, ep)) == METAROOT_OK) return (METAROOT_OK); if (rval == METAROOT_NOTFOUND) { md_eprintf(gettext( "Slice %s is not a component of root %s\n"), devnp->cname, rootnp->cname); } return (METAROOT_ERR); } else if (strcmp(miscname, MD_STRIPE) == 0) { if ((rval = validate_stripe_root(sp, rootnp, devnp, 1, ep)) == METAROOT_OK) return (METAROOT_OK); if (rval == METAROOT_NOTFOUND) { md_eprintf(gettext( "Slice %s is not a component of root %s\n"), devnp->cname, rootnp->cname); } return (METAROOT_ERR); } else { md_eprintf(gettext( "Root metadevice, %s, is not a Slice or Mirror\n"), rootnp->cname); return (METAROOT_ERR); } } else { md_eprintf(gettext( "Current Root %s is not a metadevice\n"), rootnp->cname); return (METAROOT_ERR); } } /* * What we're going to do: * * 1) Check if the device is a metadevice or not. * * 2) If a metadevice, and it is valid, ie a stripe or a mirror containing * a single slice, add "forceload:{drv,misc}/" of * underlying drivers for the meta-root and the metadevice * database to system. Otherwise, remove forceloads from system if the * slice is a component of the current root metadevice. * * 3) Add "rootdev:/devices/..." to system. * * 4) Replace / mount in vfstab. * * 5) Repatch database locations, just to be safe. */ int main( int argc, char *argv[] ) { int i; mdsetname_t *sp = NULL; mdname_t *rootnp; int c; int ckmv_flag = 0; /* non-zero if -c, -k, -m or -v */ md_error_t status = mdnullerror; md_error_t *ep = &status; char *miscname; char *curroot; mdname_t *currootnp; mdname_t *currootdevnp; char *root_path = NULL; struct def_map *map; size_t root_path_size; size_t path_buf_size; int error; /* * Get the locale set up before calling any other routines * with messages to ouput. Just in case we're not in a build * environment, make sure that TEXT_DOMAIN gets set to * something. */ #if !defined(TEXT_DOMAIN) #define TEXT_DOMAIN "SYS_TEST" #endif (void) setlocale(LC_ALL, ""); (void) textdomain(TEXT_DOMAIN); if ((sdssc_bind_library() == SDSSC_OKAY) && (sdssc_cmd_proxy(argc, argv, SDSSC_PROXY_PRIMARY, &error) == SDSSC_PROXY_DONE)) exit(error); /* initialize */ if (md_init(argc, argv, 0, 1, ep) != 0 || meta_check_root(ep) != 0) { mde_perror(ep, ""); md_exit(sp, 1); } /* parse options */ optind = 1; opterr = 1; while ((c = getopt(argc, argv, "hnk:m:v:c:R:?")) != -1) { switch (c) { case 'h': usage(sp, 0); break; case 'm': dbname = optarg; ckmv_flag = 1; break; case 'n': doit = 0; verbose = 1; break; case 'k': sname = optarg; ckmv_flag = 1; break; case 'v': vname = optarg; ckmv_flag = 1; break; case 'c': cname = optarg; ckmv_flag = 1; break; case 'R': root_path = optarg; break; case '?': if (optopt == '?') usage(sp, 0); /*FALLTHROUGH*/ default: usage(sp, 1); break; } } argc -= optind; argv += optind; if (argc != 1) usage(sp, 1); /* Can't use -R with any of -c, -k, -m or -v */ if ((ckmv_flag != 0) && (root_path != NULL)) { md_eprintf( gettext("-R invalid with any of -c, -k, -m or -v\n")); usage(sp, 1); } /* get device name */ if ((rootnp = metaname(&sp, argv[0], UNKNOWN, ep)) == NULL) { mde_perror(ep, ""); md_exit(sp, 1); } if ((curroot = meta_get_current_root(ep)) == NULL) { mde_perror(ep, ""); md_exit(sp, 1); } /* * Get device name of current root metadevice. If root is net * mounted as happens if this command is part of the install * process, currootnp will be set to NULL. */ currootnp = metaname(&sp, curroot, UNKNOWN, ep); /* * If the argument is the name of the current root filesystem, then * the command is allowed, otherwise check that the argument is * valid. */ if ((currootnp == NULL) || (strcmp(currootnp->cname, rootnp->cname) != 0)) { if (metaismeta(rootnp)) { /* * Validate that the metadevice is based on a * single slice. If none of the -k, -m, -v, -c or * -R options are specified, then the default * system files are being modified and hence the * current root slice must be a component of the * metadevice. If any of the previously mentioned * options are used don't check that the current * root is a component. */ if ((ckmv_flag == 0) && (root_path == NULL)) { /* Get device name of current root slice */ if ((currootdevnp = meta_get_current_root_dev(sp, ep)) == NULL) { mde_perror(ep, ""); md_exit(sp, 1); } } else currootdevnp = NULL; if ((miscname = metagetmiscname(rootnp, ep)) == NULL) { mde_perror(ep, ""); md_exit(sp, 1); } /* Check that metadevice is a mirror or a stripe */ if (strcmp(miscname, MD_MIRROR) == 0) { if (validate_mirror_root(sp, rootnp, currootdevnp, 0, ep) != METAROOT_OK) { md_exit(sp, 1); } } else if (strcmp(miscname, MD_STRIPE) == 0) { if (validate_stripe_root(sp, rootnp, currootdevnp, 0, ep) != METAROOT_OK) { md_exit(sp, 1); } } else { md_eprintf(gettext( "%s is not a mirror or stripe\n"), rootnp->cname); md_exit(sp, 1); } } else { /* * Check that the root device is a component of the * current root filesystem only if the default system * files are being modified */ if ((ckmv_flag == 0) && (root_path == NULL)) { if (validate_root_device(sp, rootnp, ep) != 0) { md_exit(sp, 1); } } } } if (meta_lock(sp, TRUE, ep)) { mde_perror(ep, ""); md_exit(sp, 1); } /* * If -R is specified, use the default system file names relative * to the new root location. */ if (root_path != NULL) { root_path_size = strlen(root_path); for (i = 0, map = default_names; i < sizeof (default_names) / sizeof (struct def_map); i++, map++) { /* Add 1 for null terminator */ path_buf_size = root_path_size + strlen(map->dm_default) + 1; *map->dm_fname = malloc(path_buf_size); if (*map->dm_fname == NULL) { md_eprintf(gettext("Cannot allocate memory \ for system file path relocation\n")); md_exit(sp, 1); } (void) snprintf(*map->dm_fname, path_buf_size, "%s%s", root_path, map->dm_default); } } /* patch system and vfstab for root and mddb locations */ if (meta_patch_rootdev(rootnp, sname, vname, cname, dbname, doit, verbose, ep) != 0) { if (root_path != NULL) { free_mem(); } mde_perror(ep, ""); md_exit(sp, 1); } if (root_path != NULL) { free_mem(); } /* return success */ md_exit(sp, 0); /*NOTREACHED*/ return (0); }