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