1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <ctype.h>
30*0Sstevel@tonic-gate #include <malloc.h>
31*0Sstevel@tonic-gate #include <stdio.h>
32*0Sstevel@tonic-gate #include <fcntl.h>
33*0Sstevel@tonic-gate #include <stdlib.h>
34*0Sstevel@tonic-gate #include <errno.h>
35*0Sstevel@tonic-gate #include <string.h>
36*0Sstevel@tonic-gate #include <sys/types.h>
37*0Sstevel@tonic-gate #include <sys/stat.h>
38*0Sstevel@tonic-gate #include <sys/param.h>
39*0Sstevel@tonic-gate #include <limits.h>
40*0Sstevel@tonic-gate #include <meta.h>
41*0Sstevel@tonic-gate #include <svm.h>
42*0Sstevel@tonic-gate #include <libsvm.h>
43*0Sstevel@tonic-gate 
44*0Sstevel@tonic-gate #define	MODEBITS	(S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)
45*0Sstevel@tonic-gate #define	ISREG(A)	(((A).st_mode & S_IFMT) == S_IFREG)
46*0Sstevel@tonic-gate #define	DEFAULT_ROOTDIR "/a"
47*0Sstevel@tonic-gate 
48*0Sstevel@tonic-gate 
49*0Sstevel@tonic-gate /*
50*0Sstevel@tonic-gate  * FUNCTION: svm_start
51*0Sstevel@tonic-gate  *	starts SDS/SVM configuration. If root mirroring exists then the
52*0Sstevel@tonic-gate  *	components of the root mirror are returned in svmpp.
53*0Sstevel@tonic-gate  *
54*0Sstevel@tonic-gate  * INPUT: mntpnt - root mount point
55*0Sstevel@tonic-gate  *	  svmpp - prealloced structure to return components
56*0Sstevel@tonic-gate  *	  repl_state_flag - SVM_CONV/SVM_DONT_CONV
57*0Sstevel@tonic-gate  *
58*0Sstevel@tonic-gate  * RETURN:
59*0Sstevel@tonic-gate  *	  0 - SUCCESS
60*0Sstevel@tonic-gate  *	  !0 - ERROR
61*0Sstevel@tonic-gate  *	  if > 0 errno
62*0Sstevel@tonic-gate  */
63*0Sstevel@tonic-gate 
64*0Sstevel@tonic-gate int
65*0Sstevel@tonic-gate svm_start(char *mntpnt, svm_info_t **svmpp, int repl_state_flag)
66*0Sstevel@tonic-gate {
67*0Sstevel@tonic-gate 	char *rootdir, *tf;
68*0Sstevel@tonic-gate 	char *mdevnamep = NULL;
69*0Sstevel@tonic-gate 	char system_file[PATH_MAX];
70*0Sstevel@tonic-gate 	char mdconf[PATH_MAX];
71*0Sstevel@tonic-gate 	int rval = 0;
72*0Sstevel@tonic-gate 
73*0Sstevel@tonic-gate 	if (mntpnt == NULL)
74*0Sstevel@tonic-gate 		rootdir = DEFAULT_ROOTDIR;
75*0Sstevel@tonic-gate 	else
76*0Sstevel@tonic-gate 		rootdir = mntpnt;
77*0Sstevel@tonic-gate 
78*0Sstevel@tonic-gate 	if ((rval = snprintf(system_file, PATH_MAX, "%s%s",
79*0Sstevel@tonic-gate 					rootdir, SYSTEM_FILE)) < 0) {
80*0Sstevel@tonic-gate 		return (RET_ERROR);
81*0Sstevel@tonic-gate 	}
82*0Sstevel@tonic-gate 
83*0Sstevel@tonic-gate 	if ((rval = snprintf(mdconf, PATH_MAX, "%s%s",
84*0Sstevel@tonic-gate 					rootdir, MD_CONF)) < 0) {
85*0Sstevel@tonic-gate 		return (RET_ERROR);
86*0Sstevel@tonic-gate 	}
87*0Sstevel@tonic-gate 
88*0Sstevel@tonic-gate 	debug_printf("svm_start(): repl_state_flag %s\n",
89*0Sstevel@tonic-gate 		(repl_state_flag == SVM_DONT_CONV) ? "SVM_DONT_CONV":
90*0Sstevel@tonic-gate 						"SVM_CONV");
91*0Sstevel@tonic-gate 
92*0Sstevel@tonic-gate 	if (copyfile(MD_CONF, MD_CONF_ORIG))
93*0Sstevel@tonic-gate 		return (RET_ERROR);
94*0Sstevel@tonic-gate 
95*0Sstevel@tonic-gate 	switch (rval = convert_bootlist(system_file, mdconf, &tf)) {
96*0Sstevel@tonic-gate 		case 0:
97*0Sstevel@tonic-gate 		case -1:			/* found in etc/system flag */
98*0Sstevel@tonic-gate 			break;
99*0Sstevel@tonic-gate 		default: /* convert bootlist failed */
100*0Sstevel@tonic-gate 			debug_printf("svm_start(): convert_bootlist failed."
101*0Sstevel@tonic-gate 					"rval %d\n", rval);
102*0Sstevel@tonic-gate 			goto errout;
103*0Sstevel@tonic-gate 	}
104*0Sstevel@tonic-gate 
105*0Sstevel@tonic-gate 	if (repl_state_flag == SVM_DONT_CONV) {
106*0Sstevel@tonic-gate 		rval = create_in_file_prop(PROP_KEEP_REPL_STATE, tf);
107*0Sstevel@tonic-gate 		if (rval != 0)
108*0Sstevel@tonic-gate 			goto errout;
109*0Sstevel@tonic-gate 	}
110*0Sstevel@tonic-gate 
111*0Sstevel@tonic-gate 	if (is_upgrade_prop(PROP_DEVID_DESTROY)) {
112*0Sstevel@tonic-gate 		rval = create_in_file_prop(PROP_DEVID_DESTROY, tf);
113*0Sstevel@tonic-gate 		/*
114*0Sstevel@tonic-gate 		 * For the idempotent behavior reset internal
115*0Sstevel@tonic-gate 		 * flag incase we have to return due to errors
116*0Sstevel@tonic-gate 		 */
117*0Sstevel@tonic-gate 		set_upgrade_prop(PROP_DEVID_DESTROY, 0);
118*0Sstevel@tonic-gate 		if (rval != 0)
119*0Sstevel@tonic-gate 			goto errout;
120*0Sstevel@tonic-gate 	}
121*0Sstevel@tonic-gate 
122*0Sstevel@tonic-gate 
123*0Sstevel@tonic-gate 	/*
124*0Sstevel@tonic-gate 	 * Since svm_start is called only after svm_check,
125*0Sstevel@tonic-gate 	 * we can assume that there is a valid metadb. If the mddb_bootlist
126*0Sstevel@tonic-gate 	 * is not found in etc/system, then it must be in md.conf which
127*0Sstevel@tonic-gate 	 * we copied to temporary file pointed to by tf
128*0Sstevel@tonic-gate 	 */
129*0Sstevel@tonic-gate 	if (copyfile(tf, MD_CONF)) {
130*0Sstevel@tonic-gate 		debug_printf("svm_start(): copy of %s to %s failed\n", tf,
131*0Sstevel@tonic-gate 			MD_CONF);
132*0Sstevel@tonic-gate 		goto errout;
133*0Sstevel@tonic-gate 	}
134*0Sstevel@tonic-gate 
135*0Sstevel@tonic-gate 	if ((rval = write_xlate_to_mdconf(rootdir)) != 0) {
136*0Sstevel@tonic-gate 		debug_printf("svm_start(): write_xlate_to_mdconf(%s) failed\n",
137*0Sstevel@tonic-gate 				rootdir);
138*0Sstevel@tonic-gate 		goto errout;
139*0Sstevel@tonic-gate 	}
140*0Sstevel@tonic-gate 
141*0Sstevel@tonic-gate 	if ((rval = write_targ_nm_table(rootdir)) != 0) {
142*0Sstevel@tonic-gate 		goto errout;
143*0Sstevel@tonic-gate 	}
144*0Sstevel@tonic-gate 
145*0Sstevel@tonic-gate 	/* run devfsadm to create the devices specified in md.conf */
146*0Sstevel@tonic-gate 	if ((rval = system("/usr/sbin/devfsadm -r /tmp -p "
147*0Sstevel@tonic-gate 		"/tmp/root/etc/path_to_inst -i md")) != 0) {
148*0Sstevel@tonic-gate 		debug_printf("svm_start(): devfsadm -i md failed: %d\n", rval);
149*0Sstevel@tonic-gate 		goto errout;
150*0Sstevel@tonic-gate 	}
151*0Sstevel@tonic-gate 
152*0Sstevel@tonic-gate 	/*
153*0Sstevel@tonic-gate 	 * We have to unload md after the devfsadm run so that when metainit
154*0Sstevel@tonic-gate 	 * loads things it gets the right information from md.conf.
155*0Sstevel@tonic-gate 	 */
156*0Sstevel@tonic-gate 	if (rval = svm_stop()) {
157*0Sstevel@tonic-gate 		debug_printf("svm_start(): svm_stop failed.\n");
158*0Sstevel@tonic-gate 		return (RET_ERROR);
159*0Sstevel@tonic-gate 	}
160*0Sstevel@tonic-gate 
161*0Sstevel@tonic-gate 	if ((rval = system("/usr/sbin/metainit -r")) != 0) {
162*0Sstevel@tonic-gate 		debug_printf("svm_start(): metainit -r failed: %d\n", rval);
163*0Sstevel@tonic-gate 		goto errout;
164*0Sstevel@tonic-gate 	}
165*0Sstevel@tonic-gate 
166*0Sstevel@tonic-gate 	create_diskset_links();
167*0Sstevel@tonic-gate 
168*0Sstevel@tonic-gate 	if ((rval = system("/usr/sbin/metasync -r")) != 0) {
169*0Sstevel@tonic-gate 		debug_printf("svm_start(): metasync -r failed: %d\n", rval);
170*0Sstevel@tonic-gate 		goto errout;
171*0Sstevel@tonic-gate 	}
172*0Sstevel@tonic-gate 
173*0Sstevel@tonic-gate 	/*
174*0Sstevel@tonic-gate 	 * We ignore failures from metadevadm, since it can fail if
175*0Sstevel@tonic-gate 	 * miniroot dev_t's don't match target dev_ts. But it still
176*0Sstevel@tonic-gate 	 * will update md.conf with device Id information which is
177*0Sstevel@tonic-gate 	 * why we are calling it here.
178*0Sstevel@tonic-gate 	 */
179*0Sstevel@tonic-gate 
180*0Sstevel@tonic-gate 	(void) system("/usr/sbin/metadevadm -r");
181*0Sstevel@tonic-gate 
182*0Sstevel@tonic-gate 	/*
183*0Sstevel@tonic-gate 	 * check to see if we have a root metadevice and if so
184*0Sstevel@tonic-gate 	 *  get its components.
185*0Sstevel@tonic-gate 	 */
186*0Sstevel@tonic-gate 
187*0Sstevel@tonic-gate 	if ((rval = get_rootmetadevice(rootdir, &mdevnamep)) == 0) {
188*0Sstevel@tonic-gate 		if (rval = get_mdcomponents(mdevnamep, svmpp)) {
189*0Sstevel@tonic-gate 			debug_printf("svm_start(): get_mdcomponents(%s,..)"
190*0Sstevel@tonic-gate 				"failed %d\n", mdevnamep, rval);
191*0Sstevel@tonic-gate 			goto errout;
192*0Sstevel@tonic-gate 		}
193*0Sstevel@tonic-gate 
194*0Sstevel@tonic-gate 	} else {
195*0Sstevel@tonic-gate 		rval = 0; /* not a mirrored root */
196*0Sstevel@tonic-gate 		debug_printf("svm_start(): get_rootmetadevice(%s,..) "
197*0Sstevel@tonic-gate 			"No root mirrors! ", rootdir);
198*0Sstevel@tonic-gate 	}
199*0Sstevel@tonic-gate errout:
200*0Sstevel@tonic-gate 	free(mdevnamep);
201*0Sstevel@tonic-gate 	if (rval != 0) {
202*0Sstevel@tonic-gate 		struct stat sbuf;
203*0Sstevel@tonic-gate 		if (stat(MD_CONF_ORIG, &sbuf) == 0)
204*0Sstevel@tonic-gate 			(void) copyfile(MD_CONF_ORIG, MD_CONF);
205*0Sstevel@tonic-gate 		debug_printf("svm_start(): svm_start failed: %d\n", rval);
206*0Sstevel@tonic-gate 	} else {
207*0Sstevel@tonic-gate 		int i;
208*0Sstevel@tonic-gate 
209*0Sstevel@tonic-gate 		if ((*svmpp)->count > 0) {
210*0Sstevel@tonic-gate 			debug_printf("svmpp: ");
211*0Sstevel@tonic-gate 			debug_printf("    root_md: %s", (*svmpp)->root_md);
212*0Sstevel@tonic-gate 			debug_printf("    count: %d", (*svmpp)->count);
213*0Sstevel@tonic-gate 			for (i = 0; i < (*svmpp)->count; i++) {
214*0Sstevel@tonic-gate 				debug_printf("    md_comps[%d]: %s", i,
215*0Sstevel@tonic-gate 				(*svmpp)->md_comps[i]);
216*0Sstevel@tonic-gate 			}
217*0Sstevel@tonic-gate 			debug_printf(" \n");
218*0Sstevel@tonic-gate 		} else {
219*0Sstevel@tonic-gate 			if ((*svmpp)->count == 0)
220*0Sstevel@tonic-gate 				debug_printf("svm_start(): no mirrored root\n");
221*0Sstevel@tonic-gate 		}
222*0Sstevel@tonic-gate 		debug_printf("svm_start(): svm_start succeeded.\n");
223*0Sstevel@tonic-gate 	}
224*0Sstevel@tonic-gate 	return (rval);
225*0Sstevel@tonic-gate }
226*0Sstevel@tonic-gate 
227*0Sstevel@tonic-gate /*
228*0Sstevel@tonic-gate  * FUNCTION: copyfile
229*0Sstevel@tonic-gate  *
230*0Sstevel@tonic-gate  * INPUT: self descriptive
231*0Sstevel@tonic-gate  *
232*0Sstevel@tonic-gate  * RETURN:
233*0Sstevel@tonic-gate  *	RET_SUCCESS
234*0Sstevel@tonic-gate  *	RET_ERROR
235*0Sstevel@tonic-gate  */
236*0Sstevel@tonic-gate int
237*0Sstevel@tonic-gate copyfile(char *from, char *to)
238*0Sstevel@tonic-gate {
239*0Sstevel@tonic-gate 	int fromfd, tofd;
240*0Sstevel@tonic-gate 	char buf[1024];
241*0Sstevel@tonic-gate 	ssize_t	rbytes;
242*0Sstevel@tonic-gate 	struct stat fromstat;
243*0Sstevel@tonic-gate 
244*0Sstevel@tonic-gate 	if ((fromfd = open(from, O_RDONLY | O_NDELAY)) < 0)
245*0Sstevel@tonic-gate 		return (RET_ERROR);
246*0Sstevel@tonic-gate 
247*0Sstevel@tonic-gate 	if ((fstat(fromfd, &fromstat) < 0) || ! ISREG(fromstat)) {
248*0Sstevel@tonic-gate 		(void) close(fromfd);
249*0Sstevel@tonic-gate 		return (RET_ERROR);
250*0Sstevel@tonic-gate 	}
251*0Sstevel@tonic-gate 
252*0Sstevel@tonic-gate 	if ((tofd = open(to, O_CREAT | O_WRONLY | O_TRUNC,
253*0Sstevel@tonic-gate 		(fromstat.st_mode & MODEBITS))) < 0) {
254*0Sstevel@tonic-gate 		(void) close(fromfd);
255*0Sstevel@tonic-gate 		return (RET_ERROR);
256*0Sstevel@tonic-gate 	}
257*0Sstevel@tonic-gate 
258*0Sstevel@tonic-gate 	/*
259*0Sstevel@tonic-gate 	 * in case the file exists then perm is forced by this chmod
260*0Sstevel@tonic-gate 	 */
261*0Sstevel@tonic-gate 	(void) fchmod(tofd, fromstat.st_mode & MODEBITS);
262*0Sstevel@tonic-gate 
263*0Sstevel@tonic-gate 	for (;;) {
264*0Sstevel@tonic-gate 		rbytes = read(fromfd, buf, sizeof (buf));
265*0Sstevel@tonic-gate 		/*
266*0Sstevel@tonic-gate 		 * no need to check for negative values since the file
267*0Sstevel@tonic-gate 		 * has been successfully stat'ed
268*0Sstevel@tonic-gate 		 */
269*0Sstevel@tonic-gate 		if (rbytes == 0)
270*0Sstevel@tonic-gate 			break;
271*0Sstevel@tonic-gate 		if (write(tofd, buf, rbytes) != rbytes) {
272*0Sstevel@tonic-gate 				rbytes = -1;
273*0Sstevel@tonic-gate 				break;
274*0Sstevel@tonic-gate 		}
275*0Sstevel@tonic-gate 	}
276*0Sstevel@tonic-gate 
277*0Sstevel@tonic-gate 	(void) close(fromfd);
278*0Sstevel@tonic-gate 	(void) close(tofd);
279*0Sstevel@tonic-gate 	if (rbytes < 0) {
280*0Sstevel@tonic-gate 		(void) unlink(to);
281*0Sstevel@tonic-gate 		return (RET_ERROR);
282*0Sstevel@tonic-gate 	}
283*0Sstevel@tonic-gate 	return (RET_SUCCESS);
284*0Sstevel@tonic-gate }
285