xref: /illumos-gate/usr/src/cmd/sendmail/libsm/assert.c (revision 7c478bd9)
1 /*
2  * Copyright (c) 2000-2001 Sendmail, Inc. and its suppliers.
3  *	All rights reserved.
4  *
5  * By using this file, you agree to the terms and conditions set
6  * forth in the LICENSE file which can be found at the top level of
7  * the sendmail distribution.
8  *
9  */
10 
11 #pragma ident	"%Z%%M%	%I%	%E% SMI"
12 
13 #include <sm/gen.h>
14 SM_RCSID("@(#)$Id: assert.c,v 1.25.2.1 2003/12/05 22:44:17 ca Exp $")
15 
16 /*
17 **  Abnormal program termination and assertion checking.
18 **  For documentation, see assert.html.
19 */
20 
21 #include <signal.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 
25 #include <sm/assert.h>
26 #include <sm/exc.h>
27 #include <sm/io.h>
28 #include <sm/varargs.h>
29 
30 /*
31 **  Debug categories that are used to guard expensive assertion checks.
32 */
33 
34 SM_DEBUG_T SmExpensiveAssert = SM_DEBUG_INITIALIZER("sm_check_assert",
35 	"@(#)$Debug: sm_check_assert - check assertions $");
36 
37 SM_DEBUG_T SmExpensiveRequire = SM_DEBUG_INITIALIZER("sm_check_require",
38 	"@(#)$Debug: sm_check_require - check function preconditions $");
39 
40 SM_DEBUG_T SmExpensiveEnsure = SM_DEBUG_INITIALIZER("sm_check_ensure",
41 	"@(#)$Debug: sm_check_ensure - check function postconditions $");
42 
43 /*
44 **  Debug category: send self SIGSTOP on fatal error,
45 **  so that you can run a debugger on the stopped process.
46 */
47 
48 SM_DEBUG_T SmAbortStop = SM_DEBUG_INITIALIZER("sm_abort_stop",
49 	"@(#)$Debug: sm_abort_stop - stop process on fatal error $");
50 
51 /*
52 **  SM_ABORT_DEFAULTHANDLER -- Default procedure for abnormal program
53 **				termination.
54 **
55 **	The goal is to display an error message without disturbing the
56 **	process state too much, then dump core.
57 **
58 **	Parameters:
59 **		filename -- filename (can be NULL).
60 **		lineno -- line number.
61 **		msg -- message.
62 **
63 **	Returns:
64 **		doesn't return.
65 */
66 
67 static void
68 sm_abort_defaulthandler __P((
69 	const char *filename,
70 	int lineno,
71 	const char *msg));
72 
73 static void
sm_abort_defaulthandler(filename,lineno,msg)74 sm_abort_defaulthandler(filename, lineno, msg)
75 	const char *filename;
76 	int lineno;
77 	const char *msg;
78 {
79 	if (filename != NULL)
80 		sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "%s:%d: %s\n", filename,
81 			      lineno, msg);
82 	else
83 		sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "%s\n", msg);
84 	sm_io_flush(smioerr, SM_TIME_DEFAULT);
85 #ifdef SIGSTOP
86 	if (sm_debug_active(&SmAbortStop, 1))
87 		kill(getpid(), SIGSTOP);
88 #endif /* SIGSTOP */
89 	abort();
90 }
91 
92 /*
93 **  This is the action to be taken to cause abnormal program termination.
94 */
95 
96 static SM_ABORT_HANDLER_T SmAbortHandler = sm_abort_defaulthandler;
97 
98 /*
99 **  SM_ABORT_SETHANDLER -- Set handler for SM_ABORT()
100 **
101 **	This allows you to set a handler function for causing abnormal
102 **	program termination; it is called when a logic bug is detected.
103 **
104 **	Parameters:
105 **		f -- handler.
106 **
107 **	Returns:
108 **		none.
109 */
110 
111 void
sm_abort_sethandler(f)112 sm_abort_sethandler(f)
113 	SM_ABORT_HANDLER_T f;
114 {
115 	if (f == NULL)
116 		SmAbortHandler = sm_abort_defaulthandler;
117 	else
118 		SmAbortHandler = f;
119 }
120 
121 /*
122 **  SM_ABORT -- Call it when you have detected a logic bug.
123 **
124 **	Parameters:
125 **		fmt -- format string.
126 **		... -- arguments.
127 **
128 **	Returns:
129 **		doesn't.
130 */
131 
132 void SM_DEAD_D
133 #if SM_VA_STD
sm_abort(char * fmt,...)134 sm_abort(char *fmt, ...)
135 #else /* SM_VA_STD */
136 sm_abort(fmt, va_alist)
137 	char *fmt;
138 	va_dcl
139 #endif /* SM_VA_STD */
140 {
141 	char msg[128];
142 	SM_VA_LOCAL_DECL
143 
144 	SM_VA_START(ap, fmt);
145 	sm_vsnprintf(msg, sizeof msg, fmt, ap);
146 	SM_VA_END(ap);
147 	sm_abort_at(NULL, 0, msg);
148 }
149 
150 /*
151 **  SM_ABORT_AT -- Initiate abnormal program termination.
152 **
153 **	This is the low level function that is called to initiate abnormal
154 **	program termination.  It prints an error message and terminates the
155 **	program.  It is called by sm_abort and by the assertion macros.
156 **	If filename != NULL then filename and lineno specify the line of source
157 **	code at which the bug was detected.
158 **
159 **	Parameters:
160 **		filename -- filename (can be NULL).
161 **		lineno -- line number.
162 **		msg -- message.
163 **
164 **	Returns:
165 **		doesn't.
166 */
167 
168 void SM_DEAD_D
sm_abort_at(filename,lineno,msg)169 sm_abort_at(filename, lineno, msg)
170 	const char *filename;
171 	int lineno;
172 	const char *msg;
173 {
174 	SM_TRY
175 		(*SmAbortHandler)(filename, lineno, msg);
176 	SM_EXCEPT(exc, "*")
177 		sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
178 			      "exception raised by abort handler:\n");
179 		sm_exc_print(exc, smioerr);
180 		sm_io_flush(smioerr, SM_TIME_DEFAULT);
181 	SM_END_TRY
182 
183 	/*
184 	**  SmAbortHandler isn't supposed to return.
185 	**  Since it has, let's make sure that the program is terminated.
186 	*/
187 
188 	abort();
189 }
190