2 * Copyright (c) 2000, 2001, 2003, 2004 Sendmail, Inc. and its suppliers.
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.
11 SM_RCSID("@(#)$Id: debug.c,v 1.30 2004/08/03 20:10:26 ca Exp $")
14 ** libsm debugging and tracing
15 ** For documentation, see debug.html.
22 #include <sm/assert.h>
25 #include <sm/string.h>
26 #include <sm/varargs.h>
29 static void sm_debug_reset
__P((void));
30 static const char *parse_named_setting_x
__P((const char *));
33 ** Abstractions for printing trace messages.
37 ** The output file to which trace output is directed.
38 ** There is a controversy over whether this variable
39 ** should be process global or thread local.
40 ** To make the interface more abstract, we've hidden the
41 ** variable behind access functions.
44 static SM_FILE_T
*SmDebugOutput
= smioout
;
47 ** SM_DEBUG_FILE -- Returns current debug file pointer.
53 ** current debug file pointer.
63 ** SM_DEBUG_SETFILE -- Sets debug file pointer.
66 ** fp -- new debug file pointer.
72 ** Sets SmDebugOutput.
83 ** SM_DEBUG_CLOSE -- Close debug file pointer.
92 ** Closes SmDebugOutput.
98 if (SmDebugOutput
!= NULL
&& SmDebugOutput
!= smioout
)
100 sm_io_close(SmDebugOutput
, SM_TIME_DEFAULT
);
101 SmDebugOutput
= NULL
;
106 ** SM_DPRINTF -- printf() for debug output.
109 ** fmt -- format for printf()
117 sm_dprintf(char *fmt
, ...)
118 #else /* SM_VA_STD */
119 sm_dprintf(fmt
, va_alist
)
122 #endif /* SM_VA_STD */
126 if (SmDebugOutput
== NULL
)
128 SM_VA_START(ap
, fmt
);
129 sm_io_vfprintf(SmDebugOutput
, SmDebugOutput
->f_timeout
, fmt
, ap
);
134 ** SM_DFLUSH -- Flush debug output.
146 sm_io_flush(SmDebugOutput
, SM_TIME_DEFAULT
);
150 ** This is the internal database of debug settings.
151 ** The semantics of looking up a setting in the settings database
152 ** are that the *last* setting specified in a -d option on the sendmail
153 ** command line that matches a given SM_DEBUG structure is the one that is
154 ** used. That is necessary to conform to the existing semantics of
155 ** the sendmail -d option. We store the settings as a linked list in
156 ** reverse order, so when we do a lookup, we take the *first* entry
160 typedef struct sm_debug_setting SM_DEBUG_SETTING_T
;
161 struct sm_debug_setting
163 const char *ds_pattern
;
164 unsigned int ds_level
;
165 SM_DEBUG_SETTING_T
*ds_next
;
167 SM_DEBUG_SETTING_T
*SmDebugSettings
= NULL
;
170 ** We keep a linked list of SM_DEBUG structures that have been initialized,
171 ** for use by sm_debug_reset.
174 SM_DEBUG_T
*SmDebugInitialized
= NULL
;
176 const char SmDebugMagic
[] = "sm_debug";
179 ** SM_DEBUG_RESET -- Reset SM_DEBUG structures.
181 ** Reset all SM_DEBUG structures back to the uninitialized state.
182 ** This is used by sm_debug_addsetting to ensure that references to
183 ** SM_DEBUG structures that occur before sendmail processes its -d flags
184 ** do not cause those structures to be permanently forced to level 0.
198 for (debug
= SmDebugInitialized
;
200 debug
= debug
->debug_next
)
202 debug
->debug_level
= SM_DEBUG_UNKNOWN
;
204 SmDebugInitialized
= NULL
;
208 ** SM_DEBUG_ADDSETTING_X -- add an entry to the database of debug settings
211 ** pattern -- a shell-style glob pattern (see sm_match).
212 ** WARNING: the storage for 'pattern' will be owned by
213 ** the debug package, so it should either be a string
214 ** literal or the result of a call to sm_strdup_x.
215 ** level -- a non-negative integer.
221 ** F:sm_heap -- out of memory
225 sm_debug_addsetting_x(pattern
, level
)
229 SM_DEBUG_SETTING_T
*s
;
231 SM_REQUIRE(pattern
!= NULL
);
232 SM_REQUIRE(level
>= 0);
233 s
= sm_malloc_x(sizeof(SM_DEBUG_SETTING_T
));
234 s
->ds_pattern
= pattern
;
235 s
->ds_level
= (unsigned int) level
;
236 s
->ds_next
= SmDebugSettings
;
242 ** PARSE_NAMED_SETTING_X -- process a symbolic debug setting
245 ** s -- Points to a non-empty \0 or , terminated string,
246 ** of which the initial character is not a digit.
249 ** pointer to terminating \0 or , character.
252 ** F:sm.heap -- out of memory.
255 ** adds the setting to the database.
259 parse_named_setting_x(s
)
262 const char *pat
, *endpat
;
266 while (*s
!= '\0' && *s
!= ',' && *s
!= '.')
273 while (isascii(*s
) && isdigit(*s
))
275 level
= level
* 10 + (*s
- '0');
284 sm_debug_addsetting_x(sm_strndup_x(pat
, endpat
- pat
), level
);
286 /* skip trailing junk */
287 while (*s
!= '\0' && *s
!= ',')
294 ** SM_DEBUG_ADDSETTINGS_X -- process a list of debug options
297 ** s -- a list of debug settings, eg the argument to the
298 ** sendmail -d option.
300 ** The syntax of the string s is as follows:
302 ** <settings> ::= <setting> | <settings> "," <setting>
303 ** <setting> ::= <categories> | <categories> "." <level>
304 ** <categories> ::= [a-zA-Z_*?][a-zA-Z0-9_*?]*
306 ** However, note that we skip over anything we don't
307 ** understand, rather than report an error.
313 ** F:sm.heap -- out of memory
316 ** updates the database of debug settings.
320 sm_debug_addsettings_x(s
)
332 s
= parse_named_setting_x(s
);
337 ** SM_DEBUG_LOADLEVEL -- Get activation level of the specified debug object.
340 ** debug -- debug object.
343 ** Activation level of the specified debug object.
346 ** Ensures that the debug object is initialized.
350 sm_debug_loadlevel(debug
)
353 if (debug
->debug_level
== SM_DEBUG_UNKNOWN
)
355 SM_DEBUG_SETTING_T
*s
;
357 for (s
= SmDebugSettings
; s
!= NULL
; s
= s
->ds_next
)
359 if (sm_match(debug
->debug_name
, s
->ds_pattern
))
361 debug
->debug_level
= s
->ds_level
;
365 debug
->debug_level
= 0;
367 debug
->debug_next
= SmDebugInitialized
;
368 SmDebugInitialized
= debug
;
370 return (int) debug
->debug_level
;
374 ** SM_DEBUG_LOADACTIVE -- Activation level reached?
377 ** debug -- debug object.
378 ** level -- level to check.
381 ** true iff the activation level of the specified debug
385 ** Ensures that the debug object is initialized.
389 sm_debug_loadactive(debug
, level
)
393 return sm_debug_loadlevel(debug
) >= level
;