Postfix3.3.1
msg_output.c
[詳解]
1 /*++
2 /* NAME
3 /* msg_output 3
4 /* SUMMARY
5 /* diagnostics output management
6 /* SYNOPSIS
7 /* #include <msg_output.h>
8 /*
9 /* typedef void (*MSG_OUTPUT_FN)(int level, char *text)
10 /*
11 /* void msg_output(output_fn)
12 /* MSG_OUTPUT_FN output_fn;
13 /*
14 /* void msg_printf(level, format, ...)
15 /* int level;
16 /* const char *format;
17 /*
18 /* void msg_vprintf(level, format, ap)
19 /* int level;
20 /* const char *format;
21 /* va_list ap;
22 /*
23 /* void msg_text(level, text)
24 /* int level;
25 /* const char *text;
26 /* DESCRIPTION
27 /* This module implements low-level output management for the
28 /* msg(3) diagnostics interface.
29 /*
30 /* msg_output() registers an output handler for the diagnostics
31 /* interface. An application can register multiple output handlers.
32 /* Output handlers are called in the specified order.
33 /* An output handler takes as arguments a severity level (MSG_INFO,
34 /* MSG_WARN, MSG_ERROR, MSG_FATAL, MSG_PANIC, monotonically increasing
35 /* integer values ranging from 0 to MSG_LAST) and pre-formatted,
36 /* sanitized, text in the form of a null-terminated string.
37 /*
38 /* msg_printf() and msg_vprintf() format their arguments, sanitize the
39 /* result, and call the output handlers registered with msg_output().
40 /*
41 /* msg_text() copies a pre-formatted text, sanitizes the result, and
42 /* calls the output handlers registered with msg_output().
43 /* REENTRANCY
44 /* .ad
45 /* .fi
46 /* The above output routines are protected against ordinary
47 /* recursive calls and against re-entry by signal
48 /* handlers, with the following limitations:
49 /* .IP \(bu
50 /* The signal handlers must never return. In other words, the
51 /* signal handlers must do one or more of the following: call
52 /* _exit(), kill the process with a signal, and permanently
53 /* block the process.
54 /* .IP \(bu
55 /* The signal handlers must call the above output routines not
56 /* until after msg_output() completes initialization, and not
57 /* until after the first formatted output to a VSTRING or
58 /* VSTREAM.
59 /* .IP \(bu
60 /* Each msg_output() call-back function, and each Postfix or
61 /* system function called by that call-back function, either
62 /* must protect itself against recursive calls and re-entry
63 /* by a terminating signal handler, or it must be called
64 /* exclusively by functions in the msg_output(3) module.
65 /* .PP
66 /* When re-entrancy is detected, the requested output operation
67 /* is skipped. This prevents memory corruption of VSTREAM_ERR
68 /* data structures, and prevents deadlock on Linux releases
69 /* that use mutexes within system library routines such as
70 /* syslog(). This protection exists under the condition that
71 /* these specific resources are accessed exclusively via
72 /* msg_output() call-back functions.
73 /* LICENSE
74 /* .ad
75 /* .fi
76 /* The Secure Mailer license must be distributed with this software.
77 /* AUTHOR(S)
78 /* Wietse Venema
79 /* IBM T.J. Watson Research
80 /* P.O. Box 704
81 /* Yorktown Heights, NY 10598, USA
82 /*--*/
83 
84 /* System library. */
85 
86 #include <sys_defs.h>
87 #include <stdarg.h>
88 #include <errno.h>
89 
90 /* Utility library. */
91 
92 #include <mymalloc.h>
93 #include <vstring.h>
94 #include <vstream.h>
95 #include <msg_vstream.h>
96 #include <stringops.h>
97 #include <percentm.h>
98 #include <msg_output.h>
99 
100  /*
101  * Global scope, to discourage the compiler from doing smart things.
102  */
103 volatile int msg_vprintf_lock;
104 volatile int msg_text_lock;
105 
106  /*
107  * Private state.
108  */
109 static MSG_OUTPUT_FN *msg_output_fn = 0;
110 static int msg_output_fn_count = 0;
111 static VSTRING *msg_buffer = 0;
112 
113 /* msg_output - specify output handler */
114 
115 void msg_output(MSG_OUTPUT_FN output_fn)
116 {
117 
118  /*
119  * Allocate all resources during initialization.
120  */
121  if (msg_buffer == 0)
122  msg_buffer = vstring_alloc(100);
123 
124  /*
125  * We're not doing this often, so avoid complexity and allocate memory
126  * for an exact fit.
127  */
128  if (msg_output_fn_count == 0)
129  msg_output_fn = (MSG_OUTPUT_FN *) mymalloc(sizeof(*msg_output_fn));
130  else
131  msg_output_fn = (MSG_OUTPUT_FN *) myrealloc((void *) msg_output_fn,
132  (msg_output_fn_count + 1) * sizeof(*msg_output_fn));
133  msg_output_fn[msg_output_fn_count++] = output_fn;
134 }
135 
136 /* msg_printf - format text and log it */
137 
138 void msg_printf(int level, const char *format,...)
139 {
140  va_list ap;
141 
142  va_start(ap, format);
143  msg_vprintf(level, format, ap);
144  va_end(ap);
145 }
146 
147 /* msg_vprintf - format text and log it */
148 
149 void msg_vprintf(int level, const char *format, va_list ap)
150 {
151  int saved_errno = errno;
152 
153  if (msg_vprintf_lock == 0) {
154  msg_vprintf_lock = 1;
155  /* On-the-fly initialization for debugging test programs only. */
156  if (msg_output_fn_count == 0)
157  msg_vstream_init("unknown", VSTREAM_ERR);
158  /* OK if terminating signal handler hijacks control before next stmt. */
159  vstring_vsprintf(msg_buffer, percentm(format, errno), ap);
160  msg_text(level, vstring_str(msg_buffer));
161  msg_vprintf_lock = 0;
162  }
163  errno = saved_errno;
164 }
165 
166 /* msg_text - sanitize and log pre-formatted text */
167 
168 void msg_text(int level, const char *text)
169 {
170  int i;
171 
172  /*
173  * Sanitize the text. Use a private copy if necessary.
174  */
175  if (msg_text_lock == 0) {
176  msg_text_lock = 1;
177  /* OK if terminating signal handler hijacks control before next stmt. */
178  if (text != vstring_str(msg_buffer))
179  vstring_strcpy(msg_buffer, text);
180  printable(vstring_str(msg_buffer), '?');
181  /* On-the-fly initialization for debugging test programs only. */
182  if (msg_output_fn_count == 0)
183  msg_vstream_init("unknown", VSTREAM_ERR);
184  for (i = 0; i < msg_output_fn_count; i++)
185  msg_output_fn[i] (level, vstring_str(msg_buffer));
186  msg_text_lock = 0;
187  }
188 }
void msg_output(MSG_OUTPUT_FN output_fn)
Definition: msg_output.c:115
#define vstring_str(vp)
Definition: vstring.h:71
volatile int msg_vprintf_lock
Definition: msg_output.c:103
void * myrealloc(void *ptr, ssize_t len)
Definition: mymalloc.c:175
void msg_text(int level, const char *text)
Definition: msg_output.c:168
void msg_printf(int level, const char *format,...)
Definition: msg_output.c:138
void(* MSG_OUTPUT_FN)(int, const char *)
Definition: msg_output.h:22
VSTRING * vstring_strcpy(VSTRING *vp, const char *src)
Definition: vstring.c:431
VSTRING * vstring_vsprintf(VSTRING *vp, const char *format, va_list ap)
Definition: vstring.c:614
void msg_vprintf(int level, const char *format, va_list ap)
Definition: msg_output.c:149
volatile int msg_text_lock
Definition: msg_output.c:104
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
char * percentm(const char *str, int err)
Definition: percentm.c:52
void msg_vstream_init(const char *name, VSTREAM *vp)
Definition: msg_vstream.c:77
char * printable(char *string, int replacement)
Definition: printable.c:49
#define VSTREAM_ERR
Definition: vstream.h:68
void * mymalloc(ssize_t len)
Definition: mymalloc.c:150