8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / sendmail / libsm / debug.c
blobea9cd846ace5ec798b9e641c5788c021e2a4e3b9
1 /*
2 * Copyright (c) 2000, 2001, 2003, 2004 Sendmail, Inc. and its suppliers.
3 * All rights reserved.
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 */
10 #include <sm/gen.h>
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.
18 #include <ctype.h>
19 #include <stdlib.h>
20 #if _FFR_DEBUG_PID_TIME
21 #include <unistd.h>
22 #include <time.h>
23 #endif /* _FFR_DEBUG_PID_TIME */
24 #include <setjmp.h>
25 #include <sm/io.h>
26 #include <sm/assert.h>
27 #include <sm/conf.h>
28 #include <sm/debug.h>
29 #include <sm/string.h>
30 #include <sm/varargs.h>
31 #include <sm/heap.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.
53 ** Parameters:
54 ** none.
56 ** Returns:
57 ** current debug file pointer.
60 SM_FILE_T *
61 sm_debug_file()
63 return SmDebugOutput;
67 ** SM_DEBUG_SETFILE -- Sets debug file pointer.
69 ** Parameters:
70 ** fp -- new debug file pointer.
72 ** Returns:
73 ** none.
75 ** Side Effects:
76 ** Sets SmDebugOutput.
79 void
80 sm_debug_setfile(fp)
81 SM_FILE_T *fp;
83 SmDebugOutput = fp;
87 ** SM_DEBUG_CLOSE -- Close debug file pointer.
89 ** Parameters:
90 ** none.
92 ** Returns:
93 ** none.
95 ** Side Effects:
96 ** Closes SmDebugOutput.
99 void
100 sm_debug_close()
102 if (SmDebugOutput != NULL && SmDebugOutput != smioout)
104 sm_io_close(SmDebugOutput, SM_TIME_DEFAULT);
105 SmDebugOutput = NULL;
110 ** SM_DPRINTF -- printf() for debug output.
112 ** Parameters:
113 ** fmt -- format for printf()
115 ** Returns:
116 ** none.
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 */
124 void
125 #if SM_VA_STD
126 sm_dprintf(char *fmt, ...)
127 #else /* SM_VA_STD */
128 sm_dprintf(fmt, va_alist)
129 char *fmt;
130 va_dcl
131 #endif /* SM_VA_STD */
133 SM_VA_LOCAL_DECL
135 if (SmDebugOutput == NULL)
136 return;
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] ";
142 struct tm *tmp;
143 time_t currt;
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 */
149 tmp->tm_mon + 1,
150 tmp->tm_mday,
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);
159 SM_VA_END(ap);
163 ** SM_DFLUSH -- Flush debug output.
165 ** Parameters:
166 ** none.
168 ** Returns:
169 ** none.
172 void
173 sm_dflush()
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
186 ** that matches.
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.
215 ** Parameters:
216 ** none.
218 ** Returns:
219 ** none.
222 static void
223 sm_debug_reset()
225 SM_DEBUG_T *debug;
227 for (debug = SmDebugInitialized;
228 debug != NULL;
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
239 ** Parameters:
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.
246 ** Returns:
247 ** none.
249 ** Exceptions:
250 ** F:sm_heap -- out of memory
253 void
254 sm_debug_addsetting_x(pattern, level)
255 const char *pattern;
256 int 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;
266 SmDebugSettings = s;
267 sm_debug_reset();
271 ** PARSE_NAMED_SETTING_X -- process a symbolic debug setting
273 ** Parameters:
274 ** s -- Points to a non-empty \0 or , terminated string,
275 ** of which the initial character is not a digit.
277 ** Returns:
278 ** pointer to terminating \0 or , character.
280 ** Exceptions:
281 ** F:sm.heap -- out of memory.
283 ** Side Effects:
284 ** adds the setting to the database.
287 static const char *
288 parse_named_setting_x(s)
289 const char *s;
291 const char *pat, *endpat;
292 int level;
294 pat = s;
295 while (*s != '\0' && *s != ',' && *s != '.')
296 ++s;
297 endpat = s;
298 if (*s == '.')
300 ++s;
301 level = 0;
302 while (isascii(*s) && isdigit(*s))
304 level = level * 10 + (*s - '0');
305 ++s;
307 if (level < 0)
308 level = 0;
310 else
311 level = 1;
313 sm_debug_addsetting_x(sm_strndup_x(pat, endpat - pat), level);
315 /* skip trailing junk */
316 while (*s != '\0' && *s != ',')
317 ++s;
319 return s;
323 ** SM_DEBUG_ADDSETTINGS_X -- process a list of debug options
325 ** Parameters:
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.
338 ** Returns:
339 ** none.
341 ** Exceptions:
342 ** F:sm.heap -- out of memory
344 ** Side Effects:
345 ** updates the database of debug settings.
348 void
349 sm_debug_addsettings_x(s)
350 const char *s;
352 for (;;)
354 if (*s == '\0')
355 return;
356 if (*s == ',')
358 ++s;
359 continue;
361 s = parse_named_setting_x(s);
366 ** SM_DEBUG_LOADLEVEL -- Get activation level of the specified debug object.
368 ** Parameters:
369 ** debug -- debug object.
371 ** Returns:
372 ** Activation level of the specified debug object.
374 ** Side Effects:
375 ** Ensures that the debug object is initialized.
379 sm_debug_loadlevel(debug)
380 SM_DEBUG_T *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;
391 goto initialized;
394 debug->debug_level = 0;
395 initialized:
396 debug->debug_next = SmDebugInitialized;
397 SmDebugInitialized = debug;
399 return (int) debug->debug_level;
403 ** SM_DEBUG_LOADACTIVE -- Activation level reached?
405 ** Parameters:
406 ** debug -- debug object.
407 ** level -- level to check.
409 ** Returns:
410 ** true iff the activation level of the specified debug
411 ** object >= level.
413 ** Side Effects:
414 ** Ensures that the debug object is initialized.
417 bool
418 sm_debug_loadactive(debug, level)
419 SM_DEBUG_T *debug;
420 int level;
422 return sm_debug_loadlevel(debug) >= level;