2 * Copyright (c) 2000, 2001, 2003, 2004 Proofpoint, 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.33 2013-11-22 20:51:42 ca Exp $")
14 ** libsm debugging and tracing
15 ** For documentation, see debug.html.
20 #if _FFR_DEBUG_PID_TIME
25 #endif /* _FFR_DEBUG_PID_TIME */
28 #include <sm/assert.h>
31 #include <sm/string.h>
32 #include <sm/varargs.h>
35 static void sm_debug_reset __P((void));
36 static const char *parse_named_setting_x __P((const char *));
39 ** Abstractions for printing trace messages.
43 ** The output file to which trace output is directed.
44 ** There is a controversy over whether this variable
45 ** should be process global or thread local.
46 ** To make the interface more abstract, we've hidden the
47 ** variable behind access functions.
50 static SM_FILE_T *SmDebugOutput = smioout;
53 ** SM_DEBUG_FILE -- Returns current debug file pointer.
59 ** current debug file pointer.
69 ** SM_DEBUG_SETFILE -- Sets debug file pointer.
72 ** fp -- new debug file pointer.
78 ** Sets SmDebugOutput.
89 ** SM_DEBUG_CLOSE -- Close debug file pointer.
98 ** Closes SmDebugOutput.
104 if (SmDebugOutput != NULL && SmDebugOutput != smioout)
106 sm_io_close(SmDebugOutput, SM_TIME_DEFAULT);
107 SmDebugOutput = NULL;
112 ** SM_DPRINTF -- printf() for debug output.
115 ** fmt -- format for printf()
121 #if _FFR_DEBUG_PID_TIME
122 SM_DEBUG_T SmDBGPidTime = SM_DEBUG_INITIALIZER("sm_trace_pid_time",
123 "@(#)$Debug: sm_trace_pid_time - print pid and time in debug $");
128 sm_dprintf(char *fmt, ...)
129 #else /* SM_VA_STD */
130 sm_dprintf(fmt, va_alist)
133 #endif /* SM_VA_STD */
136 #if _FFR_DEBUG_PID_TIME
137 static struct timeval lasttv;
140 if (SmDebugOutput == NULL)
142 #if _FFR_DEBUG_PID_TIME
143 /* note: this is ugly if the output isn't a full line! */
144 if (sm_debug_active(&SmDBGPidTime, 3))
146 struct timeval tv, tvd;
148 gettimeofday(&tv, NULL);
149 if (timerisset(&lasttv))
150 timersub(&tv, &lasttv, &tvd);
153 sm_io_fprintf(SmDebugOutput, SmDebugOutput->f_timeout,
160 else if (sm_debug_active(&SmDBGPidTime, 2))
164 gettimeofday(&tv, NULL);
165 sm_io_fprintf(SmDebugOutput, SmDebugOutput->f_timeout,
171 else if (sm_debug_active(&SmDBGPidTime, 1))
173 static char str[32] = "[1900-00-00/00:00:00] ";
177 currt = time((time_t *)0);
178 tmp = localtime(&currt);
179 snprintf(str, sizeof(str), "[%d-%02d-%02d/%02d:%02d:%02d] ",
180 1900 + tmp->tm_year, /* HACK */
183 tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
184 sm_io_fprintf(SmDebugOutput, SmDebugOutput->f_timeout,
185 "%ld: %s ", (long) getpid(), str);
187 #endif /* _FFR_DEBUG_PID_TIME */
189 SM_VA_START(ap, fmt);
190 sm_io_vfprintf(SmDebugOutput, SmDebugOutput->f_timeout, fmt, ap);
195 ** SM_DFLUSH -- Flush debug output.
207 sm_io_flush(SmDebugOutput, SM_TIME_DEFAULT);
211 ** This is the internal database of debug settings.
212 ** The semantics of looking up a setting in the settings database
213 ** are that the *last* setting specified in a -d option on the sendmail
214 ** command line that matches a given SM_DEBUG structure is the one that is
215 ** used. That is necessary to conform to the existing semantics of
216 ** the sendmail -d option. We store the settings as a linked list in
217 ** reverse order, so when we do a lookup, we take the *first* entry
221 typedef struct sm_debug_setting SM_DEBUG_SETTING_T;
222 struct sm_debug_setting
224 const char *ds_pattern;
225 unsigned int ds_level;
226 SM_DEBUG_SETTING_T *ds_next;
228 SM_DEBUG_SETTING_T *SmDebugSettings = NULL;
231 ** We keep a linked list of SM_DEBUG structures that have been initialized,
232 ** for use by sm_debug_reset.
235 SM_DEBUG_T *SmDebugInitialized = NULL;
237 const char SmDebugMagic[] = "sm_debug";
240 ** SM_DEBUG_RESET -- Reset SM_DEBUG structures.
242 ** Reset all SM_DEBUG structures back to the uninitialized state.
243 ** This is used by sm_debug_addsetting to ensure that references to
244 ** SM_DEBUG structures that occur before sendmail processes its -d flags
245 ** do not cause those structures to be permanently forced to level 0.
259 for (debug = SmDebugInitialized;
261 debug = debug->debug_next)
263 debug->debug_level = SM_DEBUG_UNKNOWN;
265 SmDebugInitialized = NULL;
269 ** SM_DEBUG_ADDSETTING_X -- add an entry to the database of debug settings
272 ** pattern -- a shell-style glob pattern (see sm_match).
273 ** WARNING: the storage for 'pattern' will be owned by
274 ** the debug package, so it should either be a string
275 ** literal or the result of a call to sm_strdup_x.
276 ** level -- a non-negative integer.
282 ** F:sm_heap -- out of memory
286 sm_debug_addsetting_x(pattern, level)
290 SM_DEBUG_SETTING_T *s;
292 SM_REQUIRE(pattern != NULL);
293 SM_REQUIRE(level >= 0);
294 s = sm_malloc_x(sizeof(SM_DEBUG_SETTING_T));
295 s->ds_pattern = pattern;
296 s->ds_level = (unsigned int) level;
297 s->ds_next = SmDebugSettings;
303 ** PARSE_NAMED_SETTING_X -- process a symbolic debug setting
306 ** s -- Points to a non-empty \0 or , terminated string,
307 ** of which the initial character is not a digit.
310 ** pointer to terminating \0 or , character.
313 ** F:sm.heap -- out of memory.
316 ** adds the setting to the database.
320 parse_named_setting_x(s)
323 const char *pat, *endpat;
327 while (*s != '\0' && *s != ',' && *s != '.')
334 while (isascii(*s) && isdigit(*s))
336 level = level * 10 + (*s - '0');
345 sm_debug_addsetting_x(sm_strndup_x(pat, endpat - pat), level);
347 /* skip trailing junk */
348 while (*s != '\0' && *s != ',')
355 ** SM_DEBUG_ADDSETTINGS_X -- process a list of debug options
358 ** s -- a list of debug settings, eg the argument to the
359 ** sendmail -d option.
361 ** The syntax of the string s is as follows:
363 ** <settings> ::= <setting> | <settings> "," <setting>
364 ** <setting> ::= <categories> | <categories> "." <level>
365 ** <categories> ::= [a-zA-Z_*?][a-zA-Z0-9_*?]*
367 ** However, note that we skip over anything we don't
368 ** understand, rather than report an error.
374 ** F:sm.heap -- out of memory
377 ** updates the database of debug settings.
381 sm_debug_addsettings_x(s)
393 s = parse_named_setting_x(s);
398 ** SM_DEBUG_LOADLEVEL -- Get activation level of the specified debug object.
401 ** debug -- debug object.
404 ** Activation level of the specified debug object.
407 ** Ensures that the debug object is initialized.
411 sm_debug_loadlevel(debug)
414 if (debug->debug_level == SM_DEBUG_UNKNOWN)
416 SM_DEBUG_SETTING_T *s;
418 for (s = SmDebugSettings; s != NULL; s = s->ds_next)
420 if (sm_match(debug->debug_name, s->ds_pattern))
422 debug->debug_level = s->ds_level;
426 debug->debug_level = 0;
428 debug->debug_next = SmDebugInitialized;
429 SmDebugInitialized = debug;
431 return (int) debug->debug_level;
435 ** SM_DEBUG_LOADACTIVE -- Activation level reached?
438 ** debug -- debug object.
439 ** level -- level to check.
442 ** true iff the activation level of the specified debug
446 ** Ensures that the debug object is initialized.
450 sm_debug_loadactive(debug, level)
454 return sm_debug_loadlevel(debug) >= level;