Deleted Added
full compact
debug.c (132943) debug.c (141858)
1/*
1/*
2 * Copyright (c) 2000, 2001, 2003 Sendmail, Inc. and its suppliers.
2 * Copyright (c) 2000, 2001, 2003, 2004 Sendmail, Inc. and its suppliers.
3 * All rights reserved.
4 *
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 */
9
10#include <sm/gen.h>
3 * All rights reserved.
4 *
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 */
9
10#include <sm/gen.h>
11SM_RCSID("@(#)$Id: debug.c,v 1.29 2003/01/10 00:26:06 ca Exp $")
11SM_RCSID("@(#)$Id: debug.c,v 1.30 2004/08/03 20:10:26 ca Exp $")
12
13/*
14** libsm debugging and tracing
15** For documentation, see debug.html.
16*/
17
18#include <ctype.h>
19#include <stdlib.h>
20#include <setjmp.h>
21#include <sm/io.h>
22#include <sm/assert.h>
23#include <sm/conf.h>
24#include <sm/debug.h>
25#include <sm/string.h>
26#include <sm/varargs.h>
27#include <sm/heap.h>
28
12
13/*
14** libsm debugging and tracing
15** For documentation, see debug.html.
16*/
17
18#include <ctype.h>
19#include <stdlib.h>
20#include <setjmp.h>
21#include <sm/io.h>
22#include <sm/assert.h>
23#include <sm/conf.h>
24#include <sm/debug.h>
25#include <sm/string.h>
26#include <sm/varargs.h>
27#include <sm/heap.h>
28
29static void sm_debug_reset __P((void));
30static const char *parse_named_setting_x __P((const char *));
31
29/*
30** Abstractions for printing trace messages.
31*/
32
33/*
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.
39*/
40
41static SM_FILE_T *SmDebugOutput = smioout;
42
43/*
44** SM_DEBUG_FILE -- Returns current debug file pointer.
45**
46** Parameters:
47** none.
48**
49** Returns:
50** current debug file pointer.
51*/
52
53SM_FILE_T *
54sm_debug_file()
55{
56 return SmDebugOutput;
57}
58
59/*
60** SM_DEBUG_SETFILE -- Sets debug file pointer.
61**
62** Parameters:
63** fp -- new debug file pointer.
64**
65** Returns:
66** none.
67**
68** Side Effects:
69** Sets SmDebugOutput.
70*/
71
72void
73sm_debug_setfile(fp)
74 SM_FILE_T *fp;
75{
76 SmDebugOutput = fp;
77}
78
79/*
80** SM_DEBUG_CLOSE -- Close debug file pointer.
81**
82** Parameters:
83** none.
84**
85** Returns:
86** none.
87**
88** Side Effects:
89** Closes SmDebugOutput.
90*/
91
92void
93sm_debug_close()
94{
95 if (SmDebugOutput != NULL && SmDebugOutput != smioout)
96 {
97 sm_io_close(SmDebugOutput, SM_TIME_DEFAULT);
98 SmDebugOutput = NULL;
99 }
100}
101
102/*
103** SM_DPRINTF -- printf() for debug output.
104**
105** Parameters:
106** fmt -- format for printf()
107**
108** Returns:
109** none.
110*/
111
112void
113#if SM_VA_STD
114sm_dprintf(char *fmt, ...)
115#else /* SM_VA_STD */
116sm_dprintf(fmt, va_alist)
117 char *fmt;
118 va_dcl
119#endif /* SM_VA_STD */
120{
121 SM_VA_LOCAL_DECL
122
123 if (SmDebugOutput == NULL)
124 return;
125 SM_VA_START(ap, fmt);
126 sm_io_vfprintf(SmDebugOutput, SmDebugOutput->f_timeout, fmt, ap);
127 SM_VA_END(ap);
128}
129
130/*
131** SM_DFLUSH -- Flush debug output.
132**
133** Parameters:
134** none.
135**
136** Returns:
137** none.
138*/
139
140void
141sm_dflush()
142{
143 sm_io_flush(SmDebugOutput, SM_TIME_DEFAULT);
144}
145
146/*
147** This is the internal database of debug settings.
148** The semantics of looking up a setting in the settings database
149** are that the *last* setting specified in a -d option on the sendmail
150** command line that matches a given SM_DEBUG structure is the one that is
151** used. That is necessary to conform to the existing semantics of
152** the sendmail -d option. We store the settings as a linked list in
153** reverse order, so when we do a lookup, we take the *first* entry
154** that matches.
155*/
156
157typedef struct sm_debug_setting SM_DEBUG_SETTING_T;
158struct sm_debug_setting
159{
160 const char *ds_pattern;
161 unsigned int ds_level;
162 SM_DEBUG_SETTING_T *ds_next;
163};
164SM_DEBUG_SETTING_T *SmDebugSettings = NULL;
165
166/*
167** We keep a linked list of SM_DEBUG structures that have been initialized,
168** for use by sm_debug_reset.
169*/
170
171SM_DEBUG_T *SmDebugInitialized = NULL;
172
173const char SmDebugMagic[] = "sm_debug";
174
175/*
176** SM_DEBUG_RESET -- Reset SM_DEBUG structures.
177**
178** Reset all SM_DEBUG structures back to the uninitialized state.
179** This is used by sm_debug_addsetting to ensure that references to
180** SM_DEBUG structures that occur before sendmail processes its -d flags
181** do not cause those structures to be permanently forced to level 0.
182**
183** Parameters:
184** none.
185**
186** Returns:
187** none.
188*/
189
32/*
33** Abstractions for printing trace messages.
34*/
35
36/*
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.
42*/
43
44static SM_FILE_T *SmDebugOutput = smioout;
45
46/*
47** SM_DEBUG_FILE -- Returns current debug file pointer.
48**
49** Parameters:
50** none.
51**
52** Returns:
53** current debug file pointer.
54*/
55
56SM_FILE_T *
57sm_debug_file()
58{
59 return SmDebugOutput;
60}
61
62/*
63** SM_DEBUG_SETFILE -- Sets debug file pointer.
64**
65** Parameters:
66** fp -- new debug file pointer.
67**
68** Returns:
69** none.
70**
71** Side Effects:
72** Sets SmDebugOutput.
73*/
74
75void
76sm_debug_setfile(fp)
77 SM_FILE_T *fp;
78{
79 SmDebugOutput = fp;
80}
81
82/*
83** SM_DEBUG_CLOSE -- Close debug file pointer.
84**
85** Parameters:
86** none.
87**
88** Returns:
89** none.
90**
91** Side Effects:
92** Closes SmDebugOutput.
93*/
94
95void
96sm_debug_close()
97{
98 if (SmDebugOutput != NULL && SmDebugOutput != smioout)
99 {
100 sm_io_close(SmDebugOutput, SM_TIME_DEFAULT);
101 SmDebugOutput = NULL;
102 }
103}
104
105/*
106** SM_DPRINTF -- printf() for debug output.
107**
108** Parameters:
109** fmt -- format for printf()
110**
111** Returns:
112** none.
113*/
114
115void
116#if SM_VA_STD
117sm_dprintf(char *fmt, ...)
118#else /* SM_VA_STD */
119sm_dprintf(fmt, va_alist)
120 char *fmt;
121 va_dcl
122#endif /* SM_VA_STD */
123{
124 SM_VA_LOCAL_DECL
125
126 if (SmDebugOutput == NULL)
127 return;
128 SM_VA_START(ap, fmt);
129 sm_io_vfprintf(SmDebugOutput, SmDebugOutput->f_timeout, fmt, ap);
130 SM_VA_END(ap);
131}
132
133/*
134** SM_DFLUSH -- Flush debug output.
135**
136** Parameters:
137** none.
138**
139** Returns:
140** none.
141*/
142
143void
144sm_dflush()
145{
146 sm_io_flush(SmDebugOutput, SM_TIME_DEFAULT);
147}
148
149/*
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
157** that matches.
158*/
159
160typedef struct sm_debug_setting SM_DEBUG_SETTING_T;
161struct sm_debug_setting
162{
163 const char *ds_pattern;
164 unsigned int ds_level;
165 SM_DEBUG_SETTING_T *ds_next;
166};
167SM_DEBUG_SETTING_T *SmDebugSettings = NULL;
168
169/*
170** We keep a linked list of SM_DEBUG structures that have been initialized,
171** for use by sm_debug_reset.
172*/
173
174SM_DEBUG_T *SmDebugInitialized = NULL;
175
176const char SmDebugMagic[] = "sm_debug";
177
178/*
179** SM_DEBUG_RESET -- Reset SM_DEBUG structures.
180**
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.
185**
186** Parameters:
187** none.
188**
189** Returns:
190** none.
191*/
192
190void
193static void
191sm_debug_reset()
192{
193 SM_DEBUG_T *debug;
194
195 for (debug = SmDebugInitialized;
196 debug != NULL;
197 debug = debug->debug_next)
198 {
199 debug->debug_level = SM_DEBUG_UNKNOWN;
200 }
201 SmDebugInitialized = NULL;
202}
203
204/*
205** SM_DEBUG_ADDSETTING_X -- add an entry to the database of debug settings
206**
207** Parameters:
208** pattern -- a shell-style glob pattern (see sm_match).
209** WARNING: the storage for 'pattern' will be owned by
210** the debug package, so it should either be a string
211** literal or the result of a call to sm_strdup_x.
212** level -- a non-negative integer.
213**
214** Returns:
215** none.
216**
217** Exceptions:
218** F:sm_heap -- out of memory
219*/
220
221void
222sm_debug_addsetting_x(pattern, level)
223 const char *pattern;
224 int level;
225{
226 SM_DEBUG_SETTING_T *s;
227
228 SM_REQUIRE(pattern != NULL);
229 SM_REQUIRE(level >= 0);
230 s = sm_malloc_x(sizeof(SM_DEBUG_SETTING_T));
231 s->ds_pattern = pattern;
232 s->ds_level = (unsigned int) level;
233 s->ds_next = SmDebugSettings;
234 SmDebugSettings = s;
235 sm_debug_reset();
236}
237
238/*
239** PARSE_NAMED_SETTING_X -- process a symbolic debug setting
240**
241** Parameters:
242** s -- Points to a non-empty \0 or , terminated string,
243** of which the initial character is not a digit.
244**
245** Returns:
246** pointer to terminating \0 or , character.
247**
248** Exceptions:
249** F:sm.heap -- out of memory.
250**
251** Side Effects:
252** adds the setting to the database.
253*/
254
255static const char *
256parse_named_setting_x(s)
194sm_debug_reset()
195{
196 SM_DEBUG_T *debug;
197
198 for (debug = SmDebugInitialized;
199 debug != NULL;
200 debug = debug->debug_next)
201 {
202 debug->debug_level = SM_DEBUG_UNKNOWN;
203 }
204 SmDebugInitialized = NULL;
205}
206
207/*
208** SM_DEBUG_ADDSETTING_X -- add an entry to the database of debug settings
209**
210** Parameters:
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.
216**
217** Returns:
218** none.
219**
220** Exceptions:
221** F:sm_heap -- out of memory
222*/
223
224void
225sm_debug_addsetting_x(pattern, level)
226 const char *pattern;
227 int level;
228{
229 SM_DEBUG_SETTING_T *s;
230
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;
237 SmDebugSettings = s;
238 sm_debug_reset();
239}
240
241/*
242** PARSE_NAMED_SETTING_X -- process a symbolic debug setting
243**
244** Parameters:
245** s -- Points to a non-empty \0 or , terminated string,
246** of which the initial character is not a digit.
247**
248** Returns:
249** pointer to terminating \0 or , character.
250**
251** Exceptions:
252** F:sm.heap -- out of memory.
253**
254** Side Effects:
255** adds the setting to the database.
256*/
257
258static const char *
259parse_named_setting_x(s)
257 register const char *s;
260 const char *s;
258{
259 const char *pat, *endpat;
260 int level;
261
262 pat = s;
263 while (*s != '\0' && *s != ',' && *s != '.')
264 ++s;
265 endpat = s;
266 if (*s == '.')
267 {
268 ++s;
269 level = 0;
270 while (isascii(*s) && isdigit(*s))
271 {
272 level = level * 10 + (*s - '0');
273 ++s;
274 }
275 if (level < 0)
276 level = 0;
277 }
278 else
279 level = 1;
280
281 sm_debug_addsetting_x(sm_strndup_x(pat, endpat - pat), level);
282
283 /* skip trailing junk */
284 while (*s != '\0' && *s != ',')
285 ++s;
286
287 return s;
288}
289
290/*
291** SM_DEBUG_ADDSETTINGS_X -- process a list of debug options
292**
293** Parameters:
294** s -- a list of debug settings, eg the argument to the
295** sendmail -d option.
296**
297** The syntax of the string s is as follows:
298**
299** <settings> ::= <setting> | <settings> "," <setting>
300** <setting> ::= <categories> | <categories> "." <level>
301** <categories> ::= [a-zA-Z_*?][a-zA-Z0-9_*?]*
302**
303** However, note that we skip over anything we don't
304** understand, rather than report an error.
305**
306** Returns:
307** none.
308**
309** Exceptions:
310** F:sm.heap -- out of memory
311**
312** Side Effects:
313** updates the database of debug settings.
314*/
315
316void
317sm_debug_addsettings_x(s)
261{
262 const char *pat, *endpat;
263 int level;
264
265 pat = s;
266 while (*s != '\0' && *s != ',' && *s != '.')
267 ++s;
268 endpat = s;
269 if (*s == '.')
270 {
271 ++s;
272 level = 0;
273 while (isascii(*s) && isdigit(*s))
274 {
275 level = level * 10 + (*s - '0');
276 ++s;
277 }
278 if (level < 0)
279 level = 0;
280 }
281 else
282 level = 1;
283
284 sm_debug_addsetting_x(sm_strndup_x(pat, endpat - pat), level);
285
286 /* skip trailing junk */
287 while (*s != '\0' && *s != ',')
288 ++s;
289
290 return s;
291}
292
293/*
294** SM_DEBUG_ADDSETTINGS_X -- process a list of debug options
295**
296** Parameters:
297** s -- a list of debug settings, eg the argument to the
298** sendmail -d option.
299**
300** The syntax of the string s is as follows:
301**
302** <settings> ::= <setting> | <settings> "," <setting>
303** <setting> ::= <categories> | <categories> "." <level>
304** <categories> ::= [a-zA-Z_*?][a-zA-Z0-9_*?]*
305**
306** However, note that we skip over anything we don't
307** understand, rather than report an error.
308**
309** Returns:
310** none.
311**
312** Exceptions:
313** F:sm.heap -- out of memory
314**
315** Side Effects:
316** updates the database of debug settings.
317*/
318
319void
320sm_debug_addsettings_x(s)
318 register const char *s;
321 const char *s;
319{
320 for (;;)
321 {
322 if (*s == '\0')
323 return;
324 if (*s == ',')
325 {
326 ++s;
327 continue;
328 }
329 s = parse_named_setting_x(s);
330 }
331}
332
333/*
334** SM_DEBUG_LOADLEVEL -- Get activation level of the specified debug object.
335**
336** Parameters:
337** debug -- debug object.
338**
339** Returns:
340** Activation level of the specified debug object.
341**
342** Side Effects:
343** Ensures that the debug object is initialized.
344*/
345
346int
347sm_debug_loadlevel(debug)
348 SM_DEBUG_T *debug;
349{
350 if (debug->debug_level == SM_DEBUG_UNKNOWN)
351 {
352 SM_DEBUG_SETTING_T *s;
353
354 for (s = SmDebugSettings; s != NULL; s = s->ds_next)
355 {
356 if (sm_match(debug->debug_name, s->ds_pattern))
357 {
358 debug->debug_level = s->ds_level;
359 goto initialized;
360 }
361 }
362 debug->debug_level = 0;
363 initialized:
364 debug->debug_next = SmDebugInitialized;
365 SmDebugInitialized = debug;
366 }
367 return (int) debug->debug_level;
368}
369
370/*
371** SM_DEBUG_LOADACTIVE -- Activation level reached?
372**
373** Parameters:
374** debug -- debug object.
375** level -- level to check.
376**
377** Returns:
378** true iff the activation level of the specified debug
379** object >= level.
380**
381** Side Effects:
382** Ensures that the debug object is initialized.
383*/
384
385bool
386sm_debug_loadactive(debug, level)
387 SM_DEBUG_T *debug;
388 int level;
389{
390 return sm_debug_loadlevel(debug) >= level;
391}
322{
323 for (;;)
324 {
325 if (*s == '\0')
326 return;
327 if (*s == ',')
328 {
329 ++s;
330 continue;
331 }
332 s = parse_named_setting_x(s);
333 }
334}
335
336/*
337** SM_DEBUG_LOADLEVEL -- Get activation level of the specified debug object.
338**
339** Parameters:
340** debug -- debug object.
341**
342** Returns:
343** Activation level of the specified debug object.
344**
345** Side Effects:
346** Ensures that the debug object is initialized.
347*/
348
349int
350sm_debug_loadlevel(debug)
351 SM_DEBUG_T *debug;
352{
353 if (debug->debug_level == SM_DEBUG_UNKNOWN)
354 {
355 SM_DEBUG_SETTING_T *s;
356
357 for (s = SmDebugSettings; s != NULL; s = s->ds_next)
358 {
359 if (sm_match(debug->debug_name, s->ds_pattern))
360 {
361 debug->debug_level = s->ds_level;
362 goto initialized;
363 }
364 }
365 debug->debug_level = 0;
366 initialized:
367 debug->debug_next = SmDebugInitialized;
368 SmDebugInitialized = debug;
369 }
370 return (int) debug->debug_level;
371}
372
373/*
374** SM_DEBUG_LOADACTIVE -- Activation level reached?
375**
376** Parameters:
377** debug -- debug object.
378** level -- level to check.
379**
380** Returns:
381** true iff the activation level of the specified debug
382** object >= level.
383**
384** Side Effects:
385** Ensures that the debug object is initialized.
386*/
387
388bool
389sm_debug_loadactive(debug, level)
390 SM_DEBUG_T *debug;
391 int level;
392{
393 return sm_debug_loadlevel(debug) >= level;
394}