4cf7c21641324bafc5bab0b9c559fbccaefea81d
[bbaumbach/samba-autobuild/.git] / source4 / lib / util / debug.c
1 /*
2    Unix SMB/CIFS implementation.
3    Samba debug functions
4    Copyright (C) Andrew Tridgell 2003
5    Copyright (C) James J Myers   2003
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23 #include "system/filesys.h"
24 #include "system/time.h"
25 #include "dynconfig.h"
26
27 /**
28  * @file
29  * @brief Debug logging
30  **/
31
32 /* this global variable determines what messages are printed */
33 int DEBUGLEVEL;
34
35
36 /* the registered mutex handlers */
37 static struct {
38         const char *name;
39         struct debug_ops ops;
40 } debug_handlers;
41
42 /* state variables for the debug system */
43 static struct {
44         int fd;
45         enum debug_logtype logtype;
46         const char *prog_name;
47 } state;
48
49 static void log_timestring(int level, const char *location, const char *func)
50 {
51         char *t = NULL;
52         char *s = NULL;
53
54         if (state.logtype != DEBUG_FILE) return;
55
56         t = timestring(NULL, time(NULL));
57         if (!t) return;
58
59         asprintf(&s, "[%s, %d %s:%s()]\n", t, level, location, func);
60         talloc_free(t);
61         if (!s) return;
62
63         write(state.fd, s, strlen(s));
64         free(s);
65 }
66
67 /*
68   the backend for debug messages. Note that the DEBUG() macro has already
69   ensured that the log level has been met before this is called
70 */
71 void do_debug_header(int level, const char *location, const char *func)
72 {
73         log_timestring(level, location, func);
74         log_task_id();
75 }
76
77 /*
78   the backend for debug messages. Note that the DEBUG() macro has already
79   ensured that the log level has been met before this is called
80 */
81 void do_debug(const char *format, ...) _PRINTF_ATTRIBUTE(1,2)
82 {
83         va_list ap;
84         char *s = NULL;
85
86         if (state.fd == 0) {
87                 reopen_logs();
88         }
89
90         if (state.fd <= 0) return;
91
92         va_start(ap, format);
93         vasprintf(&s, format, ap);
94         va_end(ap);
95
96         write(state.fd, s, strlen(s));
97         fsync(state.fd);
98         free(s);
99 }
100
101 /**
102   reopen the log file (usually called because the log file name might have changed)
103 */
104 void reopen_logs(void)
105 {
106         const char *logfile = lp_logfile();
107         char *fname = NULL;
108         int old_fd = state.fd;
109
110         switch (state.logtype) {
111         case DEBUG_STDOUT:
112                 state.fd = 1;
113                 break;
114
115         case DEBUG_STDERR:
116                 state.fd = 2;
117                 break;
118
119         case DEBUG_FILE:
120                 if ((*logfile) == '/') {
121                         fname = strdup(logfile);
122                 } else {
123                         asprintf(&fname, "%s/%s.log", dyn_LOGFILEBASE, state.prog_name);
124                 }
125                 if (fname) {
126                         int newfd = open(fname, O_CREAT|O_APPEND|O_WRONLY, 0600);
127                         if (newfd == -1) {
128                                 DEBUG(1, ("Failed to open new logfile: %s\n", fname));
129                         } else {
130                                 state.fd = newfd;
131                         }
132                         free(fname);
133                 } else {
134                         DEBUG(1, ("Failed to find name for file-based logfile!\n"));
135                 }
136
137                 break;
138         }
139
140         if (old_fd > 2) {
141                 fsync(old_fd);
142                 close(old_fd);
143         }
144 }
145
146 /**
147   control the name of the logfile and whether logging will be to stdout, stderr
148   or a file
149 */
150 void setup_logging(const char *prog_name, enum debug_logtype new_logtype)
151 {
152         if (state.logtype < new_logtype) {
153                 state.logtype = new_logtype;
154         }
155         if (prog_name) {
156                 state.prog_name = prog_name;
157         }
158         reopen_logs();
159 }
160
161 /**
162   return a string constant containing n tabs
163   no more than 10 tabs are returned
164 */
165 const char *do_debug_tab(uint_t n)
166 {
167         const char *tabs[] = {"", "\t", "\t\t", "\t\t\t", "\t\t\t\t", "\t\t\t\t\t", 
168                               "\t\t\t\t\t\t", "\t\t\t\t\t\t\t", "\t\t\t\t\t\t\t\t", 
169                               "\t\t\t\t\t\t\t\t\t", "\t\t\t\t\t\t\t\t\t\t"};
170         return tabs[MIN(n, 10)];
171 }
172
173
174 /**
175   log suspicious usage - print comments and backtrace
176 */      
177 void log_suspicious_usage(const char *from, const char *info)
178 {
179         if (debug_handlers.ops.log_suspicious_usage) {
180                 debug_handlers.ops.log_suspicious_usage(from, info);
181         }
182 }
183
184
185 /**
186   print suspicious usage - print comments and backtrace
187 */      
188
189 void print_suspicious_usage(const char* from, const char* info)
190 {
191         if (debug_handlers.ops.print_suspicious_usage) {
192                 debug_handlers.ops.print_suspicious_usage(from, info);
193         }
194 }
195
196 uint32_t get_task_id(void)
197 {
198         if (debug_handlers.ops.get_task_id) {
199                 return debug_handlers.ops.get_task_id();
200         }
201         return getpid();
202 }
203
204 void log_task_id(void)
205 {
206         if (debug_handlers.ops.log_task_id) {
207                 debug_handlers.ops.log_task_id(state.fd);
208         }
209 }
210
211 /**
212   register a set of debug handlers. 
213 */
214 void register_debug_handlers(const char *name, struct debug_ops *ops)
215 {
216         debug_handlers.name = name;
217         debug_handlers.ops = *ops;
218 }