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 2004 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 /*
30*0Sstevel@tonic-gate  * Just in case we're not in a build environment, make sure that
31*0Sstevel@tonic-gate  * TEXT_DOMAIN gets set to something.
32*0Sstevel@tonic-gate  */
33*0Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
34*0Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
35*0Sstevel@tonic-gate #endif
36*0Sstevel@tonic-gate 
37*0Sstevel@tonic-gate /*
38*0Sstevel@tonic-gate  * trans operations
39*0Sstevel@tonic-gate  */
40*0Sstevel@tonic-gate 
41*0Sstevel@tonic-gate #include <meta.h>
42*0Sstevel@tonic-gate #include <meta_basic.h>
43*0Sstevel@tonic-gate #include <sys/lvm/md_trans.h>
44*0Sstevel@tonic-gate #include <sys/wait.h>
45*0Sstevel@tonic-gate #include <sys/mnttab.h>
46*0Sstevel@tonic-gate #include <stddef.h>
47*0Sstevel@tonic-gate 
48*0Sstevel@tonic-gate extern char *getfullblkname();
49*0Sstevel@tonic-gate 
50*0Sstevel@tonic-gate /*
51*0Sstevel@tonic-gate  * replace trans
52*0Sstevel@tonic-gate  */
53*0Sstevel@tonic-gate 
54*0Sstevel@tonic-gate int
55*0Sstevel@tonic-gate meta_trans_replace(mdsetname_t *sp, mdname_t *transnp, mdname_t *oldnp,
56*0Sstevel@tonic-gate     mdname_t *newnp, mdcmdopts_t options, md_error_t *ep)
57*0Sstevel@tonic-gate {
58*0Sstevel@tonic-gate 	replace_params_t	params;
59*0Sstevel@tonic-gate 	md_dev64_t		old_dev,
60*0Sstevel@tonic-gate 				new_dev;
61*0Sstevel@tonic-gate 	daddr_t			new_start_blk,
62*0Sstevel@tonic-gate 				new_end_blk;
63*0Sstevel@tonic-gate 
64*0Sstevel@tonic-gate 	/* should have same set */
65*0Sstevel@tonic-gate 	assert(sp != NULL);
66*0Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(transnp->dev)));
67*0Sstevel@tonic-gate 
68*0Sstevel@tonic-gate 	new_dev = newnp->dev;
69*0Sstevel@tonic-gate 	new_start_blk = newnp->start_blk;
70*0Sstevel@tonic-gate 	new_end_blk = newnp->end_blk;
71*0Sstevel@tonic-gate 
72*0Sstevel@tonic-gate 	meta_invalidate_name(transnp);
73*0Sstevel@tonic-gate 	/* the old device binding is now established */
74*0Sstevel@tonic-gate 	if ((old_dev = oldnp->dev) == NODEV64)
75*0Sstevel@tonic-gate 		return (mdsyserror(ep, ENODEV, oldnp->cname));
76*0Sstevel@tonic-gate 
77*0Sstevel@tonic-gate 	if (((strcmp(oldnp->rname, newnp->rname) == 0) &&
78*0Sstevel@tonic-gate 	    (old_dev != new_dev))) {
79*0Sstevel@tonic-gate 		newnp->dev = new_dev;
80*0Sstevel@tonic-gate 		newnp->start_blk = new_start_blk;
81*0Sstevel@tonic-gate 		newnp->end_blk = new_end_blk;
82*0Sstevel@tonic-gate 	}
83*0Sstevel@tonic-gate 
84*0Sstevel@tonic-gate 	if (add_key_name(sp, newnp, NULL, ep) != 0)
85*0Sstevel@tonic-gate 		return (-1);
86*0Sstevel@tonic-gate 
87*0Sstevel@tonic-gate 	(void) memset(&params, 0, sizeof (params));
88*0Sstevel@tonic-gate 	params.mnum = meta_getminor(transnp->dev);
89*0Sstevel@tonic-gate 	MD_SETDRIVERNAME(&params, MD_TRANS, sp->setno);
90*0Sstevel@tonic-gate 
91*0Sstevel@tonic-gate 	params.cmd = REPLACE_COMP;
92*0Sstevel@tonic-gate 	params.old_dev = old_dev;
93*0Sstevel@tonic-gate 	params.new_dev = new_dev;
94*0Sstevel@tonic-gate 	params.new_key = newnp->key;
95*0Sstevel@tonic-gate 	if (metaioctl(MD_IOCREPLACE, &params, &params.mde, NULL) != 0) {
96*0Sstevel@tonic-gate 		(void) del_key_name(sp, newnp, ep);
97*0Sstevel@tonic-gate 		return (mdstealerror(ep, &params.mde));
98*0Sstevel@tonic-gate 	}
99*0Sstevel@tonic-gate 	meta_invalidate_name(oldnp);
100*0Sstevel@tonic-gate 	meta_invalidate_name(newnp);
101*0Sstevel@tonic-gate 	meta_invalidate_name(transnp);
102*0Sstevel@tonic-gate 
103*0Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
104*0Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN,
105*0Sstevel@tonic-gate 		    "%s: device %s is replaced with %s\n"),
106*0Sstevel@tonic-gate 		    transnp->cname, oldnp->cname, newnp->cname);
107*0Sstevel@tonic-gate 	}
108*0Sstevel@tonic-gate 	return (0);
109*0Sstevel@tonic-gate }
110*0Sstevel@tonic-gate 
111*0Sstevel@tonic-gate 
112*0Sstevel@tonic-gate 
113*0Sstevel@tonic-gate /*
114*0Sstevel@tonic-gate  * FUNCTION:	meta_get_trans_names()
115*0Sstevel@tonic-gate  * INPUT:	sp	- the set name to get trans from
116*0Sstevel@tonic-gate  *		options	- options from the command line
117*0Sstevel@tonic-gate  * OUTPUT:	nlpp	- list of all trans names
118*0Sstevel@tonic-gate  *		ep	- return error pointer
119*0Sstevel@tonic-gate  * RETURNS:	int	- -1 if error, 0 success
120*0Sstevel@tonic-gate  * PURPOSE:	returns a list of all trans in the metadb
121*0Sstevel@tonic-gate  *		for all devices in the specified set
122*0Sstevel@tonic-gate  */
123*0Sstevel@tonic-gate int
124*0Sstevel@tonic-gate meta_get_trans_names(
125*0Sstevel@tonic-gate 	mdsetname_t	*sp,
126*0Sstevel@tonic-gate 	mdnamelist_t	**nlpp,
127*0Sstevel@tonic-gate 	int		options,
128*0Sstevel@tonic-gate 	md_error_t	*ep
129*0Sstevel@tonic-gate )
130*0Sstevel@tonic-gate {
131*0Sstevel@tonic-gate 	return (meta_get_names(MD_TRANS, sp, nlpp, options, ep));
132*0Sstevel@tonic-gate }
133*0Sstevel@tonic-gate 
134*0Sstevel@tonic-gate /*
135*0Sstevel@tonic-gate  * free trans unit
136*0Sstevel@tonic-gate  */
137*0Sstevel@tonic-gate void
138*0Sstevel@tonic-gate meta_free_trans(
139*0Sstevel@tonic-gate 	md_trans_t	*transp
140*0Sstevel@tonic-gate )
141*0Sstevel@tonic-gate {
142*0Sstevel@tonic-gate 	Free(transp);
143*0Sstevel@tonic-gate }
144*0Sstevel@tonic-gate 
145*0Sstevel@tonic-gate /*
146*0Sstevel@tonic-gate  * get trans (common)
147*0Sstevel@tonic-gate  */
148*0Sstevel@tonic-gate md_trans_t *
149*0Sstevel@tonic-gate meta_get_trans_common(
150*0Sstevel@tonic-gate 	mdsetname_t	*sp,
151*0Sstevel@tonic-gate 	mdname_t	*transnp,
152*0Sstevel@tonic-gate 	int		fast,
153*0Sstevel@tonic-gate 	md_error_t	*ep
154*0Sstevel@tonic-gate )
155*0Sstevel@tonic-gate {
156*0Sstevel@tonic-gate 	mddrivename_t	*dnp = transnp->drivenamep;
157*0Sstevel@tonic-gate 	char		*miscname;
158*0Sstevel@tonic-gate 	mt_unit_t	*mt;
159*0Sstevel@tonic-gate 	md_trans_t	*transp;
160*0Sstevel@tonic-gate 	int		gotlog;
161*0Sstevel@tonic-gate 
162*0Sstevel@tonic-gate 	/* must have set */
163*0Sstevel@tonic-gate 	assert(sp != NULL);
164*0Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(transnp->dev)));
165*0Sstevel@tonic-gate 
166*0Sstevel@tonic-gate 	/* short circuit */
167*0Sstevel@tonic-gate 	if (dnp->unitp != NULL) {
168*0Sstevel@tonic-gate 		assert(dnp->unitp->type == MD_METATRANS);
169*0Sstevel@tonic-gate 		return ((md_trans_t *)dnp->unitp);
170*0Sstevel@tonic-gate 	}
171*0Sstevel@tonic-gate 
172*0Sstevel@tonic-gate 	/* get miscname and unit */
173*0Sstevel@tonic-gate 	if ((miscname = metagetmiscname(transnp, ep)) == NULL)
174*0Sstevel@tonic-gate 		return (NULL);
175*0Sstevel@tonic-gate 	if (strcmp(miscname, MD_TRANS) != 0) {
176*0Sstevel@tonic-gate 		(void) mdmderror(ep, MDE_NOT_MT,
177*0Sstevel@tonic-gate 		    meta_getminor(transnp->dev), transnp->cname);
178*0Sstevel@tonic-gate 		return (NULL);
179*0Sstevel@tonic-gate 	}
180*0Sstevel@tonic-gate 	if ((mt = (mt_unit_t *)meta_get_mdunit(sp, transnp, ep)) == NULL)
181*0Sstevel@tonic-gate 		return (NULL);
182*0Sstevel@tonic-gate 	assert(mt->c.un_type == MD_METATRANS);
183*0Sstevel@tonic-gate 
184*0Sstevel@tonic-gate 	/* allocate trans */
185*0Sstevel@tonic-gate 	transp = Zalloc(sizeof (*transp));
186*0Sstevel@tonic-gate 
187*0Sstevel@tonic-gate 	/* get common info */
188*0Sstevel@tonic-gate 	transp->common.namep = transnp;
189*0Sstevel@tonic-gate 	transp->common.type = mt->c.un_type;
190*0Sstevel@tonic-gate 	transp->common.state = mt->c.un_status;
191*0Sstevel@tonic-gate 	transp->common.capabilities = mt->c.un_capabilities;
192*0Sstevel@tonic-gate 	transp->common.parent = mt->c.un_parent;
193*0Sstevel@tonic-gate 	transp->common.size = mt->c.un_total_blocks;
194*0Sstevel@tonic-gate 	transp->common.user_flags = mt->c.un_user_flags;
195*0Sstevel@tonic-gate 	transp->common.revision = mt->c.un_revision;
196*0Sstevel@tonic-gate 
197*0Sstevel@tonic-gate 	/* get master */
198*0Sstevel@tonic-gate 	transp->masternamep = metakeyname(&sp, mt->un_m_key, fast, ep);
199*0Sstevel@tonic-gate 	if (transp->masternamep == NULL)
200*0Sstevel@tonic-gate 		goto out;
201*0Sstevel@tonic-gate 
202*0Sstevel@tonic-gate 	/* get log */
203*0Sstevel@tonic-gate 	gotlog = ((mt->un_flags & TRANS_DETACHED) == 0);
204*0Sstevel@tonic-gate 	if (gotlog) {
205*0Sstevel@tonic-gate 		daddr_t	sblk;
206*0Sstevel@tonic-gate 
207*0Sstevel@tonic-gate 		transp->lognamep = metakeyname(&sp, mt->un_l_key, fast, ep);
208*0Sstevel@tonic-gate 		if (transp->lognamep == NULL)
209*0Sstevel@tonic-gate 			goto out;
210*0Sstevel@tonic-gate 
211*0Sstevel@tonic-gate 		/* calculate the kernels start block */
212*0Sstevel@tonic-gate 		sblk = mt->un_l_pwsblk + mt->un_l_maxtransfer;
213*0Sstevel@tonic-gate 
214*0Sstevel@tonic-gate 		if (getenv("META_DEBUG_START_BLK") != NULL) {
215*0Sstevel@tonic-gate 			if (metagetstart(sp, transp->lognamep, ep) ==
216*0Sstevel@tonic-gate 			    MD_DISKADDR_ERROR)
217*0Sstevel@tonic-gate 				mdclrerror(ep);
218*0Sstevel@tonic-gate 
219*0Sstevel@tonic-gate 			if (transp->lognamep->start_blk > sblk)
220*0Sstevel@tonic-gate 				md_eprintf(dgettext(TEXT_DOMAIN,
221*0Sstevel@tonic-gate 				    "%s: suspected bad start block [trans]\n"),
222*0Sstevel@tonic-gate 				    transp->lognamep->cname);
223*0Sstevel@tonic-gate 		}
224*0Sstevel@tonic-gate 
225*0Sstevel@tonic-gate 		/* override any start_blk */
226*0Sstevel@tonic-gate 		transp->lognamep->start_blk = sblk;
227*0Sstevel@tonic-gate 	}
228*0Sstevel@tonic-gate 
229*0Sstevel@tonic-gate 	/* get flags, etc. */
230*0Sstevel@tonic-gate 	transp->flags = mt->un_flags;
231*0Sstevel@tonic-gate 	transp->timestamp = mt->un_timestamp;
232*0Sstevel@tonic-gate 	transp->log_error = mt->un_l_error;
233*0Sstevel@tonic-gate 	transp->log_timestamp = mt->un_l_timestamp;
234*0Sstevel@tonic-gate 	transp->log_size = mt->un_l_nblks;
235*0Sstevel@tonic-gate 	transp->debug = mt->un_debug;
236*0Sstevel@tonic-gate 
237*0Sstevel@tonic-gate 	/* cleanup, return success */
238*0Sstevel@tonic-gate 	Free(mt);
239*0Sstevel@tonic-gate 	dnp->unitp = (md_common_t *)transp;
240*0Sstevel@tonic-gate 	return (transp);
241*0Sstevel@tonic-gate 
242*0Sstevel@tonic-gate 	/* cleanup, return error */
243*0Sstevel@tonic-gate out:
244*0Sstevel@tonic-gate 	Free(mt);
245*0Sstevel@tonic-gate 	meta_free_trans(transp);
246*0Sstevel@tonic-gate 	return (NULL);
247*0Sstevel@tonic-gate }
248*0Sstevel@tonic-gate 
249*0Sstevel@tonic-gate /*
250*0Sstevel@tonic-gate  * get trans
251*0Sstevel@tonic-gate  */
252*0Sstevel@tonic-gate md_trans_t *
253*0Sstevel@tonic-gate meta_get_trans(
254*0Sstevel@tonic-gate 	mdsetname_t	*sp,
255*0Sstevel@tonic-gate 	mdname_t	*transnp,
256*0Sstevel@tonic-gate 	md_error_t	*ep
257*0Sstevel@tonic-gate )
258*0Sstevel@tonic-gate {
259*0Sstevel@tonic-gate 	return (meta_get_trans_common(sp, transnp, 0, ep));
260*0Sstevel@tonic-gate }
261*0Sstevel@tonic-gate 
262*0Sstevel@tonic-gate /*
263*0Sstevel@tonic-gate  * check trans for dev
264*0Sstevel@tonic-gate  */
265*0Sstevel@tonic-gate static int
266*0Sstevel@tonic-gate in_trans(
267*0Sstevel@tonic-gate 	mdsetname_t	*sp,
268*0Sstevel@tonic-gate 	mdname_t	*transnp,
269*0Sstevel@tonic-gate 	mdname_t	*np,
270*0Sstevel@tonic-gate 	mdchkopts_t	options,
271*0Sstevel@tonic-gate 	diskaddr_t	slblk,
272*0Sstevel@tonic-gate 	diskaddr_t	nblks,
273*0Sstevel@tonic-gate 	md_error_t	*ep
274*0Sstevel@tonic-gate )
275*0Sstevel@tonic-gate {
276*0Sstevel@tonic-gate 	md_trans_t	*transp;
277*0Sstevel@tonic-gate 	mdname_t	*masternp;
278*0Sstevel@tonic-gate 	mdname_t	*lognp;
279*0Sstevel@tonic-gate 
280*0Sstevel@tonic-gate 	/* should be in the same set */
281*0Sstevel@tonic-gate 	assert(sp != NULL);
282*0Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(transnp->dev)));
283*0Sstevel@tonic-gate 
284*0Sstevel@tonic-gate 	/* get unit */
285*0Sstevel@tonic-gate 	if ((transp = meta_get_trans(sp, transnp, ep)) == NULL)
286*0Sstevel@tonic-gate 		return (-1);
287*0Sstevel@tonic-gate 
288*0Sstevel@tonic-gate 	/* check master */
289*0Sstevel@tonic-gate 	masternp = transp->masternamep;
290*0Sstevel@tonic-gate 	if ((! metaismeta(masternp)) &&
291*0Sstevel@tonic-gate 	    (meta_check_overlap(transnp->cname, np, slblk, nblks,
292*0Sstevel@tonic-gate 	    masternp, 0, -1, ep) != 0)) {
293*0Sstevel@tonic-gate 		return (-1);
294*0Sstevel@tonic-gate 	}
295*0Sstevel@tonic-gate 
296*0Sstevel@tonic-gate 	/* check log */
297*0Sstevel@tonic-gate 	if (((lognp = transp->lognamep) != NULL) &&
298*0Sstevel@tonic-gate 	    (! (options & MDCHK_ALLOW_LOG)) &&
299*0Sstevel@tonic-gate 	    (! metaismeta(lognp))) {
300*0Sstevel@tonic-gate 		daddr_t		log_start;
301*0Sstevel@tonic-gate 		int		err;
302*0Sstevel@tonic-gate 
303*0Sstevel@tonic-gate 		/* check same drive since metagetstart() can fail */
304*0Sstevel@tonic-gate 		if ((err = meta_check_samedrive(np, lognp, ep)) < 0)
305*0Sstevel@tonic-gate 			return (-1);
306*0Sstevel@tonic-gate 
307*0Sstevel@tonic-gate 		/* check overlap */
308*0Sstevel@tonic-gate 		if (err != 0) {
309*0Sstevel@tonic-gate 			if ((log_start = metagetstart(sp, lognp, ep)) ==
310*0Sstevel@tonic-gate 			    MD_DISKADDR_ERROR)
311*0Sstevel@tonic-gate 				return (-1);
312*0Sstevel@tonic-gate 			if (meta_check_overlap(transnp->cname, np, slblk,
313*0Sstevel@tonic-gate 			    nblks, lognp, log_start, -1, ep) != 0) {
314*0Sstevel@tonic-gate 				return (-1);
315*0Sstevel@tonic-gate 			}
316*0Sstevel@tonic-gate 		}
317*0Sstevel@tonic-gate 	}
318*0Sstevel@tonic-gate 
319*0Sstevel@tonic-gate 	/* return success */
320*0Sstevel@tonic-gate 	return (0);
321*0Sstevel@tonic-gate }
322*0Sstevel@tonic-gate 
323*0Sstevel@tonic-gate /*
324*0Sstevel@tonic-gate  * check to see if we're in a trans
325*0Sstevel@tonic-gate  */
326*0Sstevel@tonic-gate int
327*0Sstevel@tonic-gate meta_check_intrans(
328*0Sstevel@tonic-gate 	mdsetname_t	*sp,
329*0Sstevel@tonic-gate 	mdname_t	*np,
330*0Sstevel@tonic-gate 	mdchkopts_t	options,
331*0Sstevel@tonic-gate 	diskaddr_t	slblk,
332*0Sstevel@tonic-gate 	diskaddr_t	nblks,
333*0Sstevel@tonic-gate 	md_error_t	*ep
334*0Sstevel@tonic-gate )
335*0Sstevel@tonic-gate {
336*0Sstevel@tonic-gate 	mdnamelist_t	*transnlp = NULL;
337*0Sstevel@tonic-gate 	mdnamelist_t	*p;
338*0Sstevel@tonic-gate 	int		rval = 0;
339*0Sstevel@tonic-gate 
340*0Sstevel@tonic-gate 	/* should have a set */
341*0Sstevel@tonic-gate 	assert(sp != NULL);
342*0Sstevel@tonic-gate 
343*0Sstevel@tonic-gate 	/* for each trans */
344*0Sstevel@tonic-gate 	if (meta_get_trans_names(sp, &transnlp, 0, ep) < 0)
345*0Sstevel@tonic-gate 		return (-1);
346*0Sstevel@tonic-gate 	for (p = transnlp; (p != NULL); p = p->next) {
347*0Sstevel@tonic-gate 		mdname_t	*transnp = p->namep;
348*0Sstevel@tonic-gate 
349*0Sstevel@tonic-gate 		/* check trans */
350*0Sstevel@tonic-gate 		if (in_trans(sp, transnp, np, options, slblk, nblks, ep) != 0) {
351*0Sstevel@tonic-gate 			rval = -1;
352*0Sstevel@tonic-gate 			break;
353*0Sstevel@tonic-gate 		}
354*0Sstevel@tonic-gate 	}
355*0Sstevel@tonic-gate 
356*0Sstevel@tonic-gate 	/* cleanup, return success */
357*0Sstevel@tonic-gate 	metafreenamelist(transnlp);
358*0Sstevel@tonic-gate 	return (rval);
359*0Sstevel@tonic-gate }
360*0Sstevel@tonic-gate 
361*0Sstevel@tonic-gate /*
362*0Sstevel@tonic-gate  * check master
363*0Sstevel@tonic-gate  */
364*0Sstevel@tonic-gate int
365*0Sstevel@tonic-gate meta_check_master(
366*0Sstevel@tonic-gate 	mdsetname_t	*sp,
367*0Sstevel@tonic-gate 	mdname_t	*np,
368*0Sstevel@tonic-gate 	int		force,
369*0Sstevel@tonic-gate 	md_error_t	*ep
370*0Sstevel@tonic-gate )
371*0Sstevel@tonic-gate {
372*0Sstevel@tonic-gate 	mdchkopts_t	options = 0;
373*0Sstevel@tonic-gate 	md_common_t	*mdp;
374*0Sstevel@tonic-gate 
375*0Sstevel@tonic-gate 	/* make sure we have a disk */
376*0Sstevel@tonic-gate 	if (metachkdisk(np, ep) != 0)
377*0Sstevel@tonic-gate 		return (-1);
378*0Sstevel@tonic-gate 
379*0Sstevel@tonic-gate 	/* check to ensure that it is not already in use */
380*0Sstevel@tonic-gate 	if ((!force) && meta_check_inuse(sp, np, MDCHK_INUSE, ep) != 0) {
381*0Sstevel@tonic-gate 		return (-1);
382*0Sstevel@tonic-gate 	}
383*0Sstevel@tonic-gate 
384*0Sstevel@tonic-gate 	/* make sure it is in the set */
385*0Sstevel@tonic-gate 	if (meta_check_inset(sp, np, ep) != 0)
386*0Sstevel@tonic-gate 		return (-1);
387*0Sstevel@tonic-gate 
388*0Sstevel@tonic-gate 	/* make sure its not in a metadevice */
389*0Sstevel@tonic-gate 	if (! metaismeta(np)) {		/* Non-metadevices */
390*0Sstevel@tonic-gate 		if (meta_check_inmeta(sp, np, options, 0, -1, ep) != 0)
391*0Sstevel@tonic-gate 			return (-1);
392*0Sstevel@tonic-gate 	} else {			/* Metadevices only! */
393*0Sstevel@tonic-gate 		if ((mdp = meta_get_unit(sp, np, ep)) == NULL)
394*0Sstevel@tonic-gate 			return (-1);
395*0Sstevel@tonic-gate 
396*0Sstevel@tonic-gate 		/*
397*0Sstevel@tonic-gate 		 * Since soft partitions may appear at the top or bottom
398*0Sstevel@tonic-gate 		 * of the metadevice stack, we check them separately.
399*0Sstevel@tonic-gate 		 * A trans may be built on top of a soft partition if
400*0Sstevel@tonic-gate 		 * the soft partition has no parent (can't rely on the
401*0Sstevel@tonic-gate 		 * MD_CAN_PARENT flag in this case since a soft partition
402*0Sstevel@tonic-gate 		 * built on a metadevice clears this flag to prevent nested
403*0Sstevel@tonic-gate 		 * configurations).
404*0Sstevel@tonic-gate 		 */
405*0Sstevel@tonic-gate 		if ((meta_sp_issp(sp, np, ep) == 0) &&
406*0Sstevel@tonic-gate 		    (mdp->parent == MD_NO_PARENT))
407*0Sstevel@tonic-gate 			return (0);
408*0Sstevel@tonic-gate 
409*0Sstevel@tonic-gate 		if ((! (mdp->capabilities & MD_CAN_PARENT)) ||
410*0Sstevel@tonic-gate 		    (mdp->parent != MD_NO_PARENT)) {
411*0Sstevel@tonic-gate 			return (mdmderror(ep, MDE_INVAL_UNIT,
412*0Sstevel@tonic-gate 			    meta_getminor(np->dev), np->cname));
413*0Sstevel@tonic-gate 		}
414*0Sstevel@tonic-gate 	}
415*0Sstevel@tonic-gate 
416*0Sstevel@tonic-gate 	/* return success */
417*0Sstevel@tonic-gate 	return (0);
418*0Sstevel@tonic-gate }
419*0Sstevel@tonic-gate 
420*0Sstevel@tonic-gate /*
421*0Sstevel@tonic-gate  * check log
422*0Sstevel@tonic-gate  */
423*0Sstevel@tonic-gate int
424*0Sstevel@tonic-gate meta_check_log(
425*0Sstevel@tonic-gate 	mdsetname_t	*sp,
426*0Sstevel@tonic-gate 	mdname_t	*np,
427*0Sstevel@tonic-gate 	md_error_t	*ep
428*0Sstevel@tonic-gate )
429*0Sstevel@tonic-gate {
430*0Sstevel@tonic-gate 	mdchkopts_t	options = (MDCHK_ALLOW_MDDB | MDCHK_ALLOW_LOG);
431*0Sstevel@tonic-gate 	md_common_t	*mdp;
432*0Sstevel@tonic-gate 
433*0Sstevel@tonic-gate 	/* make sure we have a disk */
434*0Sstevel@tonic-gate 	if (metachkdisk(np, ep) != 0)
435*0Sstevel@tonic-gate 		return (-1);
436*0Sstevel@tonic-gate 
437*0Sstevel@tonic-gate 	/* check to ensure that it is not already in use */
438*0Sstevel@tonic-gate 	if (meta_check_inuse(sp, np, MDCHK_INUSE, ep) != 0) {
439*0Sstevel@tonic-gate 		return (-1);
440*0Sstevel@tonic-gate 	}
441*0Sstevel@tonic-gate 
442*0Sstevel@tonic-gate 	/* make sure it is in the set */
443*0Sstevel@tonic-gate 	if (meta_check_inset(sp, np, ep) != 0)
444*0Sstevel@tonic-gate 		return (-1);
445*0Sstevel@tonic-gate 
446*0Sstevel@tonic-gate 	/* make sure its not in a metadevice */
447*0Sstevel@tonic-gate 	if (! metaismeta(np)) {		/* Non-metadevices */
448*0Sstevel@tonic-gate 		if (meta_check_inmeta(sp, np, options, 0, -1, ep) != 0)
449*0Sstevel@tonic-gate 			return (-1);
450*0Sstevel@tonic-gate 	} else {			/* Metadevices only! */
451*0Sstevel@tonic-gate 		if ((mdp = meta_get_unit(sp, np, ep)) == NULL)
452*0Sstevel@tonic-gate 			return (-1);
453*0Sstevel@tonic-gate 
454*0Sstevel@tonic-gate 		/*
455*0Sstevel@tonic-gate 		 * Since soft partitions may appear at the top or bottom
456*0Sstevel@tonic-gate 		 * of the metadevice stack, we check them separately.
457*0Sstevel@tonic-gate 		 * A trans may be built on top of a soft partition if
458*0Sstevel@tonic-gate 		 * the soft partition has no parent (can't rely on the
459*0Sstevel@tonic-gate 		 * MD_CAN_PARENT flag in this case since a soft partition
460*0Sstevel@tonic-gate 		 * built on a metadevice clears this flag to prevent nested
461*0Sstevel@tonic-gate 		 * configurations).
462*0Sstevel@tonic-gate 		 *
463*0Sstevel@tonic-gate 		 */
464*0Sstevel@tonic-gate 		if ((meta_sp_issp(sp, np, ep) == 0) &&
465*0Sstevel@tonic-gate 		    (mdp->parent == MD_NO_PARENT))
466*0Sstevel@tonic-gate 			return (0);
467*0Sstevel@tonic-gate 
468*0Sstevel@tonic-gate 		if ((! (mdp->capabilities & MD_CAN_PARENT)) ||
469*0Sstevel@tonic-gate 		    ((mdp->parent != MD_NO_PARENT) &&
470*0Sstevel@tonic-gate 		    (mdp->parent != MD_MULTI_PARENT))) {
471*0Sstevel@tonic-gate 			return (mdmderror(ep, MDE_INVAL_UNIT,
472*0Sstevel@tonic-gate 			    meta_getminor(np->dev), np->cname));
473*0Sstevel@tonic-gate 		}
474*0Sstevel@tonic-gate 	}
475*0Sstevel@tonic-gate 
476*0Sstevel@tonic-gate 	/* return success */
477*0Sstevel@tonic-gate 	return (0);
478*0Sstevel@tonic-gate }
479*0Sstevel@tonic-gate 
480*0Sstevel@tonic-gate /*
481*0Sstevel@tonic-gate  * print trans
482*0Sstevel@tonic-gate  */
483*0Sstevel@tonic-gate static int
484*0Sstevel@tonic-gate trans_print(
485*0Sstevel@tonic-gate 	md_trans_t	*transp,
486*0Sstevel@tonic-gate 	char		*fname,
487*0Sstevel@tonic-gate 	FILE		*fp,
488*0Sstevel@tonic-gate 	md_error_t	*ep
489*0Sstevel@tonic-gate )
490*0Sstevel@tonic-gate {
491*0Sstevel@tonic-gate 	int		rval = -1;
492*0Sstevel@tonic-gate 
493*0Sstevel@tonic-gate 	/* print name and -t */
494*0Sstevel@tonic-gate 	if (fprintf(fp, "%s -t", transp->common.namep->cname) == EOF)
495*0Sstevel@tonic-gate 		goto out;
496*0Sstevel@tonic-gate 
497*0Sstevel@tonic-gate 	/* print master */
498*0Sstevel@tonic-gate 	/*
499*0Sstevel@tonic-gate 	 * If the path is our standard /dev/rdsk or /dev/md/rdsk
500*0Sstevel@tonic-gate 	 * then just print out the cxtxdxsx or the dx, metainit
501*0Sstevel@tonic-gate 	 * will assume the default, otherwise we need the full
502*0Sstevel@tonic-gate 	 * pathname to make sure this works as we intend.
503*0Sstevel@tonic-gate 	 */
504*0Sstevel@tonic-gate 	if ((strstr(transp->masternamep->rname, "/dev/rdsk") == NULL) &&
505*0Sstevel@tonic-gate 	    (strstr(transp->masternamep->rname, "/dev/md/rdsk") == NULL) &&
506*0Sstevel@tonic-gate 	    (strstr(transp->masternamep->rname, "/dev/td/") == NULL)) {
507*0Sstevel@tonic-gate 		/* not standard path, print full pathname */
508*0Sstevel@tonic-gate 		if (fprintf(fp, " %s", transp->masternamep->rname) == EOF)
509*0Sstevel@tonic-gate 			goto out;
510*0Sstevel@tonic-gate 	} else {
511*0Sstevel@tonic-gate 		/* standard path, print ctds or d number */
512*0Sstevel@tonic-gate 		if (fprintf(fp, " %s", transp->masternamep->cname) == EOF)
513*0Sstevel@tonic-gate 			goto out;
514*0Sstevel@tonic-gate 	}
515*0Sstevel@tonic-gate 
516*0Sstevel@tonic-gate 
517*0Sstevel@tonic-gate 	/* print log */
518*0Sstevel@tonic-gate 	if (transp->lognamep != NULL) {
519*0Sstevel@tonic-gate 		/*
520*0Sstevel@tonic-gate 		 * If the path is our standard /dev/rdsk or /dev/md/rdsk
521*0Sstevel@tonic-gate 		 * then just print out the cxtxdxsx or the dx, metainit
522*0Sstevel@tonic-gate 		 * will assume the default, otherwise we need the full
523*0Sstevel@tonic-gate 		 * pathname to make sure this works as we intend.
524*0Sstevel@tonic-gate 		 */
525*0Sstevel@tonic-gate 		if ((strstr(transp->lognamep->rname, "/dev/rdsk") == NULL) &&
526*0Sstevel@tonic-gate 		    (strstr(transp->lognamep->rname, "/dev/md/rdsk") == NULL) &&
527*0Sstevel@tonic-gate 		    (strstr(transp->lognamep->rname, "/dev/td/") == NULL)) {
528*0Sstevel@tonic-gate 			/* not standard path, print full pathname */
529*0Sstevel@tonic-gate 			if (fprintf(fp, " %s", transp->lognamep->rname) == EOF)
530*0Sstevel@tonic-gate 				goto out;
531*0Sstevel@tonic-gate 		} else {
532*0Sstevel@tonic-gate 			/* standard path */
533*0Sstevel@tonic-gate 			if (fprintf(fp, " %s", transp->lognamep->cname) == EOF)
534*0Sstevel@tonic-gate 				goto out;
535*0Sstevel@tonic-gate 		}
536*0Sstevel@tonic-gate 	}
537*0Sstevel@tonic-gate 
538*0Sstevel@tonic-gate 	/* print terminating newline */
539*0Sstevel@tonic-gate 	if (fprintf(fp, "\n") == EOF)
540*0Sstevel@tonic-gate 		goto out;
541*0Sstevel@tonic-gate 
542*0Sstevel@tonic-gate 	/* success */
543*0Sstevel@tonic-gate 	rval = 0;
544*0Sstevel@tonic-gate 
545*0Sstevel@tonic-gate 	/* cleanup, return error */
546*0Sstevel@tonic-gate out:
547*0Sstevel@tonic-gate 	if (rval != 0)
548*0Sstevel@tonic-gate 		(void) mdsyserror(ep, errno, fname);
549*0Sstevel@tonic-gate 	return (rval);
550*0Sstevel@tonic-gate }
551*0Sstevel@tonic-gate 
552*0Sstevel@tonic-gate /*
553*0Sstevel@tonic-gate  * convert flags to repair action
554*0Sstevel@tonic-gate  */
555*0Sstevel@tonic-gate 
556*0Sstevel@tonic-gate char *
557*0Sstevel@tonic-gate mt_flags_to_action(
558*0Sstevel@tonic-gate 	md_trans_t *transp
559*0Sstevel@tonic-gate )
560*0Sstevel@tonic-gate {
561*0Sstevel@tonic-gate 	int	 len;
562*0Sstevel@tonic-gate 	char	*actionp	= NULL;
563*0Sstevel@tonic-gate 	int	 err		= -1;
564*0Sstevel@tonic-gate 
565*0Sstevel@tonic-gate 	if (!transp) {
566*0Sstevel@tonic-gate 		goto out;
567*0Sstevel@tonic-gate 	}
568*0Sstevel@tonic-gate 
569*0Sstevel@tonic-gate 	/*
570*0Sstevel@tonic-gate 	 * if in any of these states, the log_error word is not (yet) meaningful
571*0Sstevel@tonic-gate 	 */
572*0Sstevel@tonic-gate 	if (transp->flags & (TRANS_DETACHED|TRANS_DETACHING|TRANS_ATTACHING)) {
573*0Sstevel@tonic-gate 		goto out;
574*0Sstevel@tonic-gate 	}
575*0Sstevel@tonic-gate 
576*0Sstevel@tonic-gate 	if (transp->log_error & LDL_ANYERROR) {
577*0Sstevel@tonic-gate 		char *fix_msg = dgettext(TEXT_DOMAIN,
578*0Sstevel@tonic-gate 		    "    To Fix: Please refer to the log device's status.\n");
579*0Sstevel@tonic-gate 
580*0Sstevel@tonic-gate 		if ((len = strlen(fix_msg)) <= 0) {
581*0Sstevel@tonic-gate 			goto out;
582*0Sstevel@tonic-gate 		}
583*0Sstevel@tonic-gate 		if (!(actionp = Zalloc(len+1))) {
584*0Sstevel@tonic-gate 			goto out;
585*0Sstevel@tonic-gate 		}
586*0Sstevel@tonic-gate 		if (strncpy(actionp, fix_msg, len + 1) != actionp) {
587*0Sstevel@tonic-gate 			goto out;
588*0Sstevel@tonic-gate 		}
589*0Sstevel@tonic-gate 	}
590*0Sstevel@tonic-gate 	err = 0;
591*0Sstevel@tonic-gate out:
592*0Sstevel@tonic-gate 	if (err != 0) {
593*0Sstevel@tonic-gate 		if (actionp) {
594*0Sstevel@tonic-gate 			Free(actionp);
595*0Sstevel@tonic-gate 			actionp = NULL;
596*0Sstevel@tonic-gate 		}
597*0Sstevel@tonic-gate 	}
598*0Sstevel@tonic-gate 	return (actionp);
599*0Sstevel@tonic-gate }
600*0Sstevel@tonic-gate 
601*0Sstevel@tonic-gate /*
602*0Sstevel@tonic-gate  * convert log state to repair action
603*0Sstevel@tonic-gate  */
604*0Sstevel@tonic-gate char *
605*0Sstevel@tonic-gate mt_l_error_to_action(
606*0Sstevel@tonic-gate 	mdsetname_t	*sp,
607*0Sstevel@tonic-gate 	mdnamelist_t	*transnlp,
608*0Sstevel@tonic-gate 	mdname_t	*lognamep,
609*0Sstevel@tonic-gate 	md_error_t	*ep
610*0Sstevel@tonic-gate )
611*0Sstevel@tonic-gate {
612*0Sstevel@tonic-gate 	char		 umnt_msg[1024];
613*0Sstevel@tonic-gate 	char		 fsck_msg[1024];
614*0Sstevel@tonic-gate 	char		 mnt_msg[1024];
615*0Sstevel@tonic-gate 	mdnamelist_t	*p;
616*0Sstevel@tonic-gate 	md_trans_t	*tp;
617*0Sstevel@tonic-gate 	int		 rc;
618*0Sstevel@tonic-gate 	int		 len		= 0;
619*0Sstevel@tonic-gate 	char		*rmsg		= NULL;
620*0Sstevel@tonic-gate 	char		*mp		= NULL;
621*0Sstevel@tonic-gate 	bool_t		 is_mounted	= FALSE;
622*0Sstevel@tonic-gate 	bool_t		 any_in_error	= FALSE;
623*0Sstevel@tonic-gate 	int		 only_fsck	= TRUE;
624*0Sstevel@tonic-gate 
625*0Sstevel@tonic-gate 	(void) memset(umnt_msg, 0, sizeof (umnt_msg));
626*0Sstevel@tonic-gate 	(void) memset(fsck_msg, 0, sizeof (fsck_msg));
627*0Sstevel@tonic-gate 	(void) memset(mnt_msg, 0, sizeof (mnt_msg));
628*0Sstevel@tonic-gate 
629*0Sstevel@tonic-gate 	/*
630*0Sstevel@tonic-gate 	 * If a the trans devices listed in transnlp contain
631*0Sstevel@tonic-gate 	 * devices which are in error and are sub-mount points
632*0Sstevel@tonic-gate 	 * of each other, than it would need to be reverse sorted.
633*0Sstevel@tonic-gate 	 * When this actually occurs, and customers find the usage
634*0Sstevel@tonic-gate 	 * message insufficiently clear, then we should take the
635*0Sstevel@tonic-gate 	 * hit to sort it.
636*0Sstevel@tonic-gate 	 */
637*0Sstevel@tonic-gate 
638*0Sstevel@tonic-gate 	/*
639*0Sstevel@tonic-gate 	 * this preliminary loop is necessary to keep the
640*0Sstevel@tonic-gate 	 * fsck message greppable, if possible
641*0Sstevel@tonic-gate 	 */
642*0Sstevel@tonic-gate 	for (p = transnlp; ((p != NULL) && (only_fsck == TRUE)); p = p->next) {
643*0Sstevel@tonic-gate 
644*0Sstevel@tonic-gate 		if ((tp = meta_get_trans(sp, p->namep, ep)) == NULL) {
645*0Sstevel@tonic-gate 			goto out;
646*0Sstevel@tonic-gate 		}
647*0Sstevel@tonic-gate 
648*0Sstevel@tonic-gate 		if (!(tp->log_error & LDL_ANYERROR)) {
649*0Sstevel@tonic-gate 			continue;
650*0Sstevel@tonic-gate 		}
651*0Sstevel@tonic-gate 
652*0Sstevel@tonic-gate 		if ((tp->lognamep == NULL) ||
653*0Sstevel@tonic-gate 		    (strcmp(lognamep->bname, tp->lognamep->bname) != 0)) {
654*0Sstevel@tonic-gate 			continue;
655*0Sstevel@tonic-gate 		}
656*0Sstevel@tonic-gate 
657*0Sstevel@tonic-gate 		mdclrerror(ep);
658*0Sstevel@tonic-gate 		is_mounted = (meta_check_inuse(sp,
659*0Sstevel@tonic-gate 		    p->namep, MDCHK_MOUNTED, ep) != 0);
660*0Sstevel@tonic-gate 
661*0Sstevel@tonic-gate 		if (!mdisok(ep) && mdiserror(ep, MDE_IS_MOUNTED)) {
662*0Sstevel@tonic-gate 			goto out;
663*0Sstevel@tonic-gate 		}
664*0Sstevel@tonic-gate 
665*0Sstevel@tonic-gate 		mdclrerror(ep);
666*0Sstevel@tonic-gate 		mp = meta_get_mountp(sp, p->namep, ep);
667*0Sstevel@tonic-gate 
668*0Sstevel@tonic-gate 		if (!mdisok(ep)) {
669*0Sstevel@tonic-gate 			goto out;
670*0Sstevel@tonic-gate 		}
671*0Sstevel@tonic-gate 
672*0Sstevel@tonic-gate 		if (is_mounted) {
673*0Sstevel@tonic-gate 			if (!mp) {
674*0Sstevel@tonic-gate 				goto out;
675*0Sstevel@tonic-gate 			}
676*0Sstevel@tonic-gate 			only_fsck = FALSE;
677*0Sstevel@tonic-gate 
678*0Sstevel@tonic-gate 			/*
679*0Sstevel@tonic-gate 			 * not greppable; there must be multiple commands, so
680*0Sstevel@tonic-gate 			 * add preliminary newline so the formatting is uniform
681*0Sstevel@tonic-gate 			 */
682*0Sstevel@tonic-gate 			if (sprintf(umnt_msg, "\n") == EOF) {
683*0Sstevel@tonic-gate 				goto out;
684*0Sstevel@tonic-gate 			}
685*0Sstevel@tonic-gate 
686*0Sstevel@tonic-gate 		}
687*0Sstevel@tonic-gate 
688*0Sstevel@tonic-gate 		if (mp) {
689*0Sstevel@tonic-gate 			Free(mp);
690*0Sstevel@tonic-gate 			mp = NULL;
691*0Sstevel@tonic-gate 		}
692*0Sstevel@tonic-gate 	}
693*0Sstevel@tonic-gate 
694*0Sstevel@tonic-gate 	/*
695*0Sstevel@tonic-gate 	 * although the log may either be in error or hard-error
696*0Sstevel@tonic-gate 	 * states, the action is the same; unmount, fsck and remount
697*0Sstevel@tonic-gate 	 * all fs associated with this log
698*0Sstevel@tonic-gate 	 */
699*0Sstevel@tonic-gate 	for (p = transnlp; (p != NULL); p = p->next) {
700*0Sstevel@tonic-gate 
701*0Sstevel@tonic-gate 		if ((tp = meta_get_trans(sp, p->namep, ep)) == NULL) {
702*0Sstevel@tonic-gate 			goto out;
703*0Sstevel@tonic-gate 		}
704*0Sstevel@tonic-gate 
705*0Sstevel@tonic-gate 		if (!(tp->log_error & LDL_ANYERROR)) {
706*0Sstevel@tonic-gate 			continue;
707*0Sstevel@tonic-gate 		}
708*0Sstevel@tonic-gate 
709*0Sstevel@tonic-gate 		if ((tp->lognamep == NULL) ||
710*0Sstevel@tonic-gate 		    (strcmp(lognamep->bname, tp->lognamep->bname) != 0)) {
711*0Sstevel@tonic-gate 			continue;
712*0Sstevel@tonic-gate 		}
713*0Sstevel@tonic-gate 
714*0Sstevel@tonic-gate 		mdclrerror(ep);
715*0Sstevel@tonic-gate 		is_mounted = (meta_check_inuse(sp,
716*0Sstevel@tonic-gate 		    p->namep, MDCHK_MOUNTED, ep) != 0);
717*0Sstevel@tonic-gate 
718*0Sstevel@tonic-gate 		if (!mdisok(ep) && mdiserror(ep, MDE_IS_MOUNTED)) {
719*0Sstevel@tonic-gate 			goto out;
720*0Sstevel@tonic-gate 		}
721*0Sstevel@tonic-gate 
722*0Sstevel@tonic-gate 		mdclrerror(ep);
723*0Sstevel@tonic-gate 		mp = meta_get_mountp(sp, p->namep, ep);
724*0Sstevel@tonic-gate 
725*0Sstevel@tonic-gate 		if (!mdisok(ep)) {
726*0Sstevel@tonic-gate 			goto out;
727*0Sstevel@tonic-gate 		}
728*0Sstevel@tonic-gate 
729*0Sstevel@tonic-gate 		if (is_mounted) {
730*0Sstevel@tonic-gate 			if (!mp) {
731*0Sstevel@tonic-gate 				goto out;
732*0Sstevel@tonic-gate 			}
733*0Sstevel@tonic-gate 		}
734*0Sstevel@tonic-gate 
735*0Sstevel@tonic-gate 		if (is_mounted) {
736*0Sstevel@tonic-gate 			rc = snprintf(umnt_msg, sizeof (umnt_msg),
737*0Sstevel@tonic-gate 			    "%s            umount %s\n", umnt_msg, mp);
738*0Sstevel@tonic-gate 
739*0Sstevel@tonic-gate 			if (rc < 0) {
740*0Sstevel@tonic-gate 				goto out;
741*0Sstevel@tonic-gate 			}
742*0Sstevel@tonic-gate 		}
743*0Sstevel@tonic-gate 
744*0Sstevel@tonic-gate 		rc = snprintf(fsck_msg, sizeof (fsck_msg), "%s %s",
745*0Sstevel@tonic-gate 		    (any_in_error) ? fsck_msg :
746*0Sstevel@tonic-gate 		    ((only_fsck) ? "fsck" : "            fsck"),
747*0Sstevel@tonic-gate 		    p->namep->rname);
748*0Sstevel@tonic-gate 		if (rc < 0) {
749*0Sstevel@tonic-gate 			goto out;
750*0Sstevel@tonic-gate 		}
751*0Sstevel@tonic-gate 
752*0Sstevel@tonic-gate 		if (is_mounted) {
753*0Sstevel@tonic-gate 			rc = snprintf(mnt_msg, sizeof (mnt_msg),
754*0Sstevel@tonic-gate 			    "%s            mount %s %s\n",
755*0Sstevel@tonic-gate 			    mnt_msg, p->namep->bname, mp);
756*0Sstevel@tonic-gate 
757*0Sstevel@tonic-gate 			if (rc < 0) {
758*0Sstevel@tonic-gate 				goto out;
759*0Sstevel@tonic-gate 			}
760*0Sstevel@tonic-gate 		}
761*0Sstevel@tonic-gate 
762*0Sstevel@tonic-gate 		if (mp) {
763*0Sstevel@tonic-gate 			Free(mp);
764*0Sstevel@tonic-gate 			mp = NULL;
765*0Sstevel@tonic-gate 		}
766*0Sstevel@tonic-gate 
767*0Sstevel@tonic-gate 		any_in_error |= TRUE;
768*0Sstevel@tonic-gate 	}
769*0Sstevel@tonic-gate 
770*0Sstevel@tonic-gate 	if (!any_in_error) {
771*0Sstevel@tonic-gate 		goto out;
772*0Sstevel@tonic-gate 	}
773*0Sstevel@tonic-gate 
774*0Sstevel@tonic-gate 	len = strlen(umnt_msg) + strlen(fsck_msg) + strlen(mnt_msg) +
775*0Sstevel@tonic-gate 							(only_fsck? 1: 0) + 1;
776*0Sstevel@tonic-gate 	if (!(rmsg = Zalloc(len))) {
777*0Sstevel@tonic-gate 		len = 0;
778*0Sstevel@tonic-gate 		goto out;
779*0Sstevel@tonic-gate 	}
780*0Sstevel@tonic-gate 	rc = snprintf(rmsg, len, "%s%s%s%s", umnt_msg, fsck_msg,
781*0Sstevel@tonic-gate 					    !only_fsck? "\n": "", mnt_msg);
782*0Sstevel@tonic-gate 	if (rc == EOF) {
783*0Sstevel@tonic-gate 		goto out;
784*0Sstevel@tonic-gate 	}
785*0Sstevel@tonic-gate 
786*0Sstevel@tonic-gate out:
787*0Sstevel@tonic-gate 	if (mp) {
788*0Sstevel@tonic-gate 		Free(mp);
789*0Sstevel@tonic-gate 		mp = NULL;
790*0Sstevel@tonic-gate 	}
791*0Sstevel@tonic-gate 	if (len == 0 && rmsg) {
792*0Sstevel@tonic-gate 		Free(rmsg);
793*0Sstevel@tonic-gate 		rmsg = NULL;
794*0Sstevel@tonic-gate 	}
795*0Sstevel@tonic-gate 
796*0Sstevel@tonic-gate 	return (rmsg);
797*0Sstevel@tonic-gate }
798*0Sstevel@tonic-gate 
799*0Sstevel@tonic-gate /*
800*0Sstevel@tonic-gate  * printable log state
801*0Sstevel@tonic-gate  */
802*0Sstevel@tonic-gate char *
803*0Sstevel@tonic-gate mt_l_error_to_name(
804*0Sstevel@tonic-gate 	md_trans_t	*transp,
805*0Sstevel@tonic-gate 	md_timeval32_t	*tvp,
806*0Sstevel@tonic-gate 	uint_t		tstate	/* Errored tstate flags */
807*0Sstevel@tonic-gate )
808*0Sstevel@tonic-gate {
809*0Sstevel@tonic-gate 	mt_l_error_t	log_error = transp->log_error;
810*0Sstevel@tonic-gate 
811*0Sstevel@tonic-gate 	/* grab time */
812*0Sstevel@tonic-gate 	if (tvp != NULL)
813*0Sstevel@tonic-gate 		*tvp = transp->log_timestamp;
814*0Sstevel@tonic-gate 
815*0Sstevel@tonic-gate 	if (tstate != 0) {
816*0Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Unavailable"));
817*0Sstevel@tonic-gate 	}
818*0Sstevel@tonic-gate 
819*0Sstevel@tonic-gate 	/* return state */
820*0Sstevel@tonic-gate 	if (log_error & LDL_ERROR) {
821*0Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Error"));
822*0Sstevel@tonic-gate 	} else if (log_error & LDL_HERROR) {
823*0Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Hard Error"));
824*0Sstevel@tonic-gate 	} else {
825*0Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Okay"));
826*0Sstevel@tonic-gate 	}
827*0Sstevel@tonic-gate }
828*0Sstevel@tonic-gate 
829*0Sstevel@tonic-gate /*
830*0Sstevel@tonic-gate  * printable trans state
831*0Sstevel@tonic-gate  */
832*0Sstevel@tonic-gate char *
833*0Sstevel@tonic-gate mt_flags_to_name(
834*0Sstevel@tonic-gate 	md_trans_t	*transp,
835*0Sstevel@tonic-gate 	md_timeval32_t	*tvp,
836*0Sstevel@tonic-gate 	uint_t		tstate	/* Errored tstate flags */
837*0Sstevel@tonic-gate )
838*0Sstevel@tonic-gate {
839*0Sstevel@tonic-gate 	/* grab time */
840*0Sstevel@tonic-gate 	if (tvp != NULL)
841*0Sstevel@tonic-gate 		*tvp = transp->timestamp;
842*0Sstevel@tonic-gate 
843*0Sstevel@tonic-gate 	if (tstate != 0) {
844*0Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Unavailable"));
845*0Sstevel@tonic-gate 	}
846*0Sstevel@tonic-gate 
847*0Sstevel@tonic-gate 	/* return state */
848*0Sstevel@tonic-gate 	if (transp->flags & TRANS_DETACHED)
849*0Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Detached"));
850*0Sstevel@tonic-gate 	else if (transp->flags & TRANS_DETACHING)
851*0Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Detaching"));
852*0Sstevel@tonic-gate 	else if (transp->flags & TRANS_ATTACHING)
853*0Sstevel@tonic-gate 		return (dgettext(TEXT_DOMAIN, "Attaching"));
854*0Sstevel@tonic-gate 	return (mt_l_error_to_name(transp, tvp, tstate));
855*0Sstevel@tonic-gate }
856*0Sstevel@tonic-gate 
857*0Sstevel@tonic-gate /*
858*0Sstevel@tonic-gate  * report trans
859*0Sstevel@tonic-gate  */
860*0Sstevel@tonic-gate static int
861*0Sstevel@tonic-gate trans_report(
862*0Sstevel@tonic-gate 	mdsetname_t	*sp,
863*0Sstevel@tonic-gate 	md_trans_t	*transp,
864*0Sstevel@tonic-gate 	char		*fname,
865*0Sstevel@tonic-gate 	FILE		*fp,
866*0Sstevel@tonic-gate 	mdprtopts_t	options,
867*0Sstevel@tonic-gate 	md_error_t	*ep
868*0Sstevel@tonic-gate )
869*0Sstevel@tonic-gate {
870*0Sstevel@tonic-gate 	char		*mt_state;
871*0Sstevel@tonic-gate 	md_timeval32_t	tv;
872*0Sstevel@tonic-gate 	char		*timep;
873*0Sstevel@tonic-gate 	int		rval = -1;
874*0Sstevel@tonic-gate 	char		*actionp = NULL;
875*0Sstevel@tonic-gate 	char 		*devid = "";
876*0Sstevel@tonic-gate 	mdname_t	*didnp = NULL;
877*0Sstevel@tonic-gate 	ddi_devid_t	dtp;
878*0Sstevel@tonic-gate 	uint_t		tstate = 0;
879*0Sstevel@tonic-gate 
880*0Sstevel@tonic-gate 	/* print header */
881*0Sstevel@tonic-gate 	if (options & PRINT_HEADER) {
882*0Sstevel@tonic-gate 		if (fprintf(fp, dgettext(TEXT_DOMAIN, "%s: Trans"
883*0Sstevel@tonic-gate 		    " (Feature replaced see message below)\n"),
884*0Sstevel@tonic-gate 		    transp->common.namep->cname) == EOF) {
885*0Sstevel@tonic-gate 			goto out;
886*0Sstevel@tonic-gate 		}
887*0Sstevel@tonic-gate 	}
888*0Sstevel@tonic-gate 
889*0Sstevel@tonic-gate 	/* print state */
890*0Sstevel@tonic-gate 	if (metaismeta(transp->common.namep)) {
891*0Sstevel@tonic-gate 		if (meta_get_tstate(transp->common.namep->dev, &tstate, ep)
892*0Sstevel@tonic-gate 		    != 0)
893*0Sstevel@tonic-gate 			goto out;
894*0Sstevel@tonic-gate 	}
895*0Sstevel@tonic-gate 	mt_state = mt_flags_to_name(transp, &tv, tstate & MD_DEV_ERRORED);
896*0Sstevel@tonic-gate 	if (options & PRINT_TIMES) {
897*0Sstevel@tonic-gate 		timep = meta_print_time(&tv);
898*0Sstevel@tonic-gate 	} else {
899*0Sstevel@tonic-gate 		timep = "";
900*0Sstevel@tonic-gate 	}
901*0Sstevel@tonic-gate 	if (fprintf(fp, dgettext(TEXT_DOMAIN, "    State: %-12s %s\n"),
902*0Sstevel@tonic-gate 	    mt_state, timep) == EOF) {
903*0Sstevel@tonic-gate 		goto out;
904*0Sstevel@tonic-gate 	}
905*0Sstevel@tonic-gate 
906*0Sstevel@tonic-gate 	if ((tstate & MD_DEV_ERRORED) == 0) {
907*0Sstevel@tonic-gate 		actionp = mt_flags_to_action(transp);
908*0Sstevel@tonic-gate 		if (actionp) {
909*0Sstevel@tonic-gate 			if (fprintf(fp, "%s", actionp) == EOF) {
910*0Sstevel@tonic-gate 				goto out;
911*0Sstevel@tonic-gate 			}
912*0Sstevel@tonic-gate 			Free(actionp);
913*0Sstevel@tonic-gate 			actionp = NULL;
914*0Sstevel@tonic-gate 		}
915*0Sstevel@tonic-gate 	}
916*0Sstevel@tonic-gate 
917*0Sstevel@tonic-gate 	/* debug stuff */
918*0Sstevel@tonic-gate 	if (transp->debug) {
919*0Sstevel@tonic-gate 		if (fprintf(fp,
920*0Sstevel@tonic-gate 		    "    Debug Modes:%s%s%s%s%s%s%s%s%s%s%s\n",
921*0Sstevel@tonic-gate 		    (transp->debug & MT_TRANSACT) ? " TRANSACT" : "",
922*0Sstevel@tonic-gate 		    (transp->debug & MT_MATAMAP) ? " METADATA" : "",
923*0Sstevel@tonic-gate 		    (transp->debug & MT_WRITE_CHECK) ?  " WRITES" : "",
924*0Sstevel@tonic-gate 		    (transp->debug & MT_LOG_WRITE_CHECK) ? " LOGWRITES" : "",
925*0Sstevel@tonic-gate 		    (transp->debug & MT_CHECK_MAP) ? " MAP" : "",
926*0Sstevel@tonic-gate 		    (transp->debug & MT_TRACE) ? " TRACE" : "",
927*0Sstevel@tonic-gate 		    (transp->debug & MT_SIZE) ? " SIZE" : "",
928*0Sstevel@tonic-gate 		    (transp->debug & MT_NOASYNC) ? " NOASYNC" : "",
929*0Sstevel@tonic-gate 		    (transp->debug & MT_FORCEROLL) ? " FORCEROLL" : "",
930*0Sstevel@tonic-gate 		    (transp->debug & MT_SCAN) ? " SCAN" : "",
931*0Sstevel@tonic-gate 		    (transp->debug & MT_PREWRITE) ? " PREWRITE" : "")
932*0Sstevel@tonic-gate 		    == EOF) {
933*0Sstevel@tonic-gate 			goto out;
934*0Sstevel@tonic-gate 		}
935*0Sstevel@tonic-gate 	}
936*0Sstevel@tonic-gate 
937*0Sstevel@tonic-gate 	/* print size */
938*0Sstevel@tonic-gate 	if (fprintf(fp, dgettext(TEXT_DOMAIN, "    Size: %lld blocks (%s)\n"),
939*0Sstevel@tonic-gate 	    transp->common.size,
940*0Sstevel@tonic-gate 	    meta_number_to_string(transp->common.size, DEV_BSIZE)) == EOF) {
941*0Sstevel@tonic-gate 		goto out;
942*0Sstevel@tonic-gate 	}
943*0Sstevel@tonic-gate 
944*0Sstevel@tonic-gate 
945*0Sstevel@tonic-gate 	/* print master */
946*0Sstevel@tonic-gate 	if (fprintf(fp, dgettext(TEXT_DOMAIN, "    Master Device: %s\n"),
947*0Sstevel@tonic-gate 	    transp->masternamep->cname) == EOF) {
948*0Sstevel@tonic-gate 		goto out;
949*0Sstevel@tonic-gate 	}
950*0Sstevel@tonic-gate 
951*0Sstevel@tonic-gate 	/* print log */
952*0Sstevel@tonic-gate 	if (transp->lognamep != NULL) {
953*0Sstevel@tonic-gate 		if (fprintf(fp, dgettext(TEXT_DOMAIN,
954*0Sstevel@tonic-gate 		    "    Logging Device: %s\n"),
955*0Sstevel@tonic-gate 		    transp->lognamep->cname) == EOF) {
956*0Sstevel@tonic-gate 			goto out;
957*0Sstevel@tonic-gate 		}
958*0Sstevel@tonic-gate 	}
959*0Sstevel@tonic-gate 
960*0Sstevel@tonic-gate 	/* add extra line */
961*0Sstevel@tonic-gate 	if (fprintf(fp, "\n") == EOF)
962*0Sstevel@tonic-gate 		goto out;
963*0Sstevel@tonic-gate 
964*0Sstevel@tonic-gate 	/* print master details if regular device */
965*0Sstevel@tonic-gate 	if (! metaismeta(transp->masternamep)) {
966*0Sstevel@tonic-gate 		daddr_t	start_blk = 0;
967*0Sstevel@tonic-gate 		char	*has_mddb_str = dgettext(TEXT_DOMAIN, "No");
968*0Sstevel@tonic-gate 		int	len;
969*0Sstevel@tonic-gate 
970*0Sstevel@tonic-gate 		/*
971*0Sstevel@tonic-gate 		 * Building a format string on the fly that will
972*0Sstevel@tonic-gate 		 * be used in (f)printf. This allows the length
973*0Sstevel@tonic-gate 		 * of the ctd to vary from small to large without
974*0Sstevel@tonic-gate 		 * looking horrible.
975*0Sstevel@tonic-gate 		 */
976*0Sstevel@tonic-gate 		len = strlen(transp->masternamep->cname) + 2;
977*0Sstevel@tonic-gate 		len = max(len, strlen(dgettext(TEXT_DOMAIN, "Master Device")));
978*0Sstevel@tonic-gate 
979*0Sstevel@tonic-gate 		/* print header */
980*0Sstevel@tonic-gate 		if (fprintf(fp,
981*0Sstevel@tonic-gate 		    "\t%-*.*s %-12.12s %-5.5s %s\n",
982*0Sstevel@tonic-gate 		    len, len,
983*0Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Master Device"),
984*0Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Start Block"),
985*0Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Dbase"),
986*0Sstevel@tonic-gate 			dgettext(TEXT_DOMAIN, "Reloc")) == EOF) {
987*0Sstevel@tonic-gate 			goto out;
988*0Sstevel@tonic-gate 		}
989*0Sstevel@tonic-gate 
990*0Sstevel@tonic-gate 		/* populate the key in the name_p structure */
991*0Sstevel@tonic-gate 		if ((didnp = metadevname(&sp,
992*0Sstevel@tonic-gate 				transp->masternamep->dev, ep)) == NULL) {
993*0Sstevel@tonic-gate 			return (-1);
994*0Sstevel@tonic-gate 		}
995*0Sstevel@tonic-gate 
996*0Sstevel@tonic-gate 	    /* determine if devid does NOT exist */
997*0Sstevel@tonic-gate 		if (options & PRINT_DEVID)
998*0Sstevel@tonic-gate 		    if ((dtp = meta_getdidbykey(sp->setno, getmyside(sp, ep),
999*0Sstevel@tonic-gate 					didnp->key, ep)) == NULL)
1000*0Sstevel@tonic-gate 				devid = dgettext(TEXT_DOMAIN, "No ");
1001*0Sstevel@tonic-gate 			else {
1002*0Sstevel@tonic-gate 				devid = dgettext(TEXT_DOMAIN, "Yes");
1003*0Sstevel@tonic-gate 				free(dtp);
1004*0Sstevel@tonic-gate 			}
1005*0Sstevel@tonic-gate 
1006*0Sstevel@tonic-gate 		/* print info */
1007*0Sstevel@tonic-gate 		/*
1008*0Sstevel@tonic-gate 		 * This allows the length
1009*0Sstevel@tonic-gate 		 * of the ctd to vary from small to large without
1010*0Sstevel@tonic-gate 		 * looking horrible.
1011*0Sstevel@tonic-gate 		 */
1012*0Sstevel@tonic-gate 		if (fprintf(fp, "\t%-*s %8ld     %-5.5s %s\n", len,
1013*0Sstevel@tonic-gate 		    transp->masternamep->cname,
1014*0Sstevel@tonic-gate 		    start_blk, has_mddb_str, devid) == EOF) {
1015*0Sstevel@tonic-gate 			goto out;
1016*0Sstevel@tonic-gate 		}
1017*0Sstevel@tonic-gate 		/* add extra line */
1018*0Sstevel@tonic-gate 		if (fprintf(fp, "\n") == EOF)
1019*0Sstevel@tonic-gate 			goto out;
1020*0Sstevel@tonic-gate 	}
1021*0Sstevel@tonic-gate 
1022*0Sstevel@tonic-gate 	/* success */
1023*0Sstevel@tonic-gate 	rval = 0;
1024*0Sstevel@tonic-gate 
1025*0Sstevel@tonic-gate 	/* cleanup, return error */
1026*0Sstevel@tonic-gate out:
1027*0Sstevel@tonic-gate 	if (rval != 0)
1028*0Sstevel@tonic-gate 		(void) mdsyserror(ep, errno, fname);
1029*0Sstevel@tonic-gate 	return (rval);
1030*0Sstevel@tonic-gate }
1031*0Sstevel@tonic-gate 
1032*0Sstevel@tonic-gate /*
1033*0Sstevel@tonic-gate  * print/report trans
1034*0Sstevel@tonic-gate  */
1035*0Sstevel@tonic-gate int
1036*0Sstevel@tonic-gate meta_trans_print(
1037*0Sstevel@tonic-gate 	mdsetname_t	*sp,
1038*0Sstevel@tonic-gate 	mdname_t	*transnp,
1039*0Sstevel@tonic-gate 	mdnamelist_t	**nlistpp,
1040*0Sstevel@tonic-gate 	char		*fname,
1041*0Sstevel@tonic-gate 	FILE		*fp,
1042*0Sstevel@tonic-gate 	mdprtopts_t	options,
1043*0Sstevel@tonic-gate 	int		*meta_print_trans_msgp, /* NULL if transnp != NULL */
1044*0Sstevel@tonic-gate 	mdnamelist_t	**lognlpp,
1045*0Sstevel@tonic-gate 	md_error_t	*ep
1046*0Sstevel@tonic-gate )
1047*0Sstevel@tonic-gate {
1048*0Sstevel@tonic-gate 	md_trans_t	*transp;
1049*0Sstevel@tonic-gate 	mdname_t	*lognamep;
1050*0Sstevel@tonic-gate 
1051*0Sstevel@tonic-gate 	/* should have same set */
1052*0Sstevel@tonic-gate 	assert(sp != NULL);
1053*0Sstevel@tonic-gate 
1054*0Sstevel@tonic-gate 	/* print all transs */
1055*0Sstevel@tonic-gate 	if (transnp == NULL) {
1056*0Sstevel@tonic-gate 		mdnamelist_t	*nlp = NULL;
1057*0Sstevel@tonic-gate 		mdnamelist_t	*p;
1058*0Sstevel@tonic-gate 		int		cnt;
1059*0Sstevel@tonic-gate 		int		rval = 0;
1060*0Sstevel@tonic-gate 
1061*0Sstevel@tonic-gate 		/* get list */
1062*0Sstevel@tonic-gate 		if ((cnt = meta_get_trans_names(sp, &nlp, options, ep)) < 0)
1063*0Sstevel@tonic-gate 			return (-1);
1064*0Sstevel@tonic-gate 		else if (cnt == 0)
1065*0Sstevel@tonic-gate 			return (0);
1066*0Sstevel@tonic-gate 
1067*0Sstevel@tonic-gate 		/* recurse */
1068*0Sstevel@tonic-gate 		for (p = nlp; (p != NULL); p = p->next) {
1069*0Sstevel@tonic-gate 			mdname_t	*np = p->namep;
1070*0Sstevel@tonic-gate 
1071*0Sstevel@tonic-gate 			if (meta_trans_print(sp, np, nlistpp, fname, fp,
1072*0Sstevel@tonic-gate 			    options, meta_print_trans_msgp, lognlpp, ep) != 0)
1073*0Sstevel@tonic-gate 				rval = -1;
1074*0Sstevel@tonic-gate 		}
1075*0Sstevel@tonic-gate 
1076*0Sstevel@tonic-gate 		if (meta_print_trans_msgp)
1077*0Sstevel@tonic-gate 			*meta_print_trans_msgp = 1;
1078*0Sstevel@tonic-gate 
1079*0Sstevel@tonic-gate 		/* cleanup, return success */
1080*0Sstevel@tonic-gate 		metafreenamelist(nlp);
1081*0Sstevel@tonic-gate 		return (rval);
1082*0Sstevel@tonic-gate 	}
1083*0Sstevel@tonic-gate 
1084*0Sstevel@tonic-gate 
1085*0Sstevel@tonic-gate 	/* get unit structure */
1086*0Sstevel@tonic-gate 	if ((transp = meta_get_trans_common(sp, transnp,
1087*0Sstevel@tonic-gate 	    ((options & PRINT_FAST) ? 1 : 0), ep)) == NULL)
1088*0Sstevel@tonic-gate 		return (-1);
1089*0Sstevel@tonic-gate 
1090*0Sstevel@tonic-gate 	/* save unique log */
1091*0Sstevel@tonic-gate 	if ((lognlpp != NULL) &&
1092*0Sstevel@tonic-gate 	    ((lognamep = transp->lognamep) != NULL)) {
1093*0Sstevel@tonic-gate 		mdnamelist_t	*p;
1094*0Sstevel@tonic-gate 
1095*0Sstevel@tonic-gate 		for (p = *lognlpp; (p != NULL); p = p->next) {
1096*0Sstevel@tonic-gate 			if (strcmp(lognamep->bname, p->namep->bname) == 0)
1097*0Sstevel@tonic-gate 				break;
1098*0Sstevel@tonic-gate 		}
1099*0Sstevel@tonic-gate 		if (p == NULL)
1100*0Sstevel@tonic-gate 			(void) metanamelist_append(lognlpp, lognamep);
1101*0Sstevel@tonic-gate 	}
1102*0Sstevel@tonic-gate 
1103*0Sstevel@tonic-gate 	/* check for parented */
1104*0Sstevel@tonic-gate 	if ((! (options & PRINT_SUBDEVS)) &&
1105*0Sstevel@tonic-gate 	    (MD_HAS_PARENT(transp->common.parent))) {
1106*0Sstevel@tonic-gate 		return (0);
1107*0Sstevel@tonic-gate 	}
1108*0Sstevel@tonic-gate 
1109*0Sstevel@tonic-gate 	/* can't have a large trans */
1110*0Sstevel@tonic-gate 	if (!(options & PRINT_LARGEDEVICES)) {
1111*0Sstevel@tonic-gate 		/* print appropriate detail */
1112*0Sstevel@tonic-gate 		if (options & PRINT_SHORT) {
1113*0Sstevel@tonic-gate 			if (trans_print(transp, fname, fp, ep) != 0)
1114*0Sstevel@tonic-gate 				return (-1);
1115*0Sstevel@tonic-gate 		} else {
1116*0Sstevel@tonic-gate 			if (trans_report(sp, transp, fname, fp, options, ep)
1117*0Sstevel@tonic-gate 			    != 0)
1118*0Sstevel@tonic-gate 				return (-1);
1119*0Sstevel@tonic-gate 		}
1120*0Sstevel@tonic-gate 	}
1121*0Sstevel@tonic-gate 
1122*0Sstevel@tonic-gate 	/* print underlying metadevices, log is later */
1123*0Sstevel@tonic-gate 	if (metaismeta(transp->masternamep)) {
1124*0Sstevel@tonic-gate 		if (meta_print_name(sp, transp->masternamep, nlistpp, fname,
1125*0Sstevel@tonic-gate 		    fp, (options | PRINT_HEADER | PRINT_SUBDEVS), NULL, ep)
1126*0Sstevel@tonic-gate 		    != 0) {
1127*0Sstevel@tonic-gate 			return (-1);
1128*0Sstevel@tonic-gate 		}
1129*0Sstevel@tonic-gate 	}
1130*0Sstevel@tonic-gate 
1131*0Sstevel@tonic-gate 	/* return success */
1132*0Sstevel@tonic-gate 	return (0);
1133*0Sstevel@tonic-gate }
1134*0Sstevel@tonic-gate 
1135*0Sstevel@tonic-gate /*
1136*0Sstevel@tonic-gate  * print log
1137*0Sstevel@tonic-gate  */
1138*0Sstevel@tonic-gate static int
1139*0Sstevel@tonic-gate log_print(
1140*0Sstevel@tonic-gate 	mdsetname_t	*sp,
1141*0Sstevel@tonic-gate 	mdname_t	*lognamep,
1142*0Sstevel@tonic-gate 	char		*fname,
1143*0Sstevel@tonic-gate 	FILE		*fp,
1144*0Sstevel@tonic-gate 	mdprtopts_t	options,
1145*0Sstevel@tonic-gate 	md_error_t	*ep
1146*0Sstevel@tonic-gate )
1147*0Sstevel@tonic-gate {
1148*0Sstevel@tonic-gate 	mdnamelist_t	*nlp = NULL;
1149*0Sstevel@tonic-gate 
1150*0Sstevel@tonic-gate 	/* metadevice info */
1151*0Sstevel@tonic-gate 	if (metaismeta(lognamep)) {
1152*0Sstevel@tonic-gate 		return (meta_print_name(sp, lognamep, &nlp, fname, fp,
1153*0Sstevel@tonic-gate 		    options, NULL, ep));
1154*0Sstevel@tonic-gate 	}
1155*0Sstevel@tonic-gate 
1156*0Sstevel@tonic-gate 	/* regular device info */
1157*0Sstevel@tonic-gate 	return (0);
1158*0Sstevel@tonic-gate }
1159*0Sstevel@tonic-gate 
1160*0Sstevel@tonic-gate /*
1161*0Sstevel@tonic-gate  * report log
1162*0Sstevel@tonic-gate  */
1163*0Sstevel@tonic-gate static int
1164*0Sstevel@tonic-gate log_report(
1165*0Sstevel@tonic-gate 	mdsetname_t	*sp,
1166*0Sstevel@tonic-gate 	mdname_t	*lognamep,
1167*0Sstevel@tonic-gate 	mdnamelist_t	**nlistpp,
1168*0Sstevel@tonic-gate 	char		*fname,
1169*0Sstevel@tonic-gate 	FILE		*fp,
1170*0Sstevel@tonic-gate 	mdprtopts_t	options,
1171*0Sstevel@tonic-gate 	mdnamelist_t	*transnlp,
1172*0Sstevel@tonic-gate 	md_error_t	*ep
1173*0Sstevel@tonic-gate )
1174*0Sstevel@tonic-gate {
1175*0Sstevel@tonic-gate 	md_trans_t	*transp = NULL;
1176*0Sstevel@tonic-gate 	mdnamelist_t	*p;
1177*0Sstevel@tonic-gate 	char		*ml_state;
1178*0Sstevel@tonic-gate 	md_timeval32_t	tv;
1179*0Sstevel@tonic-gate 	char		*timep;
1180*0Sstevel@tonic-gate 	char		*actionp = NULL;
1181*0Sstevel@tonic-gate 	int		rval = -1;
1182*0Sstevel@tonic-gate 	char		*devid = " ";
1183*0Sstevel@tonic-gate 	mdname_t	*didnp = NULL;
1184*0Sstevel@tonic-gate 	ddi_devid_t	dtp;
1185*0Sstevel@tonic-gate 	uint_t		tstate = 0;
1186*0Sstevel@tonic-gate 
1187*0Sstevel@tonic-gate 	for (p = transnlp; (p != NULL); p = p->next) {
1188*0Sstevel@tonic-gate 		md_trans_t	*tp;
1189*0Sstevel@tonic-gate 
1190*0Sstevel@tonic-gate 		if ((tp = meta_get_trans(sp, p->namep, ep)) == NULL)
1191*0Sstevel@tonic-gate 			return (-1);
1192*0Sstevel@tonic-gate 		if ((tp->lognamep != NULL) &&
1193*0Sstevel@tonic-gate 		    (strcmp(lognamep->bname, tp->lognamep->bname) == 0)) {
1194*0Sstevel@tonic-gate 			transp = tp;	/* save any parent trans */
1195*0Sstevel@tonic-gate 		}
1196*0Sstevel@tonic-gate 	}
1197*0Sstevel@tonic-gate 
1198*0Sstevel@tonic-gate 	/* we must have at least one trans */
1199*0Sstevel@tonic-gate 	assert(transp != NULL);
1200*0Sstevel@tonic-gate 	if (transp == NULL) {
1201*0Sstevel@tonic-gate 		rval = 0;
1202*0Sstevel@tonic-gate 		goto out;
1203*0Sstevel@tonic-gate 	}
1204*0Sstevel@tonic-gate 
1205*0Sstevel@tonic-gate 	if ((options & PRINT_LARGEDEVICES) &&
1206*0Sstevel@tonic-gate 	    (transp->log_size <= MD_MAX_BLKS_FOR_SMALL_DEVS)) {
1207*0Sstevel@tonic-gate 		rval = 0;
1208*0Sstevel@tonic-gate 		goto out;
1209*0Sstevel@tonic-gate 	}
1210*0Sstevel@tonic-gate 
1211*0Sstevel@tonic-gate 	/* print header and trans devices, collect log_error and size */
1212*0Sstevel@tonic-gate 	if (fprintf(fp, dgettext(TEXT_DOMAIN, "%s: Logging device for"),
1213*0Sstevel@tonic-gate 	    lognamep->cname) == EOF) {
1214*0Sstevel@tonic-gate 		goto out;
1215*0Sstevel@tonic-gate 	}
1216*0Sstevel@tonic-gate 
1217*0Sstevel@tonic-gate 	if ((transp->lognamep != NULL) &&
1218*0Sstevel@tonic-gate 	    (strcmp(lognamep->bname, transp->lognamep->bname) == 0)) {
1219*0Sstevel@tonic-gate 		if (fprintf(fp, " %s", transp->common.namep->cname)
1220*0Sstevel@tonic-gate 		    == EOF) {
1221*0Sstevel@tonic-gate 			goto out;
1222*0Sstevel@tonic-gate 		}
1223*0Sstevel@tonic-gate 	}
1224*0Sstevel@tonic-gate 	if (fprintf(fp, "\n") == EOF)
1225*0Sstevel@tonic-gate 		goto out;
1226*0Sstevel@tonic-gate 
1227*0Sstevel@tonic-gate 	/* print state */
1228*0Sstevel@tonic-gate 	if (metaismeta(transp->lognamep)) {
1229*0Sstevel@tonic-gate 		if (meta_get_tstate(transp->lognamep->dev, &tstate, ep) != 0)
1230*0Sstevel@tonic-gate 			return (-1);
1231*0Sstevel@tonic-gate 	}
1232*0Sstevel@tonic-gate 	ml_state = mt_l_error_to_name(transp, &tv, tstate & MD_DEV_ERRORED);
1233*0Sstevel@tonic-gate 	if (options & PRINT_TIMES) {
1234*0Sstevel@tonic-gate 		timep = meta_print_time(&tv);
1235*0Sstevel@tonic-gate 	} else {
1236*0Sstevel@tonic-gate 		timep = "";
1237*0Sstevel@tonic-gate 	}
1238*0Sstevel@tonic-gate 	if (fprintf(fp, dgettext(TEXT_DOMAIN, "    State: %-12s %s\n"),
1239*0Sstevel@tonic-gate 	    ml_state, timep) == EOF) {
1240*0Sstevel@tonic-gate 		goto out;
1241*0Sstevel@tonic-gate 	}
1242*0Sstevel@tonic-gate 
1243*0Sstevel@tonic-gate 	if ((tstate & MD_DEV_ERRORED) == 0) {
1244*0Sstevel@tonic-gate 		actionp = mt_l_error_to_action(sp, transnlp, lognamep, ep);
1245*0Sstevel@tonic-gate 		if (actionp) {
1246*0Sstevel@tonic-gate 			if (fprintf(fp, dgettext(TEXT_DOMAIN,
1247*0Sstevel@tonic-gate 			    "    Invoke: %s\n"), actionp) == EOF) {
1248*0Sstevel@tonic-gate 				goto out;
1249*0Sstevel@tonic-gate 			}
1250*0Sstevel@tonic-gate 			Free(actionp);
1251*0Sstevel@tonic-gate 			actionp = NULL;
1252*0Sstevel@tonic-gate 		}
1253*0Sstevel@tonic-gate 	}
1254*0Sstevel@tonic-gate 
1255*0Sstevel@tonic-gate 	/* print size */
1256*0Sstevel@tonic-gate 	if (fprintf(fp, dgettext(TEXT_DOMAIN, "    Size: %ld blocks (%s)\n"),
1257*0Sstevel@tonic-gate 	    transp->log_size,
1258*0Sstevel@tonic-gate 	    meta_number_to_string(transp->log_size, DEV_BSIZE)) == EOF) {
1259*0Sstevel@tonic-gate 		goto out;
1260*0Sstevel@tonic-gate 	}
1261*0Sstevel@tonic-gate 
1262*0Sstevel@tonic-gate 	/* MD_DEBUG stuff */
1263*0Sstevel@tonic-gate 	if (options & PRINT_DEBUG) {
1264*0Sstevel@tonic-gate 		mdname_t	*transnp = transp->common.namep;
1265*0Sstevel@tonic-gate 		mt_unit_t	*mt;
1266*0Sstevel@tonic-gate 		daddr_t		blksinuse, head, tail, nblks, eblk, sblk;
1267*0Sstevel@tonic-gate 		int		percent;
1268*0Sstevel@tonic-gate 
1269*0Sstevel@tonic-gate 		if ((mt = (mt_unit_t *)meta_get_mdunit(sp, transnp, ep))
1270*0Sstevel@tonic-gate 		    == NULL) {
1271*0Sstevel@tonic-gate 			return (-1);
1272*0Sstevel@tonic-gate 		}
1273*0Sstevel@tonic-gate 		assert(mt->c.un_type == MD_METATRANS);
1274*0Sstevel@tonic-gate 
1275*0Sstevel@tonic-gate 		if (fprintf(fp, dgettext(TEXT_DOMAIN,
1276*0Sstevel@tonic-gate 		    "    Transfer Size: %d blocks\n"),
1277*0Sstevel@tonic-gate 		    mt->un_l_maxtransfer) == EOF) {
1278*0Sstevel@tonic-gate 			Free(mt);
1279*0Sstevel@tonic-gate 			goto out;
1280*0Sstevel@tonic-gate 		}
1281*0Sstevel@tonic-gate 
1282*0Sstevel@tonic-gate 		head = mt->un_l_head;
1283*0Sstevel@tonic-gate 		tail = mt->un_l_tail;
1284*0Sstevel@tonic-gate 		sblk = mt->un_l_sblk;
1285*0Sstevel@tonic-gate 		nblks = mt->un_l_nblks;
1286*0Sstevel@tonic-gate 		eblk = sblk + nblks;
1287*0Sstevel@tonic-gate 		if (head <= tail)
1288*0Sstevel@tonic-gate 			blksinuse = tail - head;
1289*0Sstevel@tonic-gate 		else
1290*0Sstevel@tonic-gate 			blksinuse = (eblk - head) + (tail - sblk);
1291*0Sstevel@tonic-gate 
1292*0Sstevel@tonic-gate 		percent = ((u_longlong_t)blksinuse * 100) / nblks;
1293*0Sstevel@tonic-gate 		if (fprintf(fp, dgettext(TEXT_DOMAIN,
1294*0Sstevel@tonic-gate 		    "    Full: %d%% (%ld of %ld blocks)\n"),
1295*0Sstevel@tonic-gate 		    percent, blksinuse, nblks) == EOF) {
1296*0Sstevel@tonic-gate 			Free(mt);
1297*0Sstevel@tonic-gate 			goto out;
1298*0Sstevel@tonic-gate 		}
1299*0Sstevel@tonic-gate 
1300*0Sstevel@tonic-gate 		percent = ((u_longlong_t)mt->un_l_resv * 100) /
1301*0Sstevel@tonic-gate 		    mt->un_l_maxresv;
1302*0Sstevel@tonic-gate 		if (fprintf(fp, dgettext(TEXT_DOMAIN,
1303*0Sstevel@tonic-gate 		    "    Reserved: %d%% (%ud of %ud bytes)\n"),
1304*0Sstevel@tonic-gate 		    percent, mt->un_l_resv, mt->un_l_maxresv) == EOF) {
1305*0Sstevel@tonic-gate 			Free(mt);
1306*0Sstevel@tonic-gate 			goto out;
1307*0Sstevel@tonic-gate 		}
1308*0Sstevel@tonic-gate 		Free(mt);
1309*0Sstevel@tonic-gate 	}
1310*0Sstevel@tonic-gate 
1311*0Sstevel@tonic-gate 	/* add extra line */
1312*0Sstevel@tonic-gate 	if (fprintf(fp, "\n") == EOF)
1313*0Sstevel@tonic-gate 		goto out;
1314*0Sstevel@tonic-gate 
1315*0Sstevel@tonic-gate 	/* print log details */
1316*0Sstevel@tonic-gate 	if (metaismeta(lognamep)) {
1317*0Sstevel@tonic-gate 		if (meta_print_name(sp, lognamep, nlistpp, fname, fp,
1318*0Sstevel@tonic-gate 		    options, NULL, ep) != 0) {
1319*0Sstevel@tonic-gate 			return (-1);
1320*0Sstevel@tonic-gate 		}
1321*0Sstevel@tonic-gate 	} else {
1322*0Sstevel@tonic-gate 		daddr_t		start_blk;
1323*0Sstevel@tonic-gate 		int		has_mddb;
1324*0Sstevel@tonic-gate 		char		*has_mddb_str;
1325*0Sstevel@tonic-gate 		int		len;
1326*0Sstevel@tonic-gate 
1327*0Sstevel@tonic-gate 		/*
1328*0Sstevel@tonic-gate 		 * Building a format string on the fly that will
1329*0Sstevel@tonic-gate 		 * be used in (f)printf. This allows the length
1330*0Sstevel@tonic-gate 		 * of the ctd to vary from small to large without
1331*0Sstevel@tonic-gate 		 * looking horrible.
1332*0Sstevel@tonic-gate 		 */
1333*0Sstevel@tonic-gate 		len = strlen(lognamep->cname) + 2;
1334*0Sstevel@tonic-gate 		len = max(len, strlen(dgettext(TEXT_DOMAIN, "Logging Device")));
1335*0Sstevel@tonic-gate 		/* print header */
1336*0Sstevel@tonic-gate 		if (fprintf(fp,
1337*0Sstevel@tonic-gate 		    "\t%-*.*s %-12.12s %-5.5s %s\n",
1338*0Sstevel@tonic-gate 		    len, len,
1339*0Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Logging Device"),
1340*0Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Start Block"),
1341*0Sstevel@tonic-gate 		    dgettext(TEXT_DOMAIN, "Dbase"),
1342*0Sstevel@tonic-gate 			dgettext(TEXT_DOMAIN, "Reloc")) == EOF) {
1343*0Sstevel@tonic-gate 			goto out;
1344*0Sstevel@tonic-gate 		}
1345*0Sstevel@tonic-gate 		/* get info */
1346*0Sstevel@tonic-gate 		if ((start_blk = metagetstart(sp, lognamep, ep)) ==
1347*0Sstevel@tonic-gate 		    MD_DISKADDR_ERROR) {
1348*0Sstevel@tonic-gate 			return (-1);
1349*0Sstevel@tonic-gate 		}
1350*0Sstevel@tonic-gate 		if ((has_mddb = metahasmddb(sp, lognamep, ep)) < 0) {
1351*0Sstevel@tonic-gate 			return (-1);
1352*0Sstevel@tonic-gate 		}
1353*0Sstevel@tonic-gate 		if (has_mddb)
1354*0Sstevel@tonic-gate 			has_mddb_str = dgettext(TEXT_DOMAIN, "Yes");
1355*0Sstevel@tonic-gate 		else
1356*0Sstevel@tonic-gate 			has_mddb_str = dgettext(TEXT_DOMAIN, "No");
1357*0Sstevel@tonic-gate 
1358*0Sstevel@tonic-gate 		/* populate the key in the name_p structure */
1359*0Sstevel@tonic-gate 		if ((didnp = metadevname(&sp, lognamep->dev, ep)) == NULL) {
1360*0Sstevel@tonic-gate 			return (-1);
1361*0Sstevel@tonic-gate 		}
1362*0Sstevel@tonic-gate 
1363*0Sstevel@tonic-gate 	    /* determine if devid does NOT exist */
1364*0Sstevel@tonic-gate 		if (options & PRINT_DEVID)
1365*0Sstevel@tonic-gate 		    if ((dtp = meta_getdidbykey(sp->setno, getmyside(sp, ep),
1366*0Sstevel@tonic-gate 					didnp->key, ep)) == NULL)
1367*0Sstevel@tonic-gate 				devid = dgettext(TEXT_DOMAIN, "No ");
1368*0Sstevel@tonic-gate 			else {
1369*0Sstevel@tonic-gate 				devid = dgettext(TEXT_DOMAIN, "Yes");
1370*0Sstevel@tonic-gate 				free(dtp);
1371*0Sstevel@tonic-gate 			}
1372*0Sstevel@tonic-gate 
1373*0Sstevel@tonic-gate 		/* print info */
1374*0Sstevel@tonic-gate 		/*
1375*0Sstevel@tonic-gate 		 * This allows the length
1376*0Sstevel@tonic-gate 		 * of the ctd to vary from small to large without
1377*0Sstevel@tonic-gate 		 * looking horrible.
1378*0Sstevel@tonic-gate 		 */
1379*0Sstevel@tonic-gate 		if (fprintf(fp, "\t%-*s %8ld     %-5.5s %s\n",
1380*0Sstevel@tonic-gate 		    len, lognamep->cname, start_blk,
1381*0Sstevel@tonic-gate 		    has_mddb_str, devid) == EOF) {
1382*0Sstevel@tonic-gate 			goto out;
1383*0Sstevel@tonic-gate 		}
1384*0Sstevel@tonic-gate 	}
1385*0Sstevel@tonic-gate 
1386*0Sstevel@tonic-gate 	/* add extra line */
1387*0Sstevel@tonic-gate 	if (fprintf(fp, "\n") == EOF)
1388*0Sstevel@tonic-gate 		goto out;
1389*0Sstevel@tonic-gate 
1390*0Sstevel@tonic-gate 	/* success */
1391*0Sstevel@tonic-gate 	rval = 0;
1392*0Sstevel@tonic-gate 
1393*0Sstevel@tonic-gate 	/* cleanup, return error */
1394*0Sstevel@tonic-gate out:
1395*0Sstevel@tonic-gate 	if (rval != 0)
1396*0Sstevel@tonic-gate 		(void) mdsyserror(ep, errno, fname);
1397*0Sstevel@tonic-gate 	return (rval);
1398*0Sstevel@tonic-gate }
1399*0Sstevel@tonic-gate 
1400*0Sstevel@tonic-gate /*
1401*0Sstevel@tonic-gate  * print/report logs
1402*0Sstevel@tonic-gate  */
1403*0Sstevel@tonic-gate int
1404*0Sstevel@tonic-gate meta_logs_print(
1405*0Sstevel@tonic-gate 	mdsetname_t	*sp,
1406*0Sstevel@tonic-gate 	mdnamelist_t	*lognlp,
1407*0Sstevel@tonic-gate 	mdnamelist_t	**nlistpp,
1408*0Sstevel@tonic-gate 	char		*fname,
1409*0Sstevel@tonic-gate 	FILE		*fp,
1410*0Sstevel@tonic-gate 	mdprtopts_t	options,
1411*0Sstevel@tonic-gate 	md_error_t	*ep
1412*0Sstevel@tonic-gate )
1413*0Sstevel@tonic-gate {
1414*0Sstevel@tonic-gate 	mdnamelist_t	*transnlp = NULL;
1415*0Sstevel@tonic-gate 	mdnamelist_t	*p;
1416*0Sstevel@tonic-gate 	int		rval = 0;
1417*0Sstevel@tonic-gate 
1418*0Sstevel@tonic-gate 	/* must have a set */
1419*0Sstevel@tonic-gate 	assert(sp != NULL);
1420*0Sstevel@tonic-gate 
1421*0Sstevel@tonic-gate 	/* get trans devices */
1422*0Sstevel@tonic-gate 	if (lognlp == NULL)
1423*0Sstevel@tonic-gate 		return (0);
1424*0Sstevel@tonic-gate 
1425*0Sstevel@tonic-gate 	if (! (options & PRINT_SHORT))
1426*0Sstevel@tonic-gate 		if (meta_get_trans_names(sp, &transnlp, options, ep) < 0)
1427*0Sstevel@tonic-gate 			return (-1);
1428*0Sstevel@tonic-gate 
1429*0Sstevel@tonic-gate 	/* print all logs */
1430*0Sstevel@tonic-gate 	options |= PRINT_SUBDEVS;
1431*0Sstevel@tonic-gate 	for (p = lognlp; (p != NULL); p = p->next) {
1432*0Sstevel@tonic-gate 		mdname_t	*lognamep = p->namep;
1433*0Sstevel@tonic-gate 
1434*0Sstevel@tonic-gate 		/* print appropriate detail */
1435*0Sstevel@tonic-gate 		if (options & PRINT_SHORT) {
1436*0Sstevel@tonic-gate 			if (log_print(sp, lognamep, fname, fp, options,
1437*0Sstevel@tonic-gate 			    ep) != 0) {
1438*0Sstevel@tonic-gate 				rval = -1;
1439*0Sstevel@tonic-gate 			}
1440*0Sstevel@tonic-gate 		} else {
1441*0Sstevel@tonic-gate 			if (log_report(sp, lognamep, nlistpp, fname, fp,
1442*0Sstevel@tonic-gate 			    options, transnlp, ep) != 0) {
1443*0Sstevel@tonic-gate 				rval = -1;
1444*0Sstevel@tonic-gate 			}
1445*0Sstevel@tonic-gate 		}
1446*0Sstevel@tonic-gate 	}
1447*0Sstevel@tonic-gate 
1448*0Sstevel@tonic-gate 	/* cleanup, return success */
1449*0Sstevel@tonic-gate out:
1450*0Sstevel@tonic-gate 	metafreenamelist(transnlp);
1451*0Sstevel@tonic-gate 	return (rval);
1452*0Sstevel@tonic-gate }
1453*0Sstevel@tonic-gate 
1454*0Sstevel@tonic-gate /*
1455*0Sstevel@tonic-gate  * meta_lockfs_common -- common lock and unlock code
1456*0Sstevel@tonic-gate  *
1457*0Sstevel@tonic-gate  * Normally this routine will return a 0 for success. Even if
1458*0Sstevel@tonic-gate  * lockfs wasn't able to lock down the filesystem. The reason
1459*0Sstevel@tonic-gate  * for this is that the master device can be in an errored state
1460*0Sstevel@tonic-gate  * and the lock can't be obtained. We don't want to prevent
1461*0Sstevel@tonic-gate  * possible recovery in this case and it's not likely any activity
1462*0Sstevel@tonic-gate  * will be occurring. If the filesystem is healthy with activity
1463*0Sstevel@tonic-gate  * lockfs will successfully lock the filesystem and return an
1464*0Sstevel@tonic-gate  * error code of 0.
1465*0Sstevel@tonic-gate  *
1466*0Sstevel@tonic-gate  * The one case where this routine returns a non-zero value would
1467*0Sstevel@tonic-gate  * be if we can't determine the outcome of the lockfs. This should
1468*0Sstevel@tonic-gate  * never occur because we don't catch signals that could cause
1469*0Sstevel@tonic-gate  * waitpid() to prematurely return.
1470*0Sstevel@tonic-gate  */
1471*0Sstevel@tonic-gate static int
1472*0Sstevel@tonic-gate meta_lockfs_common(mdname_t *fs, void **cookie, int lockit)
1473*0Sstevel@tonic-gate {
1474*0Sstevel@tonic-gate 	char		*blkname;
1475*0Sstevel@tonic-gate 	FILE		*m;
1476*0Sstevel@tonic-gate 	struct mnttab	tab_wildcard, tab_match;
1477*0Sstevel@tonic-gate 	pid_t		pid;
1478*0Sstevel@tonic-gate 	int		lock_exit;
1479*0Sstevel@tonic-gate 
1480*0Sstevel@tonic-gate 	(void) memset(&tab_wildcard, 0, sizeof (tab_wildcard));
1481*0Sstevel@tonic-gate 	(void) memset(&tab_match, 0, sizeof (tab_match));
1482*0Sstevel@tonic-gate 
1483*0Sstevel@tonic-gate 	if ((blkname = fs->bname) == NULL)
1484*0Sstevel@tonic-gate 		blkname = getfullblkname(fs->cname);
1485*0Sstevel@tonic-gate 
1486*0Sstevel@tonic-gate 	tab_wildcard.mnt_special = blkname;
1487*0Sstevel@tonic-gate 
1488*0Sstevel@tonic-gate 	if ((m = fopen(MNTTAB, "r")) == NULL) {
1489*0Sstevel@tonic-gate 		/*
1490*0Sstevel@tonic-gate 		 * No mnttab means nothing is mounted
1491*0Sstevel@tonic-gate 		 */
1492*0Sstevel@tonic-gate 		*cookie = 0;
1493*0Sstevel@tonic-gate 		return (0);
1494*0Sstevel@tonic-gate 	}
1495*0Sstevel@tonic-gate 
1496*0Sstevel@tonic-gate 	if (getmntany(m, &tab_match, &tab_wildcard)) {
1497*0Sstevel@tonic-gate 		/*
1498*0Sstevel@tonic-gate 		 * No match in mnttab so we're not mounted ... at least
1499*0Sstevel@tonic-gate 		 * nothing better be mounted.
1500*0Sstevel@tonic-gate 		 */
1501*0Sstevel@tonic-gate 		*cookie = 0;
1502*0Sstevel@tonic-gate 		return (0);
1503*0Sstevel@tonic-gate 	}
1504*0Sstevel@tonic-gate 
1505*0Sstevel@tonic-gate 	(void) fclose(m);
1506*0Sstevel@tonic-gate 
1507*0Sstevel@tonic-gate 	switch (pid = fork()) {
1508*0Sstevel@tonic-gate 	    case -1:
1509*0Sstevel@tonic-gate 		/*
1510*0Sstevel@tonic-gate 		 * We've got some major trouble here and shouldn't
1511*0Sstevel@tonic-gate 		 * continue. The user needs to clear up the problems
1512*0Sstevel@tonic-gate 		 * that the system currently has before proceeding
1513*0Sstevel@tonic-gate 		 * to detach the log.
1514*0Sstevel@tonic-gate 		 */
1515*0Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN, "failed to fork lockfs\n"));
1516*0Sstevel@tonic-gate 		*cookie = 0;
1517*0Sstevel@tonic-gate 		return (1);
1518*0Sstevel@tonic-gate 
1519*0Sstevel@tonic-gate 	    case 0:
1520*0Sstevel@tonic-gate 		(void) execl("/usr/sbin/lockfs", "lockfs", lockit ? "-w" : "-u",
1521*0Sstevel@tonic-gate 		    "-c", "Solaris Volume Manager detach lock",
1522*0Sstevel@tonic-gate 		    tab_match.mnt_mountp, 0);
1523*0Sstevel@tonic-gate 		/*
1524*0Sstevel@tonic-gate 		 * Shouldn't reach here, but if this code is run on
1525*0Sstevel@tonic-gate 		 * a release that doesn't have lockfs return an error
1526*0Sstevel@tonic-gate 		 * code so that the -f (force) option could be used
1527*0Sstevel@tonic-gate 		 * by metadetach.
1528*0Sstevel@tonic-gate 		 */
1529*0Sstevel@tonic-gate 		exit(1);
1530*0Sstevel@tonic-gate 
1531*0Sstevel@tonic-gate 	    default:
1532*0Sstevel@tonic-gate 		if (waitpid(pid, &lock_exit, 0) != pid) {
1533*0Sstevel@tonic-gate 			/*
1534*0Sstevel@tonic-gate 			 * We couldn't get status regarding the
1535*0Sstevel@tonic-gate 			 * outcome of the lockfs command. We should
1536*0Sstevel@tonic-gate 			 * attempt to unlock the filesystem though.
1537*0Sstevel@tonic-gate 			 * Return an error code so that if the user
1538*0Sstevel@tonic-gate 			 * is trying to force the detach make them
1539*0Sstevel@tonic-gate 			 * clear up this problem first.
1540*0Sstevel@tonic-gate 			 */
1541*0Sstevel@tonic-gate 			*cookie = (void *)1;
1542*0Sstevel@tonic-gate 			return (1);
1543*0Sstevel@tonic-gate 		}
1544*0Sstevel@tonic-gate 
1545*0Sstevel@tonic-gate 		*cookie = (void *)1;
1546*0Sstevel@tonic-gate 		return (0);
1547*0Sstevel@tonic-gate 	}
1548*0Sstevel@tonic-gate }
1549*0Sstevel@tonic-gate 
1550*0Sstevel@tonic-gate /*
1551*0Sstevel@tonic-gate  * meta_lockfs - if mounted, lock a given device against writes
1552*0Sstevel@tonic-gate  *
1553*0Sstevel@tonic-gate  * See comment section for meta_lockfs_common
1554*0Sstevel@tonic-gate  */
1555*0Sstevel@tonic-gate static int
1556*0Sstevel@tonic-gate meta_lockfs(mdname_t *fs, void **cookie)
1557*0Sstevel@tonic-gate {
1558*0Sstevel@tonic-gate 	return (meta_lockfs_common(fs, cookie, 1));
1559*0Sstevel@tonic-gate }
1560*0Sstevel@tonic-gate 
1561*0Sstevel@tonic-gate /*
1562*0Sstevel@tonic-gate  * meta_unlockfs - if mounted, unlock the filesystem if previously locked
1563*0Sstevel@tonic-gate  *
1564*0Sstevel@tonic-gate  * See comment section for meta_lockfs_common
1565*0Sstevel@tonic-gate  */
1566*0Sstevel@tonic-gate static void
1567*0Sstevel@tonic-gate meta_unlockfs(mdname_t *fs, void **cookie)
1568*0Sstevel@tonic-gate {
1569*0Sstevel@tonic-gate 	/*
1570*0Sstevel@tonic-gate 	 * Simple time saver. We could always try to unlock
1571*0Sstevel@tonic-gate 	 * the filesystem, that takes time a resources.
1572*0Sstevel@tonic-gate 	 */
1573*0Sstevel@tonic-gate 	if (*cookie == (void *)1)
1574*0Sstevel@tonic-gate 		(void) meta_lockfs_common(fs, cookie, 0);
1575*0Sstevel@tonic-gate }
1576*0Sstevel@tonic-gate 
1577*0Sstevel@tonic-gate /*
1578*0Sstevel@tonic-gate  * meta_trans_detach -- detach log from trans device
1579*0Sstevel@tonic-gate  */
1580*0Sstevel@tonic-gate int
1581*0Sstevel@tonic-gate meta_trans_detach(
1582*0Sstevel@tonic-gate 	mdsetname_t	*sp,
1583*0Sstevel@tonic-gate 	mdname_t	*transnp,
1584*0Sstevel@tonic-gate 	mdcmdopts_t	options,
1585*0Sstevel@tonic-gate 	int		*delayed,
1586*0Sstevel@tonic-gate 	md_error_t	*ep
1587*0Sstevel@tonic-gate )
1588*0Sstevel@tonic-gate {
1589*0Sstevel@tonic-gate 	int		force = ((options & MDCMD_FORCE) ? 1 : 0);
1590*0Sstevel@tonic-gate 	md_i_get_t	detach;
1591*0Sstevel@tonic-gate 	md_trans_t	*transp;
1592*0Sstevel@tonic-gate 	mdname_t	*lognp;
1593*0Sstevel@tonic-gate 	void		*lock_cookie;
1594*0Sstevel@tonic-gate 
1595*0Sstevel@tonic-gate 	/* should have a set */
1596*0Sstevel@tonic-gate 	assert(sp != NULL);
1597*0Sstevel@tonic-gate 	assert(sp->setno == MD_MIN2SET(meta_getminor(transnp->dev)));
1598*0Sstevel@tonic-gate 
1599*0Sstevel@tonic-gate 	/* check name */
1600*0Sstevel@tonic-gate 	if (metachkmeta(transnp, ep) != 0)
1601*0Sstevel@tonic-gate 		return (-1);
1602*0Sstevel@tonic-gate 
1603*0Sstevel@tonic-gate 	/* save log name */
1604*0Sstevel@tonic-gate 	if ((transp = meta_get_trans(sp, transnp, ep)) == NULL)
1605*0Sstevel@tonic-gate 		return (-1);
1606*0Sstevel@tonic-gate 	if ((lognp = transp->lognamep) == NULL)
1607*0Sstevel@tonic-gate 		return (mdmderror(ep, MDE_NO_LOG, meta_getminor(transnp->dev),
1608*0Sstevel@tonic-gate 		    transnp->cname));
1609*0Sstevel@tonic-gate 
1610*0Sstevel@tonic-gate 	/*
1611*0Sstevel@tonic-gate 	 * If trans device is mounted lock the filesystem
1612*0Sstevel@tonic-gate 	 * against writes and mod time updates.
1613*0Sstevel@tonic-gate 	 */
1614*0Sstevel@tonic-gate 	if (force && meta_lockfs(transnp, &lock_cookie)) {
1615*0Sstevel@tonic-gate 		/*
1616*0Sstevel@tonic-gate 		 * This device is mounted and we were unable
1617*0Sstevel@tonic-gate 		 * lock the device. Data corruption can occur
1618*0Sstevel@tonic-gate 		 * if we don't lock the device before removing
1619*0Sstevel@tonic-gate 		 * the log so bail out here.
1620*0Sstevel@tonic-gate 		 * NOTE: There's one case were the exist status
1621*0Sstevel@tonic-gate 		 * of lockfs could have been lost yet the command
1622*0Sstevel@tonic-gate 		 * could have run. We should try to unlock the filesystem
1623*0Sstevel@tonic-gate 		 * before returning.
1624*0Sstevel@tonic-gate 		 */
1625*0Sstevel@tonic-gate 		meta_unlockfs(transnp, &lock_cookie);
1626*0Sstevel@tonic-gate 		return (mdmderror(ep, MDE_UNKNOWN_TYPE,
1627*0Sstevel@tonic-gate 		    meta_getminor(transnp->dev), transnp->cname));
1628*0Sstevel@tonic-gate 	}
1629*0Sstevel@tonic-gate 
1630*0Sstevel@tonic-gate 	/* detach log */
1631*0Sstevel@tonic-gate 	*delayed = 0;
1632*0Sstevel@tonic-gate 	(void) memset(&detach, 0, sizeof (detach));
1633*0Sstevel@tonic-gate 	detach.id = meta_getminor(transnp->dev);
1634*0Sstevel@tonic-gate 	MD_SETDRIVERNAME(&detach, MD_TRANS, sp->setno);
1635*0Sstevel@tonic-gate 	detach.size = force;
1636*0Sstevel@tonic-gate 	if (metaioctl(MD_IOC_TRANS_DETACH, &detach, &detach.mde, NULL) != 0) {
1637*0Sstevel@tonic-gate 		/* delayed detach */
1638*0Sstevel@tonic-gate 		if ((force) && (mdissyserror(&detach.mde, EBUSY))) {
1639*0Sstevel@tonic-gate 			*delayed = 1;
1640*0Sstevel@tonic-gate 			mdclrerror(&detach.mde);
1641*0Sstevel@tonic-gate 		} else {
1642*0Sstevel@tonic-gate 			meta_unlockfs(transnp, &lock_cookie);
1643*0Sstevel@tonic-gate 			return (mdstealerror(ep, &detach.mde));
1644*0Sstevel@tonic-gate 		}
1645*0Sstevel@tonic-gate 	}
1646*0Sstevel@tonic-gate 
1647*0Sstevel@tonic-gate 	/*
1648*0Sstevel@tonic-gate 	 * Unlock the filesystem
1649*0Sstevel@tonic-gate 	 */
1650*0Sstevel@tonic-gate 	meta_unlockfs(transnp, &lock_cookie);
1651*0Sstevel@tonic-gate 
1652*0Sstevel@tonic-gate 	/* clear cache */
1653*0Sstevel@tonic-gate 	meta_invalidate_name(lognp);
1654*0Sstevel@tonic-gate 	meta_invalidate_name(transnp);
1655*0Sstevel@tonic-gate 
1656*0Sstevel@tonic-gate 	/* let em know */
1657*0Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
1658*0Sstevel@tonic-gate 		if (*delayed) {
1659*0Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
1660*0Sstevel@tonic-gate "%s: logging device %s will be detached at unmount or reboot\n"),
1661*0Sstevel@tonic-gate 			    transnp->cname, lognp->cname);
1662*0Sstevel@tonic-gate 		} else {
1663*0Sstevel@tonic-gate 			(void) printf(dgettext(TEXT_DOMAIN,
1664*0Sstevel@tonic-gate 			    "%s: logging device %s is detached\n"),
1665*0Sstevel@tonic-gate 			    transnp->cname, lognp->cname);
1666*0Sstevel@tonic-gate 		}
1667*0Sstevel@tonic-gate 		(void) fflush(stdout);
1668*0Sstevel@tonic-gate 	}
1669*0Sstevel@tonic-gate 
1670*0Sstevel@tonic-gate 	/* return success */
1671*0Sstevel@tonic-gate 	return (0);
1672*0Sstevel@tonic-gate }
1673*0Sstevel@tonic-gate 
1674*0Sstevel@tonic-gate /*
1675*0Sstevel@tonic-gate  * reset trans
1676*0Sstevel@tonic-gate  */
1677*0Sstevel@tonic-gate int
1678*0Sstevel@tonic-gate meta_trans_reset(
1679*0Sstevel@tonic-gate 	mdsetname_t	*sp,
1680*0Sstevel@tonic-gate 	mdname_t	*transnp,
1681*0Sstevel@tonic-gate 	mdcmdopts_t	options,
1682*0Sstevel@tonic-gate 	md_error_t	*ep
1683*0Sstevel@tonic-gate )
1684*0Sstevel@tonic-gate {
1685*0Sstevel@tonic-gate 	md_trans_t	*transp;
1686*0Sstevel@tonic-gate 	int		rval = -1;
1687*0Sstevel@tonic-gate 
1688*0Sstevel@tonic-gate 	/* should have a set */
1689*0Sstevel@tonic-gate 	assert(sp != NULL);
1690*0Sstevel@tonic-gate 	assert((transnp == NULL) ||
1691*0Sstevel@tonic-gate 	    (sp->setno == MD_MIN2SET(meta_getminor(transnp->dev))));
1692*0Sstevel@tonic-gate 
1693*0Sstevel@tonic-gate 	/* reset all trans */
1694*0Sstevel@tonic-gate 	if (transnp == NULL) {
1695*0Sstevel@tonic-gate 		mdnamelist_t	*transnlp = NULL;
1696*0Sstevel@tonic-gate 		mdnamelist_t	*p;
1697*0Sstevel@tonic-gate 
1698*0Sstevel@tonic-gate 		/* for each trans */
1699*0Sstevel@tonic-gate 		rval = 0;
1700*0Sstevel@tonic-gate 		if (meta_get_trans_names(sp, &transnlp, 0, ep) < 0)
1701*0Sstevel@tonic-gate 			return (-1);
1702*0Sstevel@tonic-gate 		for (p = transnlp; (p != NULL); p = p->next) {
1703*0Sstevel@tonic-gate 			/* reset trans */
1704*0Sstevel@tonic-gate 			transnp = p->namep;
1705*0Sstevel@tonic-gate 			if (meta_trans_reset(sp, transnp, options, ep) != 0) {
1706*0Sstevel@tonic-gate 				rval = -1;
1707*0Sstevel@tonic-gate 				break;
1708*0Sstevel@tonic-gate 			}
1709*0Sstevel@tonic-gate 		}
1710*0Sstevel@tonic-gate 
1711*0Sstevel@tonic-gate 		/* cleanup, return success */
1712*0Sstevel@tonic-gate 		metafreenamelist(transnlp);
1713*0Sstevel@tonic-gate 		return (rval);
1714*0Sstevel@tonic-gate 	}
1715*0Sstevel@tonic-gate 
1716*0Sstevel@tonic-gate 	/* check name */
1717*0Sstevel@tonic-gate 	if (metachkmeta(transnp, ep) != 0)
1718*0Sstevel@tonic-gate 		return (-1);
1719*0Sstevel@tonic-gate 	/* get unit structure */
1720*0Sstevel@tonic-gate 	if ((transp = meta_get_trans(sp, transnp, ep)) == NULL)
1721*0Sstevel@tonic-gate 		return (-1);
1722*0Sstevel@tonic-gate 
1723*0Sstevel@tonic-gate 	/* make sure nobody owns us */
1724*0Sstevel@tonic-gate 	if (MD_HAS_PARENT(transp->common.parent)) {
1725*0Sstevel@tonic-gate 		return (mdmderror(ep, MDE_IN_USE, meta_getminor(transnp->dev),
1726*0Sstevel@tonic-gate 		    transnp->cname));
1727*0Sstevel@tonic-gate 	}
1728*0Sstevel@tonic-gate 
1729*0Sstevel@tonic-gate 	/* clear subdevices cache */
1730*0Sstevel@tonic-gate 	meta_invalidate_name(transp->masternamep);
1731*0Sstevel@tonic-gate 	if (transp->lognamep)
1732*0Sstevel@tonic-gate 		meta_invalidate_name(transp->lognamep);
1733*0Sstevel@tonic-gate 
1734*0Sstevel@tonic-gate 	/* clear metadevice */
1735*0Sstevel@tonic-gate 	if (meta_reset(sp, transnp, options, ep) != 0)
1736*0Sstevel@tonic-gate 		goto out;
1737*0Sstevel@tonic-gate 	rval = 0;	/* success */
1738*0Sstevel@tonic-gate 
1739*0Sstevel@tonic-gate 	/* let em know */
1740*0Sstevel@tonic-gate 	if (options & MDCMD_PRINT) {
1741*0Sstevel@tonic-gate 		(void) printf(dgettext(TEXT_DOMAIN, "%s: Trans is cleared\n"),
1742*0Sstevel@tonic-gate 		    transnp->cname);
1743*0Sstevel@tonic-gate 		(void) fflush(stdout);
1744*0Sstevel@tonic-gate 	}
1745*0Sstevel@tonic-gate 
1746*0Sstevel@tonic-gate 	/* clear subdevices */
1747*0Sstevel@tonic-gate 	if (! (options & MDCMD_RECURSE))
1748*0Sstevel@tonic-gate 		goto out;
1749*0Sstevel@tonic-gate 	if (metaismeta(transp->masternamep)) {
1750*0Sstevel@tonic-gate 		mdname_t	*masternp = transp->masternamep;
1751*0Sstevel@tonic-gate 
1752*0Sstevel@tonic-gate 		if (meta_reset_by_name(sp, masternp, options, ep) != 0)
1753*0Sstevel@tonic-gate 			rval = -1;
1754*0Sstevel@tonic-gate 	}
1755*0Sstevel@tonic-gate 	/* (multi-parented) log will be cleared later */
1756*0Sstevel@tonic-gate 
1757*0Sstevel@tonic-gate 	/* cleanup, return success */
1758*0Sstevel@tonic-gate out:
1759*0Sstevel@tonic-gate 	meta_invalidate_name(transnp);
1760*0Sstevel@tonic-gate 	return (rval);
1761*0Sstevel@tonic-gate }
1762