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