Commit | Line | Data |
---|---|---|
059ec3d9 PH |
1 | /************************************************* |
2 | * Exim - an Internet mail transport agent * | |
3 | *************************************************/ | |
4 | ||
f9ba5e22 | 5 | /* Copyright (c) University of Cambridge 1995 - 2018 */ |
059ec3d9 PH |
6 | /* See the file NOTICE for conditions of use and distribution. */ |
7 | ||
8 | ||
9 | #include "exim.h" | |
10 | ||
c2bcbe20 | 11 | static uschar debug_buffer[2048]; |
059ec3d9 PH |
12 | static uschar *debug_ptr = debug_buffer; |
13 | static int debug_prefix_length = 0; | |
14 | ||
15 | ||
16 | ||
17 | /************************************************* | |
18 | * Print tree * | |
19 | *************************************************/ | |
20 | ||
21 | /* Recursive tree-printing subroutine. It uses a static vector of uschar to | |
22 | hold the line-drawing characters that need to be printed on every line as it | |
23 | moves down the page. This function is used only in debugging circumstances. The | |
24 | output is done via debug_printf(). */ | |
25 | ||
26 | #define tree_printlinesize 132 /* line size for printing */ | |
27 | static uschar tree_printline[tree_printlinesize]; | |
28 | ||
29 | /* Internal recursive subroutine. | |
30 | ||
31 | Arguments: | |
32 | p tree node | |
4c04137d | 33 | pos amount of indenting & vertical bars to print |
059ec3d9 PH |
34 | barswitch if TRUE print | at the pos value |
35 | ||
36 | Returns: nothing | |
37 | */ | |
38 | ||
39 | static void | |
40 | tree_printsub(tree_node *p, int pos, int barswitch) | |
41 | { | |
42 | int i; | |
acec9514 | 43 | if (p->right) tree_printsub(p->right, pos+2, 1); |
059ec3d9 PH |
44 | for (i = 0; i <= pos-1; i++) debug_printf("%c", tree_printline[i]); |
45 | debug_printf("-->%s [%d]\n", p->name, p->balance); | |
46 | tree_printline[pos] = barswitch? '|' : ' '; | |
acec9514 | 47 | if (p->left) |
059ec3d9 PH |
48 | { |
49 | tree_printline[pos+2] = '|'; | |
50 | tree_printsub(p->left, pos+2, 0); | |
51 | } | |
52 | } | |
53 | ||
54 | /* The external function, with just a tree node argument. */ | |
55 | ||
56 | void | |
57 | debug_print_tree(tree_node *p) | |
58 | { | |
59 | int i; | |
60 | for (i = 0; i < tree_printlinesize; i++) tree_printline[i] = ' '; | |
acec9514 | 61 | if (!p) debug_printf("Empty Tree\n"); else tree_printsub(p, 0, 0); |
059ec3d9 PH |
62 | debug_printf("---- End of tree ----\n"); |
63 | } | |
64 | ||
65 | ||
66 | ||
67 | /************************************************* | |
68 | * Print an argv vector * | |
69 | *************************************************/ | |
70 | ||
71 | /* Called when about to obey execv(). | |
72 | ||
73 | Argument: the argv vector | |
74 | Returns: nothing | |
75 | */ | |
76 | ||
77 | void | |
55414b25 | 78 | debug_print_argv(const uschar ** argv) |
059ec3d9 PH |
79 | { |
80 | debug_printf("exec"); | |
acec9514 | 81 | while (*argv) debug_printf(" %.256s", *argv++); |
059ec3d9 PH |
82 | debug_printf("\n"); |
83 | } | |
84 | ||
85 | ||
86 | ||
87 | /************************************************* | |
88 | * Expand and print debugging string * | |
89 | *************************************************/ | |
90 | ||
91 | /* The string is expanded and written as debugging output. If | |
92 | expansion fails, a message is written instead. | |
93 | ||
94 | Argument: the string | |
95 | Returns: nothing | |
96 | */ | |
97 | ||
98 | void | |
99 | debug_print_string(uschar *debug_string) | |
100 | { | |
acec9514 | 101 | if (!debug_string) return; |
059ec3d9 PH |
102 | HDEBUG(D_any|D_v) |
103 | { | |
104 | uschar *s = expand_string(debug_string); | |
acec9514 | 105 | if (!s) |
059ec3d9 PH |
106 | debug_printf("failed to expand debug_output \"%s\": %s\n", debug_string, |
107 | expand_string_message); | |
108 | else if (s[0] != 0) | |
109 | debug_printf("%s%s", s, (s[Ustrlen(s)-1] == '\n')? "" : "\n"); | |
110 | } | |
111 | } | |
112 | ||
113 | ||
114 | ||
115 | /************************************************* | |
116 | * Print current uids and gids * | |
117 | *************************************************/ | |
118 | ||
119 | /* | |
120 | Argument: an introductory string | |
121 | Returns: nothing | |
122 | */ | |
123 | ||
124 | void | |
125 | debug_print_ids(uschar *s) | |
126 | { | |
127 | debug_printf("%s uid=%ld gid=%ld euid=%ld egid=%ld\n", s, | |
128 | (long int)getuid(), (long int)getgid(), (long int)geteuid(), | |
129 | (long int)getegid()); | |
130 | } | |
131 | ||
132 | ||
133 | ||
134 | ||
135 | /************************************************* | |
136 | * Print debugging message * | |
137 | *************************************************/ | |
138 | ||
139 | /* There are two entries, one for use when being called directly from a | |
e1d04f48 | 140 | function with a variable argument list, one for prepending an indent. |
059ec3d9 PH |
141 | |
142 | If debug_pid is nonzero, print the pid at the start of each line. This is for | |
143 | tidier output when running parallel remote deliveries with debugging turned on. | |
144 | Must do the whole thing with a single printf and flush, as otherwise output may | |
145 | get interleaved. Since some calls to debug_printf() don't end with newline, | |
829dd842 JH |
146 | we save up the text until we do get the newline. |
147 | Take care to not disturb errno. */ | |
059ec3d9 | 148 | |
e1d04f48 JH |
149 | |
150 | /* Debug printf indented by ACL nest depth */ | |
151 | void | |
152 | debug_printf_indent(const char * format, ...) | |
153 | { | |
154 | va_list ap; | |
e1d04f48 | 155 | va_start(ap, format); |
398f9af3 | 156 | debug_vprintf(acl_level + expand_level, format, ap); |
e1d04f48 JH |
157 | va_end(ap); |
158 | } | |
159 | ||
059ec3d9 | 160 | void |
1ba28e2b | 161 | debug_printf(const char *format, ...) |
059ec3d9 PH |
162 | { |
163 | va_list ap; | |
164 | va_start(ap, format); | |
398f9af3 | 165 | debug_vprintf(0, format, ap); |
059ec3d9 PH |
166 | va_end(ap); |
167 | } | |
168 | ||
169 | void | |
398f9af3 | 170 | debug_vprintf(int indent, const char *format, va_list ap) |
059ec3d9 | 171 | { |
829dd842 JH |
172 | int save_errno = errno; |
173 | ||
174 | if (!debug_file) return; | |
059ec3d9 | 175 | |
d7ffbc12 PH |
176 | /* Various things can be inserted at the start of a line. Don't use the |
177 | tod_stamp() function for the timestamp, because that will overwrite the | |
178 | timestamp buffer, which may contain something useful. (This was a bug fix: the | |
179 | +memory debugging with +timestamp did cause a problem.) */ | |
059ec3d9 PH |
180 | |
181 | if (debug_ptr == debug_buffer) | |
182 | { | |
183 | DEBUG(D_timestamp) | |
184 | { | |
fca5cb18 JH |
185 | struct timeval now; |
186 | time_t tmp; | |
187 | struct tm * t; | |
188 | ||
189 | gettimeofday(&now, NULL); | |
190 | tmp = now.tv_sec; | |
8768d548 | 191 | t = f.timestamps_utc ? gmtime(&tmp) : localtime(&tmp); |
fca5cb18 JH |
192 | debug_ptr += sprintf(CS debug_ptr, |
193 | LOGGING(millisec) ? "%02d:%02d:%02d.%03d " : "%02d:%02d:%02d ", | |
cab0c277 | 194 | t->tm_hour, t->tm_min, t->tm_sec, (int)(now.tv_usec/1000)); |
059ec3d9 PH |
195 | } |
196 | ||
197 | DEBUG(D_pid) | |
5976eb99 | 198 | debug_ptr += sprintf(CS debug_ptr, "%5d ", (int)getpid()); |
059ec3d9 PH |
199 | |
200 | /* Set up prefix if outputting for host checking and not debugging */ | |
201 | ||
202 | if (host_checking && debug_selector == 0) | |
203 | { | |
204 | Ustrcpy(debug_ptr, ">>> "); | |
205 | debug_ptr += 4; | |
206 | } | |
207 | ||
208 | debug_prefix_length = debug_ptr - debug_buffer; | |
209 | } | |
210 | ||
398f9af3 JH |
211 | if (indent > 0) |
212 | { | |
213 | int i; | |
214 | for (i = indent >> 2; i > 0; i--) | |
ae8f9024 JH |
215 | DEBUG(D_noutf8) |
216 | { | |
217 | Ustrcpy(debug_ptr, " !"); | |
218 | debug_ptr += 4; /* 3 spaces + shriek */ | |
219 | debug_prefix_length += 4; | |
220 | } | |
221 | else | |
222 | { | |
223 | Ustrcpy(debug_ptr, " " UTF8_VERT_2DASH); | |
224 | debug_ptr += 6; /* 3 spaces + 3 UTF-8 octets */ | |
225 | debug_prefix_length += 6; | |
226 | } | |
227 | ||
f9913671 JH |
228 | Ustrncpy(debug_ptr, " ", indent &= 3); |
229 | debug_ptr += indent; | |
230 | debug_prefix_length += indent; | |
398f9af3 JH |
231 | } |
232 | ||
059ec3d9 PH |
233 | /* Use the checked formatting routine to ensure that the buffer |
234 | does not overflow. Ensure there's space for a newline at the end. */ | |
235 | ||
059ec3d9 | 236 | { |
d12746bc JH |
237 | gstring gs = { .size = (int)sizeof(debug_buffer) - 1, |
238 | .ptr = debug_ptr - debug_buffer, | |
239 | .s = debug_buffer }; | |
240 | if (!string_vformat(&gs, FALSE, format, ap)) | |
241 | { | |
242 | uschar * s = US"**** debug string too long - truncated ****\n"; | |
243 | uschar * p = gs.s + gs.ptr; | |
244 | int maxlen = gs.size - Ustrlen(s) - 2; | |
245 | if (p > gs.s + maxlen) p = gs.s + maxlen; | |
246 | if (p > gs.s && p[-1] != '\n') *p++ = '\n'; | |
247 | Ustrcpy(p, s); | |
248 | while(*debug_ptr) debug_ptr++; | |
249 | } | |
250 | else | |
251 | { | |
252 | string_from_gstring(&gs); | |
253 | debug_ptr = gs.s + gs.ptr; | |
254 | } | |
059ec3d9 PH |
255 | } |
256 | ||
059ec3d9 PH |
257 | /* Output the line if it is complete. If we added any prefix data and there |
258 | are internal newlines, make sure the prefix is on the continuation lines, | |
259 | as long as there is room in the buffer. We want to do just a single fprintf() | |
260 | so as to avoid interleaving. */ | |
261 | ||
262 | if (debug_ptr[-1] == '\n') | |
263 | { | |
264 | if (debug_prefix_length > 0) | |
265 | { | |
266 | uschar *p = debug_buffer; | |
267 | int left = sizeof(debug_buffer) - (debug_ptr - debug_buffer) - 1; | |
268 | while ((p = Ustrchr(p, '\n') + 1) != debug_ptr && | |
269 | left >= debug_prefix_length) | |
270 | { | |
271 | int len = debug_ptr - p; | |
272 | memmove(p + debug_prefix_length, p, len + 1); | |
273 | memmove(p, debug_buffer, debug_prefix_length); | |
274 | debug_ptr += debug_prefix_length; | |
275 | left -= debug_prefix_length; | |
276 | } | |
277 | } | |
278 | ||
279 | fprintf(debug_file, "%s", CS debug_buffer); | |
280 | fflush(debug_file); | |
281 | debug_ptr = debug_buffer; | |
282 | debug_prefix_length = 0; | |
283 | } | |
829dd842 | 284 | errno = save_errno; |
059ec3d9 PH |
285 | } |
286 | ||
287 | /* End of debug.c */ |