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