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}
|