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