Ready to release 0.2.2
[gpgme.git] / gpgme / debug.c
1 /* debug.c
2  *      Copyright (C) 2001 g10 Code GmbH
3  *
4  * This file is part of GPGME.
5  *
6  * GPGME is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GPGME is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdarg.h>
26 #include <unistd.h>
27 #include <ctype.h>
28 #ifndef HAVE_DOSISH_SYSTEM
29   #include <sys/types.h>
30   #include <sys/stat.h>
31   #include <fcntl.h>
32 #endif
33 #include <assert.h>
34
35 #include "util.h"
36 #include "sema.h"
37
38 DEFINE_STATIC_LOCK (debug_lock);
39
40 struct debug_control_s {
41     FILE *fp;
42     char fname[100];
43 };
44
45 static int debug_level = 0;
46 static FILE *errfp = NULL;
47
48 /****************
49  * remove leading and trailing white spaces
50  */
51 static char *
52 trim_spaces( char *str )
53 {
54     char *string, *p, *mark;
55
56     string = str;
57     /* find first non space character */
58     for( p=string; *p && isspace( *(byte*)p ) ; p++ )
59         ;
60     /* move characters */
61     for( (mark = NULL); (*string = *p); string++, p++ )
62         if( isspace( *(byte*)p ) ) {
63             if( !mark )
64                 mark = string ;
65         }
66         else
67             mark = NULL ;
68     if( mark )
69         *mark = '\0' ;  /* remove trailing spaces */
70
71     return str ;
72 }
73
74
75 static void
76 debug_init (void)
77 {
78     static volatile int initialized = 0;
79        
80     if (initialized) 
81         return;
82     LOCK (debug_lock);
83     if (!initialized) {
84         const char *e = getenv ("GPGME_DEBUG");
85         const char *s1, *s2;;
86
87         initialized = 1;
88         debug_level = 0;
89         errfp = stderr;
90         if (e) {
91             debug_level = atoi (e);
92             s1 = strchr (e, ':');
93             if (s1 
94 #ifndef HAVE_DOSISH_SYSTEM
95                 && getuid () == geteuid ()
96 #endif
97                 ) {
98                 char *p;
99                 FILE *fp;
100
101                 s1++;
102                 if ( !(s2 = strchr (s1, ':')) )
103                     s2 = s1 + strlen(s1);
104                 p = xtrymalloc (s2-s1+1);
105                 if (p) {
106                     memcpy (p, s1, s2-s1);
107                     p[s2-s1] = 0;
108                     trim_spaces (p);
109                     fp = fopen (p,"a");
110                     if (fp) {
111                         setvbuf (fp, NULL, _IOLBF, 0);
112                         errfp = fp;
113                     }
114                     xfree (p);
115                 }
116             }
117         }
118
119         if (debug_level > 0)
120             fprintf (errfp,"gpgme_debug: level=%d\n", debug_level);
121     }
122     UNLOCK (debug_lock);
123 }
124
125 int
126 _gpgme_debug_level ()
127 {
128     return debug_level;
129 }
130
131 void
132 _gpgme_debug (int level, const char *format, ...)
133 {
134     va_list arg_ptr ;
135
136     debug_init ();
137     if ( debug_level < level )
138         return;
139     
140     va_start ( arg_ptr, format ) ;
141     LOCK (debug_lock);
142     vfprintf (errfp, format, arg_ptr) ;
143     va_end ( arg_ptr ) ;
144     if( format && *format && format[strlen(format)-1] != '\n' )
145         putc ('\n', errfp);
146     UNLOCK (debug_lock);
147     fflush (errfp);
148 }
149
150
151
152 void
153 _gpgme_debug_begin ( void **helper, int level, const char *text)
154 {
155     struct debug_control_s *ctl;
156
157     debug_init ();
158
159     *helper = NULL;
160     if ( debug_level < level )
161         return;
162     ctl = xtrycalloc (1, sizeof *ctl );
163     if (!ctl) {
164         _gpgme_debug (255, __FILE__ ":" STR2(__LINE__)": out of core");
165         return;
166     }
167
168     /* Oh what a pitty that we don't have a asprintf or snprintf under
169      * Windoze.  We definitely should write our own clib for W32! */
170     sprintf ( ctl->fname, "/tmp/gpgme_debug.%d.%p", getpid (), ctl );
171   #if defined (__GLIBC__) || defined (HAVE_DOSISH_SYSTEM)
172     ctl->fp = fopen (ctl->fname, "w+x");
173   #else 
174     {
175         int fd  = open (ctl->fname, O_WRONLY|O_TRUNC|O_CREAT|O_EXCL,
176                         S_IRUSR|S_IWUSR );
177         if (fd == -1)
178             ctl->fp = NULL;
179         else
180             ctl->fp = fdopen (fd, "w+");
181     }
182   #endif
183     if (!ctl->fp) {
184         _gpgme_debug (255,__FILE__ ":" STR2(__LINE__)": failed to create `%s'",
185                       ctl->fname );
186         xfree (ctl);
187         return;
188     }
189     *helper = ctl;
190     _gpgme_debug_add (helper, "%s", text );
191 }
192
193 int
194 _gpgme_debug_enabled (void **helper)
195 {
196     return helper && *helper;
197 }
198
199
200 void
201 _gpgme_debug_add (void **helper, const char *format, ...)
202 {
203     struct debug_control_s *ctl = *helper;
204     va_list arg_ptr ;
205
206     if ( !*helper )
207         return;
208     
209     va_start ( arg_ptr, format ) ;
210     vfprintf (ctl->fp, format, arg_ptr) ;
211     va_end ( arg_ptr ) ;
212 }
213
214 void
215 _gpgme_debug_end (void **helper, const char *text)
216 {
217     struct debug_control_s *ctl = *helper;
218     int c, last_c=EOF;
219
220     if ( !*helper )
221         return;
222     
223     _gpgme_debug_add (helper, "%s", text );
224     fflush (ctl->fp); /* we need this for the buggy Windoze libc */
225     rewind (ctl->fp);
226     LOCK (debug_lock);
227     while ( (c=getc (ctl->fp)) != EOF ) {
228         putc (c, errfp);
229         last_c = c;
230     }
231     if (last_c != '\n')
232         putc ('\n', errfp);
233     UNLOCK (debug_lock);
234     
235     fclose (ctl->fp);
236     remove (ctl->fname);
237     xfree (ctl);
238     *helper = NULL;
239 }
240