2 * Copyright (c) 2000-2001 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.28 2001/09/25 19:57:05 gshapiro 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>
30 ** Abstractions for printing trace messages.
34 ** The output file to which trace output is directed.
35 ** There is a controversy over whether this variable
36 ** should be process global or thread local.
37 ** To make the interface more abstract, we've hidden the
38 ** variable behind access functions.
41 static SM_FILE_T *SmDebugOutput = smioout;
44 ** SM_DEBUG_FILE -- Returns current debug file pointer.
50 ** current debug file pointer.
60 ** SM_DEBUG_SETFILE -- Sets debug file pointer.
63 ** fp -- new debug file pointer.
69 ** Sets SmDebugOutput.
80 ** SM_DPRINTF -- printf() for debug output.
83 ** fmt -- format for printf()
91 sm_dprintf(char *fmt, ...)
93 sm_dprintf(fmt, va_alist)
96 #endif /* SM_VA_STD */
100 if (SmDebugOutput == NULL)
102 SM_VA_START(ap, fmt);
103 sm_io_vfprintf(SmDebugOutput, SmDebugOutput->f_timeout, fmt, ap);
108 ** SM_DFLUSH -- Flush debug output.
120 sm_io_flush(SmDebugOutput, SM_TIME_DEFAULT);
124 ** This is the internal database of debug settings.
125 ** The semantics of looking up a setting in the settings database
126 ** are that the *last* setting specified in a -d option on the sendmail
127 ** command line that matches a given SM_DEBUG structure is the one that is
128 ** used. That is necessary to conform to the existing semantics of
129 ** the sendmail -d option. We store the settings as a linked list in
130 ** reverse order, so when we do a lookup, we take the *first* entry
134 typedef struct sm_debug_setting SM_DEBUG_SETTING_T;
135 struct sm_debug_setting
137 const char *ds_pattern;
138 unsigned int ds_level;
139 SM_DEBUG_SETTING_T *ds_next;
141 SM_DEBUG_SETTING_T *SmDebugSettings = NULL;
144 ** We keep a linked list of SM_DEBUG structures that have been initialized,
145 ** for use by sm_debug_reset.
148 SM_DEBUG_T *SmDebugInitialized = NULL;
150 const char SmDebugMagic[] = "sm_debug";
153 ** SM_DEBUG_RESET -- Reset SM_DEBUG structures.
155 ** Reset all SM_DEBUG structures back to the uninitialized state.
156 ** This is used by sm_debug_addsetting to ensure that references to
157 ** SM_DEBUG structures that occur before sendmail processes its -d flags
158 ** do not cause those structures to be permanently forced to level 0.
172 for (debug = SmDebugInitialized;
174 debug = debug->debug_next)
176 debug->debug_level = SM_DEBUG_UNKNOWN;
178 SmDebugInitialized = NULL;
182 ** SM_DEBUG_ADDSETTING_X -- add an entry to the database of debug settings
185 ** pattern -- a shell-style glob pattern (see sm_match).
186 ** WARNING: the storage for 'pattern' will be owned by
187 ** the debug package, so it should either be a string
188 ** literal or the result of a call to sm_strdup_x.
189 ** level -- a non-negative integer.
195 ** F:sm_heap -- out of memory
199 sm_debug_addsetting_x(pattern, level)
203 SM_DEBUG_SETTING_T *s;
205 SM_REQUIRE(pattern != NULL);
206 SM_REQUIRE(level >= 0);
207 s = sm_malloc_x(sizeof(SM_DEBUG_SETTING_T));
208 s->ds_pattern = pattern;
209 s->ds_level = (unsigned int) level;
210 s->ds_next = SmDebugSettings;
216 ** PARSE_NAMED_SETTING_X -- process a symbolic debug setting
219 ** s -- Points to a non-empty \0 or , terminated string,
220 ** of which the initial character is not a digit.
223 ** pointer to terminating \0 or , character.
226 ** F:sm.heap -- out of memory.
229 ** adds the setting to the database.
233 parse_named_setting_x(s)
234 register const char *s;
236 const char *pat, *endpat;
240 while (*s != '\0' && *s != ',' && *s != '.')
247 while (isascii(*s) && isdigit(*s))
249 level = level * 10 + (*s - '0');
258 sm_debug_addsetting_x(sm_strndup_x(pat, endpat - pat), level);
260 /* skip trailing junk */
261 while (*s != '\0' && *s != ',')
268 ** SM_DEBUG_ADDSETTINGS_X -- process a list of debug options
271 ** s -- a list of debug settings, eg the argument to the
272 ** sendmail -d option.
274 ** The syntax of the string s is as follows:
276 ** <settings> ::= <setting> | <settings> "," <setting>
277 ** <setting> ::= <categories> | <categories> "." <level>
278 ** <categories> ::= [a-zA-Z_*?][a-zA-Z0-9_*?]*
280 ** However, note that we skip over anything we don't
281 ** understand, rather than report an error.
287 ** F:sm.heap -- out of memory
290 ** updates the database of debug settings.
294 sm_debug_addsettings_x(s)
295 register const char *s;
306 s = parse_named_setting_x(s);
311 ** SM_DEBUG_LOADLEVEL -- Get activation level of the specified debug object.
314 ** debug -- debug object.
317 ** Activation level of the specified debug object.
320 ** Ensures that the debug object is initialized.
324 sm_debug_loadlevel(debug)
327 if (debug->debug_level == SM_DEBUG_UNKNOWN)
329 SM_DEBUG_SETTING_T *s;
331 for (s = SmDebugSettings; s != NULL; s = s->ds_next)
333 if (sm_match(debug->debug_name, s->ds_pattern))
335 debug->debug_level = s->ds_level;
339 debug->debug_level = 0;
341 debug->debug_next = SmDebugInitialized;
342 SmDebugInitialized = debug;
344 return (int) debug->debug_level;
348 ** SM_DEBUG_LOADACTIVE -- Activation level reached?
351 ** debug -- debug object.
352 ** level -- level to check.
355 ** true iff the activation level of the specified debug
359 ** Ensures that the debug object is initialized.
363 sm_debug_loadactive(debug, level)
367 return sm_debug_loadlevel(debug) >= level;