Line data Source code
1 : /* debug.c - helpful output in desperate situations
2 : Copyright (C) 2000 Werner Koch (dd9jn)
3 : Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2009 g10 Code GmbH
4 :
5 : This file is part of GPGME.
6 :
7 : GPGME is free software; you can redistribute it and/or modify it
8 : under the terms of the GNU Lesser General Public License as
9 : published by the Free Software Foundation; either version 2.1 of
10 : the License, or (at your option) any later version.
11 :
12 : GPGME is distributed in the hope that it will be useful, but
13 : WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : Lesser General Public License for more details.
16 :
17 : You should have received a copy of the GNU Lesser General Public
18 : License along with this program; if not, write to the Free Software
19 : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20 : MA 02110-1301, USA. */
21 :
22 : #if HAVE_CONFIG_H
23 : #include <config.h>
24 : #endif
25 : #include <stdio.h>
26 : #include <stdlib.h>
27 : #include <string.h>
28 : #include <stdarg.h>
29 : #ifdef HAVE_UNISTD_H
30 : # include <unistd.h>
31 : #endif
32 : #include <ctype.h>
33 : #include <errno.h>
34 : #include <time.h>
35 : #ifndef HAVE_DOSISH_SYSTEM
36 : # ifdef HAVE_SYS_TYPES_H
37 : # include <sys/types.h>
38 : # endif
39 : # ifdef HAVE_SYS_STAT_H
40 : # include <sys/stat.h>
41 : # endif
42 : # include <fcntl.h>
43 : #endif
44 : #include <assert.h>
45 :
46 : #include "util.h"
47 : #include "ath.h"
48 : #include "sema.h"
49 : #include "sys-util.h"
50 : #include "debug.h"
51 :
52 :
53 : /* Lock to serialize initialization of the debug output subsystem and
54 : output of actual debug messages. */
55 : DEFINE_STATIC_LOCK (debug_lock);
56 :
57 : /* The amount of detail requested by the user, per environment
58 : variable GPGME_DEBUG. */
59 : static int debug_level;
60 :
61 : /* The output stream for the debug messages. */
62 : static FILE *errfp;
63 :
64 : /* If not NULL, this malloced string is used instead of the
65 : GPGME_DEBUG envvar. It must have been set before the debug
66 : subsystem has been initialized. Using it later may or may not have
67 : any effect. */
68 : static char *envvar_override;
69 :
70 :
71 : #ifdef HAVE_TLS
72 : #define FRAME_NR
73 : static __thread int frame_nr = 0;
74 : #endif
75 :
76 : void
77 106388 : _gpgme_debug_frame_begin (void)
78 : {
79 : #ifdef FRAME_NR
80 106388 : frame_nr++;
81 : #endif
82 106388 : }
83 :
84 106284 : int _gpgme_debug_frame_end (void)
85 : {
86 : #ifdef FRAME_NR
87 106284 : frame_nr--;
88 : #endif
89 106284 : return 0;
90 : }
91 :
92 :
93 :
94 : /* Remove leading and trailing white spaces. */
95 : static char *
96 0 : trim_spaces (char *str)
97 : {
98 : char *string, *p, *mark;
99 :
100 0 : string = str;
101 : /* Find first non space character. */
102 0 : for (p = string; *p && isspace (*(unsigned char *) p); p++)
103 : ;
104 : /* Move characters. */
105 0 : for (mark = NULL; (*string = *p); string++, p++)
106 0 : if (isspace (*(unsigned char *) p))
107 : {
108 0 : if (!mark)
109 0 : mark = string;
110 : }
111 : else
112 0 : mark = NULL;
113 0 : if (mark)
114 0 : *mark = '\0'; /* Remove trailing spaces. */
115 :
116 0 : return str;
117 : }
118 :
119 :
120 : /* This is an internal function to set debug info. The caller must
121 : assure that this function is called only by one thread at a time.
122 : The function may have no effect if called after the debug system
123 : has been initialized. Returns 0 on success. */
124 : int
125 0 : _gpgme_debug_set_debug_envvar (const char *value)
126 : {
127 0 : free (envvar_override);
128 0 : envvar_override = strdup (value);
129 0 : return !envvar_override;
130 : }
131 :
132 :
133 : static void
134 119 : debug_init (void)
135 : {
136 : static int initialized;
137 :
138 119 : LOCK (debug_lock);
139 119 : if (!initialized)
140 : {
141 : gpgme_error_t err;
142 : char *e;
143 : const char *s1, *s2;;
144 :
145 119 : if (envvar_override)
146 : {
147 0 : e = strdup (envvar_override);
148 0 : free (envvar_override);
149 0 : envvar_override = NULL;
150 : }
151 : else
152 : {
153 119 : err = _gpgme_getenv ("GPGME_DEBUG", &e);
154 119 : if (err)
155 : {
156 0 : UNLOCK (debug_lock);
157 0 : return;
158 : }
159 : }
160 :
161 119 : initialized = 1;
162 119 : errfp = stderr;
163 119 : if (e)
164 : {
165 0 : debug_level = atoi (e);
166 0 : s1 = strchr (e, PATHSEP_C);
167 0 : if (s1)
168 : {
169 : #ifndef HAVE_DOSISH_SYSTEM
170 0 : if (getuid () == geteuid ()
171 : #if defined(HAVE_GETGID) && defined(HAVE_GETEGID)
172 0 : && getgid () == getegid ()
173 : #endif
174 : )
175 : {
176 : #endif
177 : char *p;
178 : FILE *fp;
179 :
180 0 : s1++;
181 0 : if (!(s2 = strchr (s1, PATHSEP_C)))
182 0 : s2 = s1 + strlen (s1);
183 0 : p = malloc (s2 - s1 + 1);
184 0 : if (p)
185 : {
186 0 : memcpy (p, s1, s2 - s1);
187 0 : p[s2-s1] = 0;
188 0 : trim_spaces (p);
189 0 : fp = fopen (p,"a");
190 0 : if (fp)
191 : {
192 0 : setvbuf (fp, NULL, _IOLBF, 0);
193 0 : errfp = fp;
194 : }
195 0 : free (p);
196 : }
197 : #ifndef HAVE_DOSISH_SYSTEM
198 : }
199 : #endif
200 : }
201 0 : free (e);
202 : }
203 : }
204 119 : UNLOCK (debug_lock);
205 :
206 119 : if (debug_level > 0)
207 : {
208 0 : _gpgme_debug (DEBUG_INIT, "gpgme_debug: level=%d\n", debug_level);
209 : #ifdef HAVE_W32_SYSTEM
210 : {
211 : const char *name = _gpgme_get_inst_dir ();
212 : _gpgme_debug (DEBUG_INIT, "gpgme_debug: gpgme='%s'\n",
213 : name? name: "?");
214 : }
215 : #endif
216 : }
217 : }
218 :
219 :
220 :
221 : /* This should be called as soon as the locks are initialized. It is
222 : required so that the assuan logging gets conncted to the gpgme log
223 : stream as early as possible. */
224 : void
225 119 : _gpgme_debug_subsystem_init (void)
226 : {
227 119 : debug_init ();
228 119 : }
229 :
230 :
231 :
232 :
233 : /* Log the formatted string FORMAT at debug level LEVEL or higher.
234 : *
235 : * Returns: 0
236 : *
237 : * Note that we always return 0 because the old TRACE macro evaluated
238 : * to 0 which issues a warning with newer gcc version about an unused
239 : * values. By using a return value of this function this can be
240 : * avoided. Fixme: It might be useful to check whether the return
241 : * value from the TRACE macros are actually used somewhere.
242 : */
243 : int
244 329461 : _gpgme_debug (int level, const char *format, ...)
245 : {
246 : va_list arg_ptr;
247 : int saved_errno;
248 :
249 329461 : saved_errno = errno;
250 411376 : if (debug_level < level)
251 411376 : return 0;
252 :
253 0 : va_start (arg_ptr, format);
254 0 : LOCK (debug_lock);
255 : {
256 : struct tm *tp;
257 0 : time_t atime = time (NULL);
258 :
259 0 : tp = localtime (&atime);
260 0 : fprintf (errfp, "GPGME %04d-%02d-%02d %02d:%02d:%02d <0x%04llx> ",
261 0 : 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
262 : tp->tm_hour, tp->tm_min, tp->tm_sec,
263 0 : (unsigned long long) ath_self ());
264 : }
265 : #ifdef FRAME_NR
266 : {
267 : int indent;
268 :
269 0 : indent = frame_nr > 0? (2 * (frame_nr - 1)):0;
270 0 : fprintf (errfp, "%*s", indent < 40? indent : 40, "");
271 : }
272 : #endif
273 :
274 0 : vfprintf (errfp, format, arg_ptr);
275 0 : va_end (arg_ptr);
276 0 : if(format && *format && format[strlen (format) - 1] != '\n')
277 0 : putc ('\n', errfp);
278 0 : UNLOCK (debug_lock);
279 0 : fflush (errfp);
280 :
281 0 : gpg_err_set_errno (saved_errno);
282 0 : return 0;
283 : }
284 :
285 :
286 : /* Start a new debug line in *LINE, logged at level LEVEL or higher,
287 : and starting with the formatted string FORMAT. */
288 : void
289 35401 : _gpgme_debug_begin (void **line, int level, const char *format, ...)
290 : {
291 : va_list arg_ptr;
292 : int res;
293 :
294 35401 : if (debug_level < level)
295 : {
296 : /* Disable logging of this line. */
297 35401 : *line = NULL;
298 35401 : return;
299 : }
300 :
301 0 : va_start (arg_ptr, format);
302 0 : res = gpgrt_vasprintf ((char **) line, format, arg_ptr);
303 0 : va_end (arg_ptr);
304 0 : if (res < 0)
305 0 : *line = NULL;
306 : }
307 :
308 :
309 : /* Add the formatted string FORMAT to the debug line *LINE. */
310 : void
311 49215 : _gpgme_debug_add (void **line, const char *format, ...)
312 : {
313 : va_list arg_ptr;
314 : char *toadd;
315 : char *result;
316 : int res;
317 :
318 49215 : if (!*line)
319 49215 : return;
320 :
321 0 : va_start (arg_ptr, format);
322 0 : res = gpgrt_vasprintf (&toadd, format, arg_ptr);
323 0 : va_end (arg_ptr);
324 0 : if (res < 0)
325 : {
326 0 : gpgrt_free (*line);
327 0 : *line = NULL;
328 : }
329 0 : res = gpgrt_asprintf (&result, "%s%s", *(char **) line, toadd);
330 0 : gpgrt_free (toadd);
331 0 : gpgrt_free (*line);
332 0 : if (res < 0)
333 0 : *line = NULL;
334 : else
335 0 : *line = result;
336 : }
337 :
338 :
339 : /* Finish construction of *LINE and send it to the debug output
340 : stream. */
341 : void
342 17858 : _gpgme_debug_end (void **line)
343 : {
344 17858 : if (!*line)
345 17858 : return;
346 :
347 : /* The smallest possible level is 1, so force logging here by
348 : using that. */
349 0 : _gpgme_debug (1, "%s", *line);
350 0 : gpgrt_free (*line);
351 0 : *line = NULL;
352 : }
353 :
354 :
355 : #define TOHEX(val) (((val) < 10) ? ((val) + '0') : ((val) - 10 + 'a'))
356 :
357 : void
358 11834 : _gpgme_debug_buffer (int lvl, const char *const fmt,
359 : const char *const func, const char *const buffer,
360 : size_t len)
361 : {
362 11834 : int idx = 0;
363 : int j;
364 :
365 : if (!_gpgme_debug_trace ())
366 : return;
367 :
368 11834 : if (!buffer)
369 0 : return;
370 :
371 228306 : while (idx < len)
372 : {
373 : char str[51];
374 204643 : char *strp = str;
375 204643 : char *strp2 = &str[34];
376 :
377 2836338 : for (j = 0; j < 16; j++)
378 : {
379 : unsigned char val;
380 2631695 : if (idx < len)
381 : {
382 2555137 : val = buffer[idx++];
383 2555137 : *(strp++) = TOHEX (val >> 4);
384 2555137 : *(strp++) = TOHEX (val % 16);
385 2555137 : *(strp2++) = isprint (val) ? val : '.';
386 : }
387 : else
388 : {
389 76558 : *(strp++) = ' ';
390 76558 : *(strp++) = ' ';
391 : }
392 2631695 : if (j == 7)
393 204636 : *(strp++) = ' ';
394 : }
395 204643 : *(strp++) = ' ';
396 204643 : *(strp2) = '\0';
397 :
398 204643 : _gpgme_debug (lvl, fmt, func, str);
399 : }
400 : }
|