xref: /titanic_41/usr/src/lib/lvm/libmeta/common/meta_setup.c (revision 1410cb930a3e26032c59c6835837a28c47366b3c)
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  * setup utility
39  */
40 
41 #include "meta_set_prv.h"
42 #include <sys/resource.h>
43 #include <syslog.h>
44 
45 
46 /* globals */
47 char		*myname = "";
48 FILE		*metalogfp = NULL;
49 int		metasyslog = 0;
50 uint_t		verbosity = 0;
51 hrtime_t	start_time = 0;
52 sigset_t	allsigs;
53 
54 /* locals */
55 static	int	rb_signal_handling = FALSE;
56 static	int	rb_signal_caught = FALSE;
57 static	int	rb_signal_which = 0;
58 static	size_t	metansig = 0;
59 static	struct	sigaction	*metahandlers = NULL;
60 #ifdef	_DEBUG_MALLOC_INC
61 static	ulong_t	malloc_histid_begin;
62 static	ulong_t	malloc_histid_end;
63 static	ulong_t	malloc_inuse_begin;
64 static	ulong_t	malloc_inuse_end;
65 #endif	/* _DEBUG_MALLOC_INC */
66 
67 /* forwards */
68 static	void	md_catcher(int sig);
69 
70 /*
71  * push/pop signal handlers
72  */
73 static int
74 md_pushsig(
75 	unsigned	sig,
76 	void		(*handler)(int sig),
77 	md_error_t	*ep
78 )
79 {
80 	struct	sigaction	newhandler;
81 
82 	/* expand vector as neccessary */
83 	if (sig >= metansig) {
84 		if (metahandlers == NULL) {
85 			metahandlers = Zalloc(
86 			    (sig + 1) * sizeof (metahandlers[0]));
87 		} else {
88 			metahandlers = Realloc(metahandlers,
89 			    ((sig + 1) * sizeof (metahandlers[0])));
90 			(void) memset(&metahandlers[metansig], 0,
91 			    ((sig - metansig) * sizeof (metahandlers[0])));
92 		}
93 		metansig = sig;
94 	}
95 
96 	/* We need to have a seperate stack to handle rollback properly */
97 	newhandler.sa_flags = 0;
98 	if (sigfillset(&newhandler.sa_mask) < 0)
99 		return (mdsyserror(ep, errno,
100 		    "sigfillset(&newhandler.sa_mask)"));
101 	newhandler.sa_handler = handler;
102 
103 	/* push handler */
104 	if (sigaction(sig, &newhandler, &metahandlers[sig]) < 0)
105 		return (mdsyserror(ep, errno, "sigaction(&newhandler)"));
106 
107 	/* return success */
108 	return (0);
109 }
110 
111 static int
112 md_popsig(
113 	unsigned	sig,
114 	md_error_t	*ep
115 )
116 {
117 	/* can't pop what isn't pushed */
118 	assert(sig <= metansig);
119 	assert(metahandlers[sig].sa_handler != md_catcher);
120 
121 	/* pop handler */
122 	if (sigaction(sig, &metahandlers[sig], NULL) < 0)
123 		return (mdsyserror(ep, errno, "sigaction(&metahandlers)"));
124 
125 	/* return success */
126 	return (0);
127 }
128 
129 char *
130 meta_lock_name(
131 	set_t	setno
132 )
133 {
134 	char	lockname[30];
135 
136 	if (setno == MD_LOCAL_SET)
137 		return (strdup(METALOCK));
138 
139 	(void) snprintf(lockname, sizeof (lockname), "%s.%ld", METALOCK, setno);
140 	return (strdup(lockname));
141 }
142 
143 #define	META_LOCK_FD(sp)	((sp)->lockfd)
144 #define	META_LOCK_NAME(sp)	(meta_lock_name((sp)->setno))
145 
146 /*
147  * open lock
148  */
149 static int
150 meta_lock_open(
151 	mdsetname_t	*sp,
152 	md_error_t	*ep
153 )
154 {
155 	int	lockfd = META_LOCK_FD(sp);
156 	char	*lockname = META_LOCK_NAME(sp);
157 
158 	/* check for already open */
159 	if (lockfd >= 0)
160 		goto success;
161 	assert(lockfd == MD_NO_LOCK);
162 
163 	/* open and/or create lock file */
164 	if ((lockfd = open(lockname, O_WRONLY, 0)) < 0) {
165 		if (errno == EROFS) {
166 			lockfd = MD_NO_LOCK;
167 			goto success;
168 		}
169 		if (errno != ENOENT) {
170 			(void) mdsyserror(ep, errno, lockname);
171 			goto failure;
172 		}
173 		if ((lockfd = open(lockname, (O_WRONLY|O_CREAT),
174 		    0644)) < 0) {
175 			(void) mdsyserror(ep, errno, lockname);
176 			goto failure;
177 		}
178 		if (fchmod(lockfd, 0644) != 0) {
179 			(void) mdsyserror(ep, errno, lockname);
180 			goto failure;
181 		}
182 	}
183 
184 	/* return success */
185 success:
186 	if (lockname != NULL)
187 		free(lockname);
188 	META_LOCK_FD(sp) = lockfd;
189 	return (0);
190 
191 	/* flag failure */
192 failure:
193 	if (lockname != NULL)
194 		free(lockname);
195 	if (lockfd >= 0)
196 		(void) close(lockfd);
197 	return (-1);
198 }
199 
200 static int
201 meta_lock_close(
202 	mdsetname_t	*sp,
203 	md_error_t	*ep
204 )
205 {
206 	int	retval = 0;
207 
208 	if (close(META_LOCK_FD(sp)) != 0) {
209 		if (ep != NULL) {
210 			char	*lockname = META_LOCK_NAME(sp);
211 			(void) mdsyserror(ep, errno, lockname);
212 			if (lockname != NULL)
213 				free(lockname);
214 		}
215 
216 		retval = -1;
217 	}
218 	META_LOCK_FD(sp) = MD_NO_LOCK;
219 	return (retval);
220 }
221 
222 /*
223  * unlock
224  */
225 int
226 meta_unlock(
227 	mdsetname_t	*sp,
228 	md_error_t	*ep
229 )
230 {
231 	int	lockfd = META_LOCK_FD(sp);
232 
233 	/* ignore read-only filesystem */
234 	if (lockfd == MD_NO_LOCK)
235 		return (0);
236 
237 	assert(lockfd >= 0);
238 
239 	/* unlock and discard */
240 	if (lockf(lockfd, F_ULOCK, 0) != 0) {
241 		(void) mdsyserror(ep, errno, METALOCK);
242 		(void) meta_lock_close(sp, NULL);
243 		return (-1);
244 	}
245 	return (meta_lock_close(sp, ep));
246 }
247 
248 /*
249  * lock
250  */
251 int
252 meta_lock(
253 	mdsetname_t	*sp,
254 	int		print_status,
255 	md_error_t	*ep
256 )
257 {
258 	int	lockfd;
259 	char	*lockname = NULL;
260 
261 	/* open lock file */
262 	if (meta_lock_open(sp, ep) != 0) {
263 		assert(META_LOCK_FD(sp) == MD_NO_LOCK);
264 		goto failure;
265 	}
266 
267 	/* ignore read-only filesystem */
268 	if ((lockfd = META_LOCK_FD(sp)) == MD_NO_LOCK)
269 		goto success;
270 	assert(lockfd >= 0);
271 
272 	lockname = META_LOCK_NAME(sp);
273 
274 	/* grab lock */
275 	if (lockf(lockfd, F_TLOCK, 0) != 0) {
276 		if ((errno != EACCES) && (errno != EAGAIN)) {
277 			(void) mdsyserror(ep, errno, lockname);
278 			goto failure;
279 		}
280 		if (print_status)
281 			(void) fprintf(stderr, dgettext(TEXT_DOMAIN,
282 			    "%s: waiting on %s\n"),
283 			    myname, lockname);
284 		if (lockf(lockfd, F_LOCK, 0) != 0) {
285 			(void) mdsyserror(ep, errno, lockname);
286 			goto failure;
287 		}
288 	}
289 
290 	/* return success */
291 success:
292 	if (lockname != NULL)
293 		free(lockname);
294 	return (0);
295 
296 	/* flag failure */
297 failure:
298 	if (lockname != NULL)
299 		free(lockname);
300 	if (lockfd >= 0)
301 		(void) meta_lock_close(sp, ep);
302 	return (-1);
303 }
304 
305 int
306 meta_lock_nowait(
307 	mdsetname_t	*sp,
308 	md_error_t	*ep
309 )
310 {
311 	int	lockfd;
312 	char	*lockname = NULL;
313 
314 	/* open lock file */
315 	if (meta_lock_open(sp, ep) != 0) {
316 		assert(META_LOCK_FD(sp) == MD_NO_LOCK);
317 		goto failure;
318 	}
319 
320 	/* ignore read-only filesystem */
321 	if ((lockfd = META_LOCK_FD(sp)) == MD_NO_LOCK)
322 		goto success;
323 	assert(lockfd >= 0);
324 
325 	lockname = META_LOCK_NAME(sp);
326 
327 	/* grab lock */
328 	if (lockf(lockfd, F_TLOCK, 0) != 0) {
329 		if ((errno != EACCES) && (errno != EAGAIN)) {
330 			(void) mdsyserror(ep, errno, lockname);
331 			goto failure;
332 		}
333 		(void) mdsyserror(ep, EAGAIN, lockname);
334 		goto failure;
335 	}
336 
337 	/* return success */
338 success:
339 	if (lockname != NULL)
340 		free(lockname);
341 	return (0);
342 
343 	/* flag failure */
344 failure:
345 	if (lockname != NULL)
346 		free(lockname);
347 	if (lockfd >= 0)
348 		(void) meta_lock_close(sp, ep);
349 	return (-1);
350 }
351 
352 /*
353  * lock status
354  */
355 int
356 meta_lock_status(
357 	mdsetname_t	*sp,
358 	md_error_t	*ep
359 )
360 {
361 	int lockfd;
362 
363 	/* open lock file */
364 	if (meta_lock_open(sp, ep) != 0) {
365 		assert(META_LOCK_FD(sp) == MD_NO_LOCK);
366 		return (-1);
367 	}
368 
369 	lockfd = META_LOCK_FD(sp);
370 	/* ignore read-only filesystem */
371 	if (lockfd == MD_NO_LOCK)
372 		return (0);
373 	assert(lockfd >= 0);
374 
375 	/* test lock */
376 	if (lockf(lockfd, F_TEST, 0) != 0) {
377 		char *lockname = META_LOCK_NAME(sp);
378 		(void) mdsyserror(ep, errno, lockname);
379 		if (lockname != NULL)
380 			free(lockname);
381 		return (-1);
382 	}
383 
384 	return (0);
385 }
386 
387 /*
388  * setup for syslog daemon output
389  */
390 static void
391 md_syslog(
392 	char	*name	/* name of program */
393 )
394 {
395 	if ((name == NULL) || (*name == '\0'))
396 		name = "md";
397 	openlog(name, LOG_CONS, LOG_DAEMON);
398 	metasyslog = 1;
399 }
400 
401 /*
402  * daemonize: put in background
403  */
404 int
405 md_daemonize(
406 	mdsetname_t	*sp,
407 	md_error_t	*ep
408 )
409 {
410 	char		*p;
411 	struct rlimit	rlim;
412 	pid_t		pid;
413 	int		i;
414 
415 	/* debug */
416 	if (((p = getenv("MD_DEBUG")) != NULL) &&
417 	    (strstr(p, "NODAEMON") != NULL)) {
418 		return (0);	/* do nothing */
419 	}
420 
421 	/* get number of file descriptors */
422 	if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
423 		return (mdsyserror(ep, errno, "getrlimit(RLIMIT_NOFILE)"));
424 	}
425 
426 	/* fork and kill parent */
427 	if ((pid = fork()) == -1)
428 		return (mdsyserror(ep, errno, "fork"));
429 	else if (pid != 0)
430 		return (pid);
431 
432 	/*
433 	 * We need to close the admin device and reset the specialfd to force
434 	 * the child process to reopen it, since we are going to close all
435 	 * descriptors from 3 up to RLIMIT_NOFILE in the child.
436 	 */
437 	if (close_admin(ep) != 0)
438 		return (-1);
439 
440 	/* close RPC connections */
441 	metarpccloseall();
442 
443 	/* drop lock */
444 	if (meta_unlock(sp, ep) != 0)
445 		return (-1);
446 
447 	if (rlim.rlim_cur != RLIM_INFINITY) {
448 		/*
449 		 * close all but stdout, stderr, and metalogfp
450 		 */
451 
452 		for (i = 0; (i < rlim.rlim_cur); ++i) {
453 			if ((i == fileno(stdout)) ||
454 			    (i == fileno(stderr)) ||
455 			    ((metalogfp != NULL) &&
456 			    (i == fileno(metalogfp)))) {
457 				continue;
458 			}
459 			(void) close(i);
460 		}
461 	}
462 
463 	/* put in own process group */
464 	if (setsid() == -1)
465 		return (mdsyserror(ep, errno, "setsid"));
466 
467 	/* setup syslog */
468 	md_syslog(myname);
469 
470 	/* return success */
471 	return (0);
472 }
473 
474 /*
475  * flush and sync fp
476  */
477 static void
478 flushfp(
479 	FILE	*fp
480 )
481 {
482 	(void) fflush(fp);
483 	(void) fsync(fileno(fp));
484 }
485 
486 /*
487  * reset and exit utility
488  */
489 void
490 md_exit(
491 	mdsetname_t	*sp,
492 	int		eval
493 )
494 {
495 	md_error_t	status = mdnullerror;
496 	md_error_t	*ep = &status;
497 
498 
499 	/* close RPC connections */
500 	metarpccloseall();
501 
502 	if (sp != NULL) {
503 		if (meta_unlock(sp, ep) != 0) {
504 			mde_perror(ep, "");
505 			mdclrerror(ep);
506 			if (eval == 0)
507 				eval = 1;
508 		}
509 	}
510 
511 	/* flush name caches */
512 #ifdef	DEBUG
513 	metaflushnames(1);
514 #endif	/* DEBUG */
515 
516 	/* log exit */
517 	if (metalogfp != NULL) {
518 		md_logpfx(metalogfp);
519 		(void) fprintf(metalogfp, dgettext(TEXT_DOMAIN,
520 		    "exiting with %d\n"), eval);
521 		flushfp(metalogfp);
522 		(void) fclose(metalogfp);
523 		metalogfp = NULL;
524 	}
525 	if ((metasyslog) && (eval != 0)) {
526 		syslog(LOG_ERR, dgettext(TEXT_DOMAIN,
527 		    "exiting with %d\n"), eval);
528 		closelog();
529 		metasyslog = 0;
530 	}
531 
532 	/* check arena, print malloc usage */
533 #ifdef	_DEBUG_MALLOC_INC
534 	(void) malloc_chain_check(1);
535 	{
536 		char	*p;
537 
538 		if (((p = getenv("MD_DEBUG")) != NULL) &&
539 		    (strstr(p, "MALLOC") != NULL)) {
540 			malloc_inuse_end = malloc_inuse(&malloc_histid_end);
541 			(void) fprintf(stderr, "%s: end malloc_inuse %lu\n",
542 			    myname, malloc_inuse_end);
543 			if (malloc_inuse_end != malloc_inuse_begin) {
544 				malloc_list(fileno(stderr),
545 				    malloc_histid_begin, malloc_histid_end);
546 			}
547 		}
548 	}
549 #endif	/* _DEBUG_MALLOC_INC */
550 
551 	/* exit with value */
552 	exit(eval);
553 }
554 
555 /*
556  * signal catcher
557  */
558 static void
559 md_catcher(
560 	int			sig
561 )
562 {
563 	char			buf[128];
564 	char			*msg;
565 	md_error_t		status = mdnullerror;
566 	md_error_t		*ep = &status;
567 	struct sigaction	defhandler;
568 
569 	/* log signal */
570 	if ((msg = strsignal(sig)) == NULL) {
571 		(void) snprintf(buf, sizeof (buf),
572 		    dgettext(TEXT_DOMAIN, "unknown signal %d"), sig);
573 		msg = buf;
574 	}
575 	md_eprintf("%s\n", msg);
576 
577 	/*
578 	 * In roll_back crtical section handling, the first instance of a user
579 	 * generated signal is caught, a flag is set to allow preemption at a
580 	 * "convenient" point and md_catcher returns.  If the user continues
581 	 * generate the signal, the second instance will invoke the default
582 	 * handler and exit.
583 	 */
584 	if (rb_signal_handling == TRUE) {
585 		if (sig != SIGABRT && sig != SIGBUS && sig != SIGSEGV) {
586 			if (rb_signal_caught == FALSE) {
587 				rb_signal_caught = TRUE;
588 				rb_signal_which  = sig;
589 				return;
590 			}
591 		}
592 	}
593 
594 	/* let default handler do it's thing */
595 	if (md_popsig(sig, ep) != 0) {
596 		mde_perror(ep, "");
597 		mdclrerror(ep);
598 		defhandler.sa_flags = 0;
599 		if (sigfillset(&defhandler.sa_mask) < 0) {
600 			(void) mdsyserror(ep, errno,
601 			    "sigfillset(&defhandler.sa_mask)");
602 			mde_perror(ep, "");
603 			md_exit(NULL, 1);
604 		}
605 		defhandler.sa_handler = SIG_DFL;
606 		if (sigaction(sig, &defhandler, NULL) < 0) {
607 			(void) mdsyserror(ep, errno, "sigaction(&defhandler)");
608 			mde_perror(ep, "");
609 			md_exit(NULL, 1);
610 		}
611 	}
612 
613 	md_post_sig(sig);
614 }
615 
616 void
617 md_post_sig(int sig)
618 {
619 	if (kill(getpid(), sig) != 0) {
620 		md_perror("kill(getpid())");
621 		md_exit(NULL, -sig);
622 	}
623 }
624 
625 int
626 md_got_sig(void)
627 {
628 	return (rb_signal_caught);
629 }
630 
631 int
632 md_which_sig(void)
633 {
634 	return (rb_signal_which);
635 }
636 
637 void
638 md_rb_sig_handling_on(void)
639 {
640 	rb_signal_handling = TRUE;
641 }
642 
643 void
644 md_rb_sig_handling_off(int sig_seen, int sig)
645 {
646 	rb_signal_handling = FALSE;
647 	rb_signal_caught = FALSE;
648 	rb_signal_which  = 0;
649 	if (sig_seen)
650 		md_post_sig(sig);
651 }
652 
653 /*
654  * setup metaclust variables
655  */
656 void
657 setup_mc_log(
658 	uint_t	level
659 )
660 {
661 	/* initialise externals */
662 	verbosity = level;
663 	start_time = gethrtime();
664 }
665 
666 /*
667  * initilize utility
668  */
669 int
670 md_init(
671 	int		argc,
672 	char		*argv[],
673 	int		dosyslog,
674 	int		doadmin,
675 	md_error_t	*ep
676 )
677 {
678 	int ret = 0;
679 
680 	/* initialize everything but the signals */
681 	if ((ret = md_init_nosig(argc, argv, dosyslog,
682 			doadmin, ep)) != 0)
683 		return (ret);
684 
685 
686 	if (sigfillset(&allsigs) < 0)
687 		return (mdsyserror(ep, errno, "sigfillset(&allsigs)"));
688 
689 	/* catch common signals */
690 	if ((md_pushsig(SIGHUP, md_catcher, ep) != 0) ||
691 	    (md_pushsig(SIGINT, md_catcher, ep) != 0) ||
692 	    (md_pushsig(SIGQUIT, md_catcher, ep) != 0) ||
693 	    (md_pushsig(SIGABRT, md_catcher, ep) != 0) ||
694 	    (md_pushsig(SIGBUS, md_catcher, ep) != 0) ||
695 	    (md_pushsig(SIGSEGV, md_catcher, ep) != 0) ||
696 	    (md_pushsig(SIGPIPE, md_catcher, ep) != 0) ||
697 	    (md_pushsig(SIGTERM, md_catcher, ep) != 0)) {
698 		return (-1);
699 	}
700 
701 	/* return success */
702 	return (0);
703 }
704 
705 
706 /*
707  * initilize utility without setting up sighandlers
708  * setting up signal handlers in libmeta can affect others
709  * programs that link with libmeta but have their own handlers
710  */
711 int
712 md_init_nosig(
713 	int		argc,
714 	char		*argv[],
715 	int		dosyslog,
716 	int		doadmin,
717 	md_error_t	*ep
718 )
719 {
720 	/* setup myname */
721 	if ((myname = strrchr(argv[0], '/')) != NULL)
722 		++myname;
723 	else
724 		myname = argv[0];
725 
726 #if !defined(TEXT_DOMAIN)
727 #define	TEXT_DOMAIN "SYS_TEST"
728 #endif
729 
730 	/* print malloc usage */
731 #ifdef	_DEBUG_MALLOC_INC
732 	{
733 		char	*p;
734 
735 		if (((p = getenv("MD_DEBUG")) != NULL) &&
736 		    (strstr(p, "MALLOC") != NULL)) {
737 			malloc_inuse_begin =
738 			    malloc_inuse(&malloc_histid_begin);
739 			(void) fprintf(stderr, "%s: begin malloc_inuse %lu\n",
740 			    myname, malloc_inuse_begin);
741 		}
742 	}
743 #endif	/* _DEBUG_MALLOC_INC */
744 
745 	/* open syslog */
746 	if (dosyslog)
747 		md_syslog(myname);
748 
749 	/* log command */
750 	if (getenv(METALOGENV) != NULL) {
751 		if ((metalogfp = fopen(METALOG, "a")) != NULL) {
752 			int	i;
753 
754 			(void) fchmod(fileno(metalogfp), 0664);
755 			md_logpfx(metalogfp);
756 			for (i = 1; (i < argc); ++i)
757 				(void) fprintf(metalogfp, " %s", argv[i]);
758 			(void) fprintf(metalogfp, "\n");
759 			flushfp(metalogfp);
760 		}
761 	}
762 
763 	/* make sure we can open the admin device before we do anything else */
764 	if (doadmin)
765 		if (open_admin(ep) < 0)
766 			return (-1);
767 
768 	/* flush name caches */
769 	metaflushnames(1);
770 
771 	/* return success */
772 	return (0);
773 }
774 
775 /*
776  * (re)initilize daemon
777  */
778 int
779 md_init_daemon(
780 	char		*name,
781 	md_error_t	*ep
782 )
783 {
784 	static int	already = 0;
785 	int		dosyslog = 1;
786 	int		doadmin = 1;
787 
788 	/* setup */
789 	if (! already) {
790 		if (md_init(1, &name, dosyslog, doadmin, ep) != 0)
791 			return (-1);
792 		already = 1;
793 	}
794 
795 	/* return success */
796 	return (0);
797 }
798 
799 /*
800  * Roll back functions for handling sync and async cleanup.
801  */
802 
803 int
804 procsigs(int block, sigset_t *oldsigs, md_error_t *ep)
805 {
806 	if (block == TRUE) {
807 		if (sigprocmask(SIG_BLOCK, &allsigs, oldsigs) < 0) {
808 			(void) mdsyserror(ep, errno, "sigprocmask(SIG_BLOCK)");
809 			return (-1);
810 		}
811 	} else {
812 		if (sigprocmask(SIG_SETMASK, oldsigs, NULL) < 0) {
813 			(void) mdsyserror(ep, errno,
814 			    "sigprocmask(SIG_SETMASK)");
815 			return (-1);
816 		}
817 	}
818 	return (0);
819 }
820 
821 #ifdef DEBUG
822 int
823 rb_test(
824 	int		rbt_sel_tpt,
825 	char		*rbt_sel_tag,
826 	md_error_t	*ep
827 )
828 {
829 	char		*rbt_env_tpt = getenv("META_RBT_TPT");
830 	char		*rbt_env_tag = getenv("META_RBT_TAG");
831 	int		sig = 0;
832 	int		rbt_int_tpt;
833 	int		rbt_tag_match = 1;
834 	sigset_t	curmask;
835 	md_error_t	xep = mdnullerror;
836 
837 	if (rbt_env_tpt) {
838 		rbt_int_tpt = atoi(rbt_env_tpt);
839 		if (rbt_int_tpt < 0) {
840 			sig = 1;
841 			rbt_int_tpt = -1 * rbt_int_tpt;
842 		}
843 
844 		assert(rbt_sel_tpt != 0);
845 
846 		if (rbt_int_tpt == 0)
847 			return (0);
848 
849 		if (rbt_env_tag && rbt_sel_tag)
850 			if (strcmp(rbt_env_tag, rbt_sel_tag) != 0)
851 				rbt_tag_match = 0;
852 
853 		if (rbt_int_tpt == rbt_sel_tpt && rbt_tag_match) {
854 			md_eprintf(
855 			    "******************** RB_TEST(%s, %d, sig=%s)\n",
856 			    rbt_sel_tag, rbt_sel_tpt,
857 			    (sig != 0) ? "True" : "False");
858 			if (sig) {
859 				md_eprintf("********** sigsuspend()\n");
860 				if (sigprocmask(NULL, NULL, &curmask) < 0) {
861 					(void) mdsyserror(&xep, errno, NULL);
862 					mde_perror(&xep, "sigprocmask(GET)");
863 					md_exit(NULL, 1);
864 				}
865 
866 				if (sigsuspend(&curmask) < 0) {
867 					(void) mdsyserror(&xep, errno, NULL);
868 					mde_perror(&xep,
869 					    "sigsuspend(&curmask)");
870 					md_exit(NULL, 1);
871 				}
872 
873 				if (md_got_sig())
874 					return (-1);
875 			}
876 			(void) mderror(ep, MDE_TESTERROR,
877 			    "********** rb_test()");
878 			md_eprintf("******************** rollback\n");
879 			return (-1);
880 		}
881 	}
882 	return (0);
883 }
884 #else
885 /* ARGSUSED */
886 int
887 rb_test(
888 	int		rbt_sel_tpt,
889 	char		*rbt_sel_tag,
890 	md_error_t	*ep
891 )
892 {
893 	(void) mderror(ep, MDE_TESTERROR, "******** rb_test:Not supported\n");
894 	return (-1);
895 
896 }
897 #endif	/* DEBUG */
898