/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (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 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MODEBITS (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO) #define ISREG(A) (((A).st_mode & S_IFMT) == S_IFREG) #define DEFAULT_ROOTDIR "/a" /* * FUNCTION: svm_start * starts SDS/SVM configuration. If root mirroring exists then the * components of the root mirror are returned in svmpp. * * INPUT: mntpnt - root mount point * svmpp - prealloced structure to return components * repl_state_flag - SVM_CONV/SVM_DONT_CONV * * RETURN: * 0 - SUCCESS * !0 - ERROR * if > 0 errno */ int svm_start(char *mntpnt, svm_info_t **svmpp, int repl_state_flag) { char *rootdir, *tf; char *mdevnamep = NULL; char system_file[PATH_MAX]; char mdconf[PATH_MAX]; int rval = 0; if (mntpnt == NULL) rootdir = DEFAULT_ROOTDIR; else rootdir = mntpnt; if ((rval = snprintf(system_file, PATH_MAX, "%s%s", rootdir, SYSTEM_FILE)) < 0) { return (RET_ERROR); } if ((rval = snprintf(mdconf, PATH_MAX, "%s%s", rootdir, MD_CONF)) < 0) { return (RET_ERROR); } debug_printf("svm_start(): repl_state_flag %s\n", (repl_state_flag == SVM_DONT_CONV) ? "SVM_DONT_CONV": "SVM_CONV"); if (copyfile(MD_CONF, MD_CONF_ORIG)) return (RET_ERROR); switch (rval = convert_bootlist(system_file, mdconf, &tf)) { case 0: case -1: /* found in etc/system flag */ break; default: /* convert bootlist failed */ debug_printf("svm_start(): convert_bootlist failed." "rval %d\n", rval); goto errout; } if (repl_state_flag == SVM_DONT_CONV) { rval = create_in_file_prop(PROP_KEEP_REPL_STATE, tf); if (rval != 0) goto errout; } if (is_upgrade_prop(PROP_DEVID_DESTROY)) { rval = create_in_file_prop(PROP_DEVID_DESTROY, tf); /* * For the idempotent behavior reset internal * flag incase we have to return due to errors */ set_upgrade_prop(PROP_DEVID_DESTROY, 0); if (rval != 0) goto errout; } /* * Since svm_start is called only after svm_check, * we can assume that there is a valid metadb. If the mddb_bootlist * is not found in etc/system, then it must be in md.conf which * we copied to temporary file pointed to by tf */ if (copyfile(tf, MD_CONF)) { debug_printf("svm_start(): copy of %s to %s failed\n", tf, MD_CONF); goto errout; } if ((rval = write_xlate_to_mdconf(rootdir)) != 0) { debug_printf("svm_start(): write_xlate_to_mdconf(%s) failed\n", rootdir); goto errout; } if ((rval = write_targ_nm_table(rootdir)) != 0) { goto errout; } /* run devfsadm to create the devices specified in md.conf */ if ((rval = system("/usr/sbin/devfsadm -r /tmp -p " "/tmp/root/etc/path_to_inst -i md")) != 0) { debug_printf("svm_start(): devfsadm -i md failed: %d\n", rval); goto errout; } /* * We have to unload md after the devfsadm run so that when metainit * loads things it gets the right information from md.conf. */ if (rval = svm_stop()) { debug_printf("svm_start(): svm_stop failed.\n"); return (RET_ERROR); } if ((rval = system("/usr/sbin/metainit -r")) != 0) { debug_printf("svm_start(): metainit -r failed: %d\n", rval); goto errout; } create_diskset_links(); if ((rval = system("/usr/sbin/metasync -r")) != 0) { debug_printf("svm_start(): metasync -r failed: %d\n", rval); goto errout; } /* * We ignore failures from metadevadm, since it can fail if * miniroot dev_t's don't match target dev_ts. But it still * will update md.conf with device Id information which is * why we are calling it here. */ (void) system("/usr/sbin/metadevadm -r"); /* * check to see if we have a root metadevice and if so * get its components. */ if ((rval = get_rootmetadevice(rootdir, &mdevnamep)) == 0) { if (rval = get_mdcomponents(mdevnamep, svmpp)) { debug_printf("svm_start(): get_mdcomponents(%s,..)" "failed %d\n", mdevnamep, rval); goto errout; } } else { rval = 0; /* not a mirrored root */ debug_printf("svm_start(): get_rootmetadevice(%s,..) " "No root mirrors! ", rootdir); } errout: free(mdevnamep); if (rval != 0) { struct stat sbuf; if (stat(MD_CONF_ORIG, &sbuf) == 0) (void) copyfile(MD_CONF_ORIG, MD_CONF); debug_printf("svm_start(): svm_start failed: %d\n", rval); } else { int i; if ((*svmpp)->count > 0) { debug_printf("svmpp: "); debug_printf(" root_md: %s", (*svmpp)->root_md); debug_printf(" count: %d", (*svmpp)->count); for (i = 0; i < (*svmpp)->count; i++) { debug_printf(" md_comps[%d]: %s", i, (*svmpp)->md_comps[i]); } debug_printf(" \n"); } else { if ((*svmpp)->count == 0) debug_printf("svm_start(): no mirrored root\n"); } debug_printf("svm_start(): svm_start succeeded.\n"); } return (rval); } /* * FUNCTION: copyfile * * INPUT: self descriptive * * RETURN: * RET_SUCCESS * RET_ERROR */ int copyfile(char *from, char *to) { int fromfd, tofd; char buf[1024]; ssize_t rbytes; struct stat fromstat; if ((fromfd = open(from, O_RDONLY | O_NDELAY)) < 0) return (RET_ERROR); if ((fstat(fromfd, &fromstat) < 0) || ! ISREG(fromstat)) { (void) close(fromfd); return (RET_ERROR); } if ((tofd = open(to, O_CREAT | O_WRONLY | O_TRUNC, (fromstat.st_mode & MODEBITS))) < 0) { (void) close(fromfd); return (RET_ERROR); } /* * in case the file exists then perm is forced by this chmod */ (void) fchmod(tofd, fromstat.st_mode & MODEBITS); for (;;) { rbytes = read(fromfd, buf, sizeof (buf)); /* * no need to check for negative values since the file * has been successfully stat'ed */ if (rbytes == 0) break; if (write(tofd, buf, rbytes) != rbytes) { rbytes = -1; break; } } (void) close(fromfd); (void) close(tofd); if (rbytes < 0) { (void) unlink(to); return (RET_ERROR); } return (RET_SUCCESS); }