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.32 2009/09/20 05:38:46 ca Exp $")
14 ** libsm debugging and tracing
15 ** For documentation, see debug.html.
20 #if _FFR_DEBUG_PID_TIME
23 #endif /* _FFR_DEBUG_PID_TIME */
26 #include <sm/assert.h>
29 #include <sm/string.h>
30 #include <sm/varargs.h>
33 static void sm_debug_reset
__P((void));
34 static const char *parse_named_setting_x
__P((const char *));
37 ** Abstractions for printing trace messages.
41 ** The output file to which trace output is directed.
42 ** There is a controversy over whether this variable
43 ** should be process global or thread local.
44 ** To make the interface more abstract, we've hidden the
45 ** variable behind access functions.
48 static SM_FILE_T
*SmDebugOutput
= smioout
;
51 ** SM_DEBUG_FILE -- Returns current debug file pointer.
57 ** current debug file pointer.
67 ** SM_DEBUG_SETFILE -- Sets debug file pointer.
70 ** fp -- new debug file pointer.
76 ** Sets SmDebugOutput.
87 ** SM_DEBUG_CLOSE -- Close debug file pointer.
96 ** Closes SmDebugOutput.
102 if (SmDebugOutput
!= NULL
&& SmDebugOutput
!= smioout
)
104 sm_io_close(SmDebugOutput
, SM_TIME_DEFAULT
);
105 SmDebugOutput
= NULL
;
110 ** SM_DPRINTF -- printf() for debug output.
113 ** fmt -- format for printf()
119 #if _FFR_DEBUG_PID_TIME
120 SM_DEBUG_T SmDBGPidTime
= SM_DEBUG_INITIALIZER("sm_trace_pid_time",
121 "@(#)$Debug: sm_trace_pid_time - print pid and time in debug $");
122 #endif /* _FFR_DEBUG_PID_TIME */
126 sm_dprintf(char *fmt
, ...)
127 #else /* SM_VA_STD */
128 sm_dprintf(fmt
, va_alist
)
131 #endif /* SM_VA_STD */
135 if (SmDebugOutput
== NULL
)
137 #if _FFR_DEBUG_PID_TIME
138 /* note: this is ugly if the output isn't a full line! */
139 if (sm_debug_active(&SmDBGPidTime
, 1))
141 static char str
[32] = "[1900-00-00/00:00:00] ";
145 currt
= time((time_t *)0);
146 tmp
= localtime(&currt
);
147 snprintf(str
, sizeof(str
), "[%d-%02d-%02d/%02d:%02d:%02d] ",
148 1900 + tmp
->tm_year
, /* HACK */
151 tmp
->tm_hour
, tmp
->tm_min
, tmp
->tm_sec
);
152 sm_io_fprintf(SmDebugOutput
, SmDebugOutput
->f_timeout
,
153 "%ld: %s ", (long) getpid(), str
);
155 #endif /* _FFR_DEBUG_PID_TIME */
157 SM_VA_START(ap
, fmt
);
158 sm_io_vfprintf(SmDebugOutput
, SmDebugOutput
->f_timeout
, fmt
, ap
);
163 ** SM_DFLUSH -- Flush debug output.
175 sm_io_flush(SmDebugOutput
, SM_TIME_DEFAULT
);
179 ** This is the internal database of debug settings.
180 ** The semantics of looking up a setting in the settings database
181 ** are that the *last* setting specified in a -d option on the sendmail
182 ** command line that matches a given SM_DEBUG structure is the one that is
183 ** used. That is necessary to conform to the existing semantics of
184 ** the sendmail -d option. We store the settings as a linked list in
185 ** reverse order, so when we do a lookup, we take the *first* entry
189 typedef struct sm_debug_setting SM_DEBUG_SETTING_T
;
190 struct sm_debug_setting
192 const char *ds_pattern
;
193 unsigned int ds_level
;
194 SM_DEBUG_SETTING_T
*ds_next
;
196 SM_DEBUG_SETTING_T
*SmDebugSettings
= NULL
;
199 ** We keep a linked list of SM_DEBUG structures that have been initialized,
200 ** for use by sm_debug_reset.
203 SM_DEBUG_T
*SmDebugInitialized
= NULL
;
205 const char SmDebugMagic
[] = "sm_debug";
208 ** SM_DEBUG_RESET -- Reset SM_DEBUG structures.
210 ** Reset all SM_DEBUG structures back to the uninitialized state.
211 ** This is used by sm_debug_addsetting to ensure that references to
212 ** SM_DEBUG structures that occur before sendmail processes its -d flags
213 ** do not cause those structures to be permanently forced to level 0.
227 for (debug
= SmDebugInitialized
;
229 debug
= debug
->debug_next
)
231 debug
->debug_level
= SM_DEBUG_UNKNOWN
;
233 SmDebugInitialized
= NULL
;
237 ** SM_DEBUG_ADDSETTING_X -- add an entry to the database of debug settings
240 ** pattern -- a shell-style glob pattern (see sm_match).
241 ** WARNING: the storage for 'pattern' will be owned by
242 ** the debug package, so it should either be a string
243 ** literal or the result of a call to sm_strdup_x.
244 ** level -- a non-negative integer.
250 ** F:sm_heap -- out of memory
254 sm_debug_addsetting_x(pattern
, level
)
258 SM_DEBUG_SETTING_T
*s
;
260 SM_REQUIRE(pattern
!= NULL
);
261 SM_REQUIRE(level
>= 0);
262 s
= sm_malloc_x(sizeof(SM_DEBUG_SETTING_T
));
263 s
->ds_pattern
= pattern
;
264 s
->ds_level
= (unsigned int) level
;
265 s
->ds_next
= SmDebugSettings
;
271 ** PARSE_NAMED_SETTING_X -- process a symbolic debug setting
274 ** s -- Points to a non-empty \0 or , terminated string,
275 ** of which the initial character is not a digit.
278 ** pointer to terminating \0 or , character.
281 ** F:sm.heap -- out of memory.
284 ** adds the setting to the database.
288 parse_named_setting_x(s
)
291 const char *pat
, *endpat
;
295 while (*s
!= '\0' && *s
!= ',' && *s
!= '.')
302 while (isascii(*s
) && isdigit(*s
))
304 level
= level
* 10 + (*s
- '0');
313 sm_debug_addsetting_x(sm_strndup_x(pat
, endpat
- pat
), level
);
315 /* skip trailing junk */
316 while (*s
!= '\0' && *s
!= ',')
323 ** SM_DEBUG_ADDSETTINGS_X -- process a list of debug options
326 ** s -- a list of debug settings, eg the argument to the
327 ** sendmail -d option.
329 ** The syntax of the string s is as follows:
331 ** <settings> ::= <setting> | <settings> "," <setting>
332 ** <setting> ::= <categories> | <categories> "." <level>
333 ** <categories> ::= [a-zA-Z_*?][a-zA-Z0-9_*?]*
335 ** However, note that we skip over anything we don't
336 ** understand, rather than report an error.
342 ** F:sm.heap -- out of memory
345 ** updates the database of debug settings.
349 sm_debug_addsettings_x(s
)
361 s
= parse_named_setting_x(s
);
366 ** SM_DEBUG_LOADLEVEL -- Get activation level of the specified debug object.
369 ** debug -- debug object.
372 ** Activation level of the specified debug object.
375 ** Ensures that the debug object is initialized.
379 sm_debug_loadlevel(debug
)
382 if (debug
->debug_level
== SM_DEBUG_UNKNOWN
)
384 SM_DEBUG_SETTING_T
*s
;
386 for (s
= SmDebugSettings
; s
!= NULL
; s
= s
->ds_next
)
388 if (sm_match(debug
->debug_name
, s
->ds_pattern
))
390 debug
->debug_level
= s
->ds_level
;
394 debug
->debug_level
= 0;
396 debug
->debug_next
= SmDebugInitialized
;
397 SmDebugInitialized
= debug
;
399 return (int) debug
->debug_level
;
403 ** SM_DEBUG_LOADACTIVE -- Activation level reached?
406 ** debug -- debug object.
407 ** level -- level to check.
410 ** true iff the activation level of the specified debug
414 ** Ensures that the debug object is initialized.
418 sm_debug_loadactive(debug
, level
)
422 return sm_debug_loadlevel(debug
) >= level
;