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 (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#pragma ident	"%Z%%M%	%I%	%E% SMI"
27
28/*
29 * initialize metadevices
30 */
31
32#include <meta.h>
33
34#include <sdssc.h>
35#include <sys/lvm/md_mirror.h>
36#include <syslog.h>
37#include "meta_set_prv.h"
38
39/*
40 * try to initialize devices
41 */
42#define	DO_AGAIN	0
43#define	DONT_DO		1
44#define	IS_DONE		2
45
46/*
47 * mn_send_command
48 *
49 * generate a command of the form "metainit -s setname [-n] [-f] ....."
50 *
51 * If -n option is *not* set, send the metainit command *with -n set* to
52 * all nodes first. Do this with MD_MSGF_STOP_ON_ERROR set.
53 * That means if it fails on one node, it'll return immediately,
54 * reporting the error.
55 * By doing so, we have a dryrun first that has to succeed on every node
56 * before we start the command for real.
57 * This saves us from backing out a metainit command that succeeded on
58 * some nodes but failed on one.
59 */
60static int
61mn_send_command(
62	mdsetname_t	**spp,
63	int		argc,
64	char		**argv,
65	mdcmdopts_t	options,
66	int		flags,
67	char		*context,
68	md_error_t	*ep
69)
70{
71	int		newargc;
72	char		**newargv;
73	int		i;
74	int		ret;
75	int		dryrun_only = 0;
76
77
78	newargv = calloc(argc+5, sizeof (char *));
79	newargv[0] = "metainit";
80	newargv[1] = "-s";
81	newargv[2] = (*spp)->setname;
82	newargv[3] = "-n"; /* always do "-n" first */
83	newargc = 4;
84	if ((options & MDCMD_DOIT) == 0) {
85		dryrun_only = 1;
86	}
87	if ((options & MDCMD_FORCE) != 0) {
88		newargv[newargc] = "-f";
89		newargc++;
90	}
91	for (i = 0; i < argc; i++, newargc++)
92		newargv[newargc] = argv[i];
93	ret = meta_mn_send_command(*spp, newargc, newargv,
94	    flags | MD_DRYRUN | MD_NOLOG, context, ep);
95
96	if ((dryrun_only == 0) && (ret == 0)) {
97		/*
98		 * Do it for real now. Remove "-n" from the arguments and
99		 * MD_DRYRUN from the flags. If we fail this time the master
100		 * must panic as the mddbs may be inconsistent.
101		 */
102		newargv[3] = ""; /* this was "-n" before */
103		ret = meta_mn_send_command(*spp, newargc, newargv,
104		    flags | MD_RETRY_BUSY | MD_PANIC_WHEN_INCONSISTENT,
105		    context,  ep);
106	}
107
108	free(newargv);
109	return (ret);
110}
111
112static int
113init_entries(
114	mdsetname_t	**spp,
115	md_tab_t	*tabp,
116	mdcmdopts_t	options,
117	uint_t		flags,
118	bool_t		called_thru_rpc,
119	md_error_t	*ep
120)
121{
122	uint_t		cnt = 0;
123	uint_t		line;
124	int		rval = 0;
125	int		ret;
126
127	/* for all matching entries, which haven't already been done */
128	for (line = 0; (line < tabp->nlines); ++line) {
129		md_tab_line_t	*linep = &tabp->lines[line];
130		char		*uname = linep->argv[0];
131
132		/* see if already done */
133		if (linep->flags != DO_AGAIN)
134			continue;
135
136		/* clear the metadev/hsp caches between inits */
137		metaflushmetanames();
138
139		/* try it */
140		if ((called_thru_rpc == FALSE) &&
141		    meta_is_mn_name(spp, uname, ep)) {
142			/*
143			 * MN set, send command to all nodes
144			 * Note that is sp is NULL, meta_is_mn_name() derives
145			 * sp from linep->argv which is the metadevice arg
146			 */
147			ret = mn_send_command(spp, linep->argc, linep->argv,
148			    options, flags, linep->context, ep);
149		} else {
150			char		*cname = NULL;
151
152			cname = meta_name_getname(spp, uname, META_DEVICE, ep);
153			if (cname == NULL) {
154				mde_perror(ep, "");
155				mdclrerror(ep);
156			} else {
157
158				ret = meta_init_name(spp, linep->argc,
159				    linep->argv, cname, options, ep);
160				Free(cname);
161
162				if (ret != 0) {
163					if (!(flags & MD_IGNORE_STDERR)) {
164					    mderrorextra(ep, linep->context);
165					    mde_perror(ep, "");
166					    rval = -1;
167					}
168					mdclrerror(ep);
169				}
170			}
171		}
172		if (ret == 0) {
173			linep->flags = IS_DONE;
174			++cnt;
175		}
176	}
177
178	/* return success */
179	if (rval != 0)
180		return (rval);
181	return (cnt);
182}
183
184/*
185 * initialize all devices in set
186 */
187static int
188init_all(
189	mdsetname_t	**spp,
190	mdcmdopts_t	options,
191	bool_t		called_thru_rpc,
192	md_error_t	*ep
193)
194{
195	md_tab_t	*tabp = NULL;
196	size_t		setlen;
197	uint_t		more;
198	int		done;
199	int		eval = -1;
200
201	/*
202	 * Only take the lock if this is not a MN set
203	 * We can only enter this code for a MN set if we are the initiator
204	 * and in this case, we don't want to take locks.
205	 */
206	if (meta_is_mn_set((*spp), ep) == 0) {
207		/* grab set lock */
208		if (meta_lock(*spp, TRUE, ep)) {
209			mde_perror(ep, "");
210			mdclrerror(ep);
211			return (eval);
212		}
213
214		/* check for ownership */
215		if (meta_check_ownership(*spp, ep) != 0) {
216			mde_perror(ep, "");
217			mdclrerror(ep);
218			return (eval);
219		}
220
221		/* lock is held across init_entries */
222		options |= MDCMD_NOLOCK;
223	}
224
225	/* get md.tab, preen entries */
226	if ((tabp = meta_tab_parse(NULL, ep)) == NULL) {
227		mde_perror(ep, "");
228		mdclrerror(ep);
229		return (eval);
230	}
231
232	setlen = strlen((*spp)->setname);
233	for (more = 0; (more < tabp->nlines); ++more) {
234		md_tab_line_t	*linep = &tabp->lines[more];
235		char		*cname = linep->cname;
236		char		*p;
237		size_t		len;
238
239		/* better have args */
240		assert((linep->argc > 0) && (linep->argv[0] != NULL));
241
242		/* only do metadevices and hotspare pools in set */
243		if (linep->type & TAB_MD_HSP) {
244			if ((p = strrchr(cname, '/')) == NULL) {
245				len = 0;
246			} else {
247				len = p - cname;
248			}
249			if ((len == setlen) &&
250			    (strncmp(cname, (*spp)->setname, len) == 0)) {
251				linep->flags = DO_AGAIN;
252			} else {
253				linep->flags = DONT_DO;
254			}
255
256		} else {
257			linep->flags = DONT_DO;
258		}
259	}
260
261	eval = 1;
262
263	/* while more devices get made */
264	do {
265		done = init_entries(spp, tabp, options,
266		    MD_IGNORE_STDERR|MD_RETRY_BUSY, called_thru_rpc, ep);
267	} while (done > 0);
268
269	/* now do it and report errors */
270	if (init_entries(spp, tabp, options, MD_RETRY_BUSY,
271	    called_thru_rpc, ep) >= 0)
272		eval = 0;	/* success */
273	mdclrerror(ep);
274
275	/* cleanup, return success */
276out:
277	meta_tab_free(tabp);
278	return (eval);
279}
280
281/*
282 * initialize named device or hotspare pool
283 */
284static int
285init_name(
286	mdsetname_t	**spp,
287	int		argc,
288	char		*argv[],
289	mdcmdopts_t	options,
290	int		called_thru_rpc,
291	md_error_t	*ep
292)
293{
294	md_tab_t	*tabp = NULL;
295	md_tab_line_t	*linep = NULL;
296	int		rval = -1;
297	int		ret;
298	char		*uname = argv[0];
299
300	/* look in md.tab */
301	if (argc == 1) {
302		/* get md.tab entries */
303		if ((tabp = meta_tab_parse(NULL, ep)) == NULL) {
304			if (! mdissyserror(ep, ENOENT))
305				return (-1);
306		}
307
308		/* look in md.tab */
309		if ((linep = meta_tab_find(*spp, tabp, uname, TAB_MD_HSP))
310								!= NULL) {
311			argc = linep->argc;
312			argv = linep->argv;
313		}
314	}
315
316	if ((called_thru_rpc == FALSE) &&
317	    meta_is_mn_name(spp, uname, ep)) {
318		/*
319		 * MN set, send command to all nodes
320		 */
321		ret = mn_send_command(spp, argc, argv, options,
322		    MD_DISP_STDERR, NO_CONTEXT_STRING, ep);
323	} else {
324		char		*cname = NULL;
325
326		cname = meta_name_getname(spp, uname, META_DEVICE, ep);
327		if (cname == NULL) {
328			goto out;
329		}
330
331		/* check for ownership */
332		if (meta_check_ownership(*spp, ep) != 0) {
333			Free(cname);
334			goto out;
335		}
336
337		ret = meta_init_name(spp, argc, argv, cname, options, ep);
338		Free(cname);
339	}
340
341	if (ret != 0) {
342		if (linep != NULL)
343			mderrorextra(ep, linep->context);
344		goto out;
345	}
346	rval = 0;	/* success */
347
348	/* cleanup, return error */
349out:
350	if (tabp != NULL)
351		meta_tab_free(tabp);
352	return (rval);
353}
354
355/*
356 * print usage message
357 */
358static void
359usage(
360	mdsetname_t	*sp,
361	int		eval
362)
363{
364#ifndef	lint
365	(void) fprintf(stderr, gettext("\
366usage:	%s [-s setname] [-n] [-f] concat/stripe numstripes\n\
367		width component... [-i interlace]\n\
368		[width component... [-i interlace]] [-h hotspare_pool]\n\
369	%s [-s setname] [-n] [-f] mirror -m submirror...\n\
370		[read_options] [write_options] [pass_num]\n\
371	%s [-s setname] [-n] [-f] RAID -r component...\n\
372		[-i interlace] [-h hotspare_pool]\n\
373		[-k] [-o original_column_count]\n\
374	%s [-s setname] [-n] [-f] hotspare_pool [hotspare...]\n\
375	%s [-s setname] [-n] [-f] softpart -p [-A alignment]\n\
376		[-e] device size|all\n\
377	%s [-s setname] [-n] [-f] md.tab_entry\n\
378	%s [-s setname] [-n] [-f] -a\n\
379	%s -r\n"), myname, myname, myname, myname, myname, myname, myname,
380	    myname);
381#endif	/* ! lint */
382	md_exit(sp, eval);
383}
384
385/*
386 * If we fail during the attempt to take the auto-take disksets
387 * we need to tell the kernel to cleanup the in-core set struct
388 * so that we have a chance to take the set again later.
389 */
390static void
391auto_take_cleanup(mdsetname_t *sp, side_t sideno)
392{
393	mddb_config_t   c;
394
395	(void) memset(&c, 0, sizeof (c));
396	c.c_setno = sp->setno;
397	c.c_sideno = sideno;
398
399	if (metaioctl(MD_RELEASE_SET, &c, &c.c_mde, NULL) != 0) {
400		mde_perror(&c.c_mde, "auto_take_cleanup");
401		return;
402	}
403}
404
405/*
406 * Take the diskset.
407 *
408 * This is a clean auto-take set, so do the work to take it.
409 * This is a streamlined version of the code in meta_set_take.  We avoid the
410 * need for talking to the rpc.metad since that can't run this early during the
411 * boot.  We don't need to talk to the metad for this diskset since we're the
412 * only host in the set.
413 */
414static void
415take_set(md_set_record *sr)
416{
417	mdsetname_t		sn;
418	md_drive_desc		*dd;
419	md_error_t		error = mdnullerror;
420	md_replicalist_t	*rlp = NULL;
421	md_replicalist_t	*rl;
422	daddr_t			nblks = 0;
423	md_drive_record		*dr;
424	side_t			sideno;
425
426	/*
427	 * Several of the functions we call take a sp param so
428	 * construct one from the set record.
429	 */
430	sn.setname = sr->sr_setname;
431	sn.setno = sr->sr_setno;
432	sn.setdesc = sr2setdesc(sr);
433	sn.lockfd = MD_NO_LOCK;
434
435	if (sr->sr_flags & MD_SR_MB_DEVID)
436		dd = metaget_drivedesc(&sn, MD_BASICNAME_OK | PRINT_FAST,
437		    &error);
438	else
439		dd = metaget_drivedesc(&sn, MD_BASICNAME_OK, &error);
440
441	if (dd == NULL) {
442	    mde_perror(&error, "");
443	    mdclrerror(&error);
444	    return;
445	}
446
447	/*
448	 * Skip call to tk_own_bydd.  This talks to rpc.metamhd (which we can't
449	 * do yet) and is not needed for auto-take disksets since we are not
450	 * doing SCSI reservations on these drives.
451	 */
452
453	if (setup_db_bydd(&sn, dd, 0, &error) != 0) {
454	    if (! mdismddberror(&error, MDE_DB_ACCOK) &&
455		! mdismddberror(&error, MDE_DB_TAGDATA)) {
456		/*
457		 * Skip call to rel_own_bydd since that really just
458		 * calls rpc.metamhd which we don't need to do,
459		 * so there really isn't anything to rollback here.
460		 */
461		mde_perror(&error, "");
462		mdclrerror(&error);
463		return;
464	    }
465	    mdclrerror(&error);
466	}
467
468	if ((sideno = getmyside(&sn, &error)) == MD_SIDEWILD) {
469	    mde_perror(&error, "");
470	    return;
471	}
472
473	if (snarf_set(&sn, FALSE, &error) != 0) {
474	    if (mdismddberror(&error, MDE_DB_STALE) ||
475		mdismddberror(&error, MDE_DB_TAGDATA) ||
476		! mdismddberror(&error, MDE_DB_NODB) &&
477		! mdismddberror(&error, MDE_DB_NOTOWNER)) {
478		/*
479		 * rollback
480		 * Normally MDE_DB_STALE or MDE_DB_TAGDATA
481		 * would still keep the set but in this case we don't
482		 * want to do that.  This will probably result in the
483		 * boot going in to single-user since we won't have the
484		 * set so any attempted mounts using the set's metadevices
485		 * will fail.  However, that is a "good thing" so the
486		 * sysadmin can fix the set.  Normally they would see
487		 * all of these problems when they ran the take and be
488		 * able to immediately fix the problem.
489		 */
490		mde_perror(&error, "");
491		auto_take_cleanup(&sn, sideno);
492		return;
493	    }
494	}
495
496	/*
497	 * Call metareplicalist and upd_dr_dbinfo.
498	 * Most of that code is only needed to synchronize amongst the multiple
499	 * hosts in a set, which is not applicable in our case.  But we do a
500	 * subset here to handle the case when the user had been
501	 * adding/deleting/balancing mddbs when this node panic'd.  We are
502	 * synchronizing the ondisk mddbs to the list of drive records stored
503	 * in the local mddb.
504	 */
505	if (metareplicalist(&sn, (MD_BASICNAME_OK | PRINT_FAST), &rlp, &error)
506	    < 0) {
507	    /* rollback */
508	    mde_perror(&error, "");
509	    auto_take_cleanup(&sn, sideno);
510	    return;
511	}
512
513	/*
514	 * The following code is equivalent to upd_dr_dbinfo for syncronizing
515	 * the local host only.  That function is normally run through the
516	 * metad with a local and daemon side but we'll do all of the work
517	 * here.
518	 */
519
520	/* find the smallest existing replica */
521	for (rl = rlp; rl != NULL; rl = rl->rl_next) {
522	    md_replica_t *r;
523
524	    r = rl->rl_repp;
525	    nblks = ((nblks == 0) ? r->r_nblk : min(r->r_nblk, nblks));
526	}
527
528	if (nblks <= 0)
529	    nblks = MD_DBSIZE;
530
531	for (dr = sr->sr_drivechain; dr; dr = dr->dr_next) {
532	    int			dbcnt;
533	    mddrivename_t	*dnp;
534	    md_replicalist_t	*rl;
535
536		/*
537		 * The cname style for dnp and replica list will be same since
538		 * both use the the same flags MD_BASICNAME_OK|PRINT_FAST which
539		 * will always provide the cached value.
540		 */
541	    if ((dnp = metadrivename_withdrkey(&sn, sideno, dr->dr_key,
542		MD_BASICNAME_OK | PRINT_FAST, &error)) == NULL) {
543		mde_perror(&error, "");
544		metafreereplicalist(rlp);
545		auto_take_cleanup(&sn, sideno);
546		return;
547	    }
548
549	    dbcnt = 0;
550	    /* see how many replicas are on this drive */
551	    for (rl = rlp; rl != NULL; rl = rl->rl_next) {
552		if (strcmp(rl->rl_repp->r_namep->drivenamep->cname, dnp->cname)
553		    == 0)
554		    dbcnt++;
555	    }
556
557	    /* Adjust the fields in the copy */
558	    dr->dr_dbcnt = dbcnt;
559	    dr->dr_dbsize = dbcnt > 0 ? nblks : 0;
560	}
561
562	/*
563	 * If the set doesn't have the MD_SR_MB_DEVID bit set, i.e
564	 * the drives in the set don't have the device id information,
565	 * then stick it in if possible.
566	 *
567	 * If updating the master block fails for whatever reason, it's
568	 * okay. It just means the disk(s) in the diskset won't be self
569	 * identifying.
570	 */
571	if (!(sr->sr_flags & MD_SR_MB_DEVID)) {
572		if (meta_update_mb(&sn, dd, &error) == 0) {
573			sr->sr_flags |= MD_SR_MB_DEVID;
574			mdclrerror(&error);
575		}
576	}
577
578	commitset(sr, FALSE, &error);
579
580	metafreereplicalist(rlp);
581
582	/*
583	 * This finishes up the logical equivalent of meta_set_take.
584	 */
585	if (meta_resync_all(&sn, MD_DEF_RESYNC_BUF_SIZE, &error) != 0) {
586	    mde_perror(&error, "");
587	    mdclrerror(&error);
588	}
589}
590
591/*
592 * Take the disksets that are marked to be taken at boot time.
593 */
594static void
595auto_take_sets()
596{
597	int		max_sets;
598	int		i;
599	md_error_t	error = mdnullerror;
600	char		*hostname;
601
602	if ((max_sets = get_max_sets(&error)) == 0)
603	    return;
604
605	if (!mdisok(&error)) {
606	    mde_perror(&error, "");
607	    return;
608	}
609
610	/* set up so auto-take errors also go to syslog */
611	openlog("metainit", LOG_ODELAY, LOG_USER);
612	metasyslog = 1;
613
614	hostname = mynode();
615
616	/*
617	 * For each possible set number (skip set 0 which is the unnamed local
618	 * set), see if we really have a diskset.  If so, check if auto-take
619	 * is enabled.
620	 *
621	 * In order to take the set it must have drives and it must not be
622	 * stuck in mid-add.  The sr_validate routine within rpc.metad will
623	 * delete sets that are in mid-add when it runs.
624	 */
625	for (i = 1; i < max_sets; i++) {
626	    md_set_record	*sr;
627
628	    if ((sr = metad_getsetbynum(i, &error)) == NULL) {
629		mdclrerror(&error);
630		continue;
631	    }
632
633	    if (sr->sr_flags & MD_SR_AUTO_TAKE && !(sr->sr_flags & MD_SR_ADD)) {
634		int	j;
635		int	cnt = 0;
636		int	host_mismatch = 0;
637		int	take = 0;
638		md_drive_record	*dr;
639
640		/* check for host renames or multiple hosts in set */
641		for (j = 0; j < MD_MAXSIDES; j++) {
642		    /* Skip empty slots */
643		    if (sr->sr_nodes[j][0] == '\0')
644			continue;
645
646		    cnt++;
647		    if (strcmp(sr->sr_nodes[j], hostname) != 0)
648			host_mismatch = 1;
649		}
650
651		/* paranoid check that we're the only host in the set */
652		if (cnt > 1) {
653			md_eprintf(gettext(
654		"diskset %s: auto-take enabled and multiple hosts in set\n"),
655			    sr->sr_setname);
656			continue;
657		}
658
659		if (host_mismatch) {
660			/* The host was renamed, repair the set. */
661			for (j = 0; j < MD_MAXSIDES; j++) {
662				/* Skip empty slots */
663				if (sr->sr_nodes[j][0] == '\0')
664					continue;
665
666				(void) strncpy(sr->sr_nodes[j], hostname,
667				    sizeof (sr->sr_nodes[j]));
668				commitset(sr, FALSE, &error);
669				if (!mdisok(&error)) {
670					mde_perror(&error, "");
671					mdclrerror(&error);
672				} else {
673					md_eprintf(gettext(
674			"new hostname %s, update auto-take diskset %s\n"),
675						hostname, sr->sr_setname);
676				}
677				break;
678			}
679		}
680
681		/* set must have at least one drive to be taken */
682		for (dr = sr->sr_drivechain; dr != NULL; dr = dr->dr_next) {
683			/* ignore drives in mid-add */
684			if (!(dr->dr_flags & MD_DR_ADD)) {
685			    take = 1;
686			    break;
687			}
688		}
689
690		if (take)
691			take_set(sr);
692		else
693			md_eprintf(gettext(
694		"diskset %s: auto-take enabled but set has no drives\n"),
695			    sr->sr_setname);
696	    }
697	}
698}
699
700/*
701 * mainline. crack command line arguments.
702 */
703int
704main(
705	int		argc,
706	char		*argv[]
707)
708{
709	char		*sname = MD_LOCAL_NAME;
710	mdsetname_t	*sp = NULL;
711	enum action {
712		NONE,
713		INIT,
714		ALL
715	}		todo = NONE;
716	mdcmdopts_t	options = (MDCMD_DOIT | MDCMD_PRINT);
717	int		c;
718	md_error_t	status = mdnullerror;
719	md_error_t	*ep = &status;
720
721	md_error_t	dummystatus = mdnullerror;
722	md_error_t	*dummyep = &dummystatus;
723	int		eval = 1;
724	int		error;
725	bool_t		called_thru_rpc = FALSE;
726	char		*cp;
727	pid_t		pid;
728
729	/*
730	 * Get the locale set up before calling any other routines
731	 * with messages to ouput.  Just in case we're not in a build
732	 * environment, make sure that TEXT_DOMAIN gets set to
733	 * something.
734	 */
735#if !defined(TEXT_DOMAIN)
736#define	TEXT_DOMAIN "SYS_TEST"
737#endif
738	(void) setlocale(LC_ALL, "");
739	(void) textdomain(TEXT_DOMAIN);
740	if ((cp = strstr(argv[0], ".rpc_call")) != NULL) {
741		*cp = '\0'; /* cut off ".rpc_call" */
742		called_thru_rpc = TRUE;
743	} else {
744		if (sdssc_bind_library() == SDSSC_OKAY)
745			if (sdssc_cmd_proxy(argc, argv, SDSSC_PROXY_PRIMARY,
746						&error) == SDSSC_PROXY_DONE)
747				exit(error);
748	}
749
750	/* initialize */
751	if (md_init(argc, argv, 0, 1, ep) != 0 ||
752			meta_check_root(ep) != 0) {
753		mde_perror(ep, "");
754		md_exit(sp, 1);
755	}
756
757	/* parse args */
758	optind = 1;
759	opterr = 1;
760	while ((c = getopt(argc, argv, "afhnrs:?")) != -1) {
761		switch (c) {
762
763		/* help */
764		case 'h':
765			usage(sp, 0);
766			break;
767
768		/* set name */
769		case 's':
770			sname = optarg;
771			break;
772
773		/* all devices in md.tab */
774		case 'a':
775			if (todo != NONE)
776				usage(sp, 1);
777			todo = ALL;
778			options |= MDCMD_ALLOPTION;
779			break;
780		/* check for validity, but don't really init */
781		case 'n':
782			options &= ~MDCMD_DOIT;
783			break;
784
785		/* for recovery */
786		case 'r':
787			if (todo != NONE)
788				usage(sp, 1);
789			todo = INIT;
790			break;
791
792		/* mounted and swapped components are OK */
793		case 'f':
794			options |= MDCMD_FORCE;
795			break;
796
797		case '?':
798			if (optopt == '?')
799				usage(sp, 0);
800			/*FALLTHROUGH*/
801		default:
802			usage(sp, 1);
803			break;
804		}
805	}
806
807	/* sname is MD_LOCAL_NAME if not specified on the command line */
808	if ((sp = metasetname(sname, ep)) == NULL) {
809		mde_perror(ep, "");
810		md_exit(sp, 1);
811	}
812
813	argc -= optind;
814	argv += optind;
815	if (todo == NONE) {
816		if (argc <= 0) {
817			usage(sp, 1);
818		}
819	} else if (argc > 0) {
820		usage(sp, 1);
821	}
822
823
824	/* setup database locations */
825	if (meta_setup_db_locations(ep) != 0) {
826		mde_perror(ep, "");
827		if (mdismddberror(ep, MDE_DB_STALE))
828			md_exit(sp, 66);
829		if (! mdiserror(ep, MDE_MDDB_CKSUM))	/* relatively benign */
830			md_exit(sp, 1);
831	}
832	if (todo == INIT) {		/* load and take auto-take sets */
833		auto_take_sets();
834
835		/*
836		 * During the boot sequence we need to update the mediator
837		 * records, however this depends upon the rpc.metamedd
838		 * running. So, in order to not introduce a delay in the
839		 * boot time, fork a new process to do this work in the
840		 * background.
841		 */
842		pid = fork1();
843		if (pid == (pid_t)-1) {
844			/*
845			 * We could not fork a child process to udpate mediator
846			 * information on this node. There is no need to panic.
847			 * We shall simply return 1.
848			 */
849			mde_perror(ep, "Could not fork a child process to"
850			    " update mediator record");
851			md_exit(sp, 1);
852		} else if (pid == (pid_t)0) {
853			/* child */
854			if (meta_mediator_info_from_file(NULL, 0, ep) == 1) {
855				/*
856				 * No need to print any error messages.
857				 * All the errors messages are printed in the
858				 * library routine itself.
859				 */
860				md_exit(sp, 1);
861			} else {
862				md_exit(sp, 0);
863			}
864		} else {
865			/* Parent process */
866			md_exit(sp, 0);
867		}
868	} else if (todo == ALL) {	/* initialize all devices in md.tab */
869		eval = init_all(&sp, options, called_thru_rpc, ep);
870	} else {			/* initialize the named device */
871		eval = 0;
872		if (init_name(&sp, argc, argv, options, called_thru_rpc,
873		    ep) != 0) {
874			/*
875			 * If we're dealing with MN metadevices and we are
876			 * directly called, then the appropriate error message
877			 * has already been displayed. So just exit.
878			 */
879			if (meta_is_mn_set(sp, dummyep) && (!called_thru_rpc)) {
880				md_exit(sp, 1);
881			}
882			mde_perror(ep, "");
883			mdclrerror(ep);
884			eval = 1;
885			goto nomdcf;
886		}
887	}
888
889domdcf:
890	/* update md.cf, return success */
891	if (meta_update_md_cf(sp, ep) != 0) {
892		mde_perror(ep, "");
893		eval = 1;
894	}
895
896nomdcf:
897	md_exit(sp, eval);
898	/*NOTREACHED*/
899	return (eval);
900}
901