1 /**
2  * gam_error.c: the debugging intrastructure
3  *
4  * Allow to use GAM_DEBUG environment variable or SIG_USR2 for
5  * dynamic debugging of clients and server.
6  *
7  * Daniel Veillard <veillard@redhat.com>
8  * See the Copyright file.
9  */
10 #include <config.h>
11 #include <stdio.h>
12 #include <stdarg.h>
13 #include <stdlib.h>
14 #include <signal.h>
15 #include <errno.h>
16 #include "gam_error.h"
17 
18 typedef void (*signal_handler) (int);
19 
20 extern void gam_show_debug(void);
21 extern void gam_got_signal (void);
22 
23 int gam_debug_active = 0;
24 static int initialized = 0;
25 static int do_debug = 0;
26 static int got_signal = 0;
27 static FILE *debug_out = NULL;
28 
29 static void
gam_error_handle_signal(void)30 gam_error_handle_signal(void)
31 {
32     if (got_signal == 0)
33         return;
34 
35     got_signal = 0;
36 
37     if (do_debug == 0) {
38         if (debug_out != stderr) {
39             char path[50] = "/tmp/gamin_debug_XXXXXX";
40             int fd = mkstemp(path);
41 
42             if (fd >= 0) {
43                 debug_out = fdopen(fd, "a");
44                 if (debug_out != NULL) {
45                     do_debug = 1;
46                     gam_debug_active = 1;
47                     gam_show_debug();
48                 }
49             }
50         }
51     } else {
52         if (debug_out != stderr) {
53             do_debug = 0;
54             gam_debug_active = 0;
55             if (debug_out != NULL) {
56                 fflush(debug_out);
57                 fclose(debug_out);
58                 debug_out = NULL;
59             }
60         }
61     }
62 }
63 
64 
65 static void
gam_error_signal(int no)66 gam_error_signal(int no)
67 {
68     got_signal = !got_signal;
69     gam_debug_active = -1;      /* force going into gam_debug() */
70     gam_got_signal ();
71 }
72 
73 /**
74  * gam_error_init:
75  *
76  * Initialization routine for the error and debug handling.
77  */
78 void
gam_error_init(void)79 gam_error_init(void)
80 {
81     if (initialized == 0) {
82         struct sigaction oldact;
83 
84         initialized = 1;
85 
86         if (getenv("GAM_DEBUG") != NULL) {
87 	    debug_out = stderr;
88 	    gam_debug_active = 1;
89 	    do_debug = 1;
90             /* Fake the signal */
91             got_signal = 1;
92             gam_error_handle_signal();
93         }
94 
95 	/* if there is already an handler, leave it as is to
96 	 * avoid disturbing the application's behaviour */
97 	if (sigaction (SIGUSR2, NULL, &oldact) == 0) {
98 	    if (oldact.sa_handler == NULL && oldact.sa_sigaction == NULL)
99 	        signal(SIGUSR2, gam_error_signal);
100 	}
101     }
102 }
103 
104 /**
105  * gam_error_init:
106  *
107  * Checking routine to call from time to time to handle asynchronous
108  * error debugging events.
109  */
110 void
gam_error_check(void)111 gam_error_check(void)
112 {
113     if (initialized == 0)
114         gam_error_init();
115 
116     if (got_signal)
117         gam_error_handle_signal();
118 }
119 
120 int
gam_errno(void)121 gam_errno(void)
122 {
123     return (errno);
124 }
125 
126 /**
127  * gam_error:
128  * @file: the filename where the error was detected
129  * @line: the line where the error was detected
130  * @function: the function where the error was detected
131  * @format: *printf format
132  * @...:  extra arguments
133  *
134  * Log an error, currently only stderr, but could go into syslog
135  */
136 void
gam_error(const char * file,int line,const char * function,const char * format,...)137 gam_error(const char *file, int line, const char *function,
138           const char *format, ...)
139 {
140     va_list args;
141 
142     if (initialized == 0)
143         gam_error_init();
144 
145     if (got_signal)
146         gam_error_handle_signal();
147 
148     if ((file == NULL) || (function == NULL) || (format == NULL))
149         return;
150 
151     va_start(args, format);
152     vfprintf((debug_out ? debug_out : stderr), format, args);
153     va_end(args);
154 
155     if (debug_out)
156         fflush(debug_out);
157 }
158 
159 /**
160  * gam_debug:
161  * @file: the filename where the error was detected
162  * @line: the line where the error was detected
163  * @function: the function where the error was detected
164  * @format: *printf format
165  * @...:  extra arguments
166  *
167  * Log a debug message, fi those are activated by the GAM_DEBUG environment
168  */
169 void
gam_debug(const char * file,int line,const char * function,const char * format,...)170 gam_debug(const char *file, int line, const char *function,
171           const char *format, ...)
172 {
173     va_list args;
174 
175     if (initialized == 0)
176         gam_error_init();
177 
178     if (got_signal)
179         gam_error_handle_signal();
180 
181     if ((do_debug == 0) || (gam_debug_active == 0))
182         return;
183 
184     if ((file == NULL) || (function == NULL) || (format == NULL))
185         return;
186 
187     va_start(args, format);
188     vfprintf((debug_out ? debug_out : stdout), format, args);
189     va_end(args);
190     if (debug_out)
191         fflush(debug_out);
192 }
193