callbacks for logging and aborting
[nobug.git] / src / nobug_env.c
blobe404f43b54dd9c975490299a661d09cc6a7689a9
1 /*
2 This file is part of the NoBug debugging library.
4 Copyright (C) 2007, 2008, Christian Thaeter <chth@gmx.net>
6 This program 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.
11 This program 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.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, contact Christian Thaeter <ct@pipapo.org>.
19 #define NOBUG_LIBNOBUG_C
20 #include "nobug.h"
22 #include <unistd.h>
25 Env variable parsing
29 Syntax:
31 logdecl_list --> logdecl, any( ',' logdecl_list)
32 logdecl --> flag, opt(limitdecl, any(targetdecl))
33 flag --> "identifier of a flag"
34 limitdecl --> ':', "LIMITNAME"
35 targetdecl --> '@', "targetname", opt(targetopts)
36 targetopts --> '(', "options for target", ')', opt(targetopts)
38 examples:
39 NOBUG_LOG='flag,other' # set the limit of the 'default' target a default limit
40 NOBUG_LOG='flag:DEBUG' # set the limit of the 'default' target to DEBUG
41 NOBUG_LOG='flag:DEBUG@console@syslog' # set console and syslog limits for flag to DEBUG
42 NOBUG_LOG='flag:DEBUG,other:TRACE@ringbuffer'
44 TODO:
45 (options) on targets are not yet implemented
49 const struct
51 const char * name;
52 int value;
53 } nobug_limits[] =
55 { ":EMERG", LOG_EMERG },
56 { ":ALERT", LOG_ALERT },
57 { ":CRIT", LOG_CRIT },
58 { ":ERR", LOG_ERR },
59 { ":ERROR", LOG_ERR },
60 { ":WARNING", LOG_WARNING },
61 { ":WARN", LOG_WARNING },
62 { ":NOTICE", LOG_NOTICE },
63 { ":INFO", LOG_INFO },
64 { ":DEBUG", LOG_DEBUG },
65 { ":TRACE", LOG_DEBUG },
68 const char* nobug_targets[] =
69 {"@ringbuffer", "@console", "@file", "@syslog", "@application"};
72 static int
73 nobug_env_parse_string_option (const char** env, const char* key, char* value)
75 char* end = strchr (*env, ')');
76 if (!end)
77 return -1;
79 if (!strncasecmp (key, *env+1, strlen (key)))
81 char* delim = strchr (*env, '=');
82 if (delim)
84 if (delim > end || end-delim > 256)
85 return -1;
86 strncat (value, delim+1, end-delim-1);
88 *env = end + 1;
89 return 1;
91 return 0;
94 static int
95 nobug_env_parse_size_option (const char** env, const char* key, size_t* value)
97 char* end = strchr (*env, ')');
98 if (!end)
99 return -1;
101 if (!strncasecmp (key, *env+1, strlen (key)))
103 char* delim = strchr (*env, '=');
104 if (!delim || sscanf (delim+1, "%zi", value) != 1)
105 return -1;
106 *env = end + 1;
107 return 1;
109 return 0;
112 static int
113 nobug_env_parse_flag_option (const char** env, const char* key, int* flag, int mask)
116 char* end = strchr (*env, ')');
117 if (!end)
118 return -1;
120 if (!strncasecmp (key, *env+1, strlen (key)))
122 //char* delim = strchr (*env, '='); TODO =yes =no =true =false =1 =0
123 /*|| !delim || delim > end*/
124 *flag ^= mask;
125 *env = end + 1;
126 return 1;
128 return 0;
131 static int
132 nobug_env_parse_int_option (const char** env, const char* key, int* value)
134 char* end = strchr (*env, ')');
135 char* delim = strchr (*env, '=');
136 if (!end || !delim || delim > end)
137 return -1;
139 if (!strncasecmp (key, *env+1, strlen (key)))
141 if (sscanf (delim+1, "%i", value) != 1)
142 return -1;
143 *env = end + 1;
144 return 1;
146 return 0;
149 static int
150 nobug_env_parse_drop_option (const char** env)
152 char* end = strchr (*env, ')');
153 if (!end)
154 return -1;
155 *env = end + 1;
156 return 0;
160 nobug_env_parse_flag (const char* env, struct nobug_flag* flag, int default_target, int default_limit)
162 int ret = -1;
163 if (!env || !flag->name)
164 return ret;
165 size_t flaglen = strlen (flag->name);
167 if (flag != &nobug_flag_nobug)
168 nobug_log (&nobug_flag_nobug, LOG_NOTICE, "%.10llu: NOBUG: INIT_FLAG: %s", ++nobug_counter, flag->name);
172 if (!strncmp(env, flag->name, flaglen))
174 /* flagname matches */
175 int limit;
176 env += flaglen;
177 if (*env == ':')
178 for (limit = 0; limit<11; ++limit)
180 size_t limitlen = strlen (nobug_limits[limit].name);
181 if (!strncmp(env, nobug_limits[limit].name, limitlen))
183 /* found :LIMIT */
184 int target;
185 env += limitlen;
186 if (*env == '@')
187 while (*env == '@')
189 for (target = 0; target<5; ++target)
191 size_t targetlen = strlen (nobug_targets[target]);
192 if (!strncmp(env, nobug_targets[target], targetlen))
194 /* @target found */
195 env += targetlen;
196 int given = 0;
197 int s = 0;
199 int fd = -1;
200 char name[256];
201 *name = '\0';
202 size_t size = 4096;
203 int flags = 0;
205 switch (target)
207 case NOBUG_TARGET_RINGBUFFER:
208 while (*env == '(' && given >= 0)
210 /* (file=name) */
211 if ((s = nobug_env_parse_string_option (&env, "file", name)))
213 given |= s;
214 continue;
217 /* (size=N) */
218 if ((s = nobug_env_parse_size_option (&env, "size", &size)))
220 given |= s;
221 continue;
224 /* (append) (temp) (keep) */
225 if ((s = nobug_env_parse_flag_option (&env, "append",
226 &flags, NOBUG_RINGBUFFER_APPEND)))
228 given |= s;
229 continue;
231 if ((s = nobug_env_parse_flag_option (&env, "temp",
232 &flags, NOBUG_RINGBUFFER_TEMP)))
234 given |= s;
235 continue;
237 if ((s = nobug_env_parse_flag_option (&env, "keep",
238 &flags, NOBUG_RINGBUFFER_KEEP)))
240 given |= s;
241 continue;
243 if (nobug_env_parse_drop_option (&env))
244 return -1;
246 if (given < 0)
247 return -1;
248 if (given)
250 /* create new ringbuffer for flag */
251 if (flag->ringbuffer_target != &nobug_default_ringbuffer)
252 nobug_ringbuffer_delete (flag->ringbuffer_target);
253 flag->ringbuffer_target = nobug_ringbuffer_new (size, name, flags);
255 break;
256 case NOBUG_TARGET_CONSOLE:
257 while (*env == '(' && given >= 0)
259 /* (fd=N) */
260 if ((s = nobug_env_parse_int_option (&env, "fd", &fd)))
262 given |= s;
263 continue;
265 if (nobug_env_parse_drop_option (&env))
266 return -1;
268 if (given < 0)
269 return -1;
270 if (given)
272 // open fd for console
273 if (!write (fd, NULL, 0) && flag->console_target == stderr)
274 flag->console_target = fdopen (fd, "w");
276 break;
277 case NOBUG_TARGET_FILE:
278 while (*env == '(' && given >= 0)
280 /* (name=name) */
281 if ((s = nobug_env_parse_string_option (&env, "name", name)))
283 given |= s;
284 continue;
287 /* (append) */
288 if ((s = nobug_env_parse_flag_option (&env, "append",
289 &flags, NOBUG_RINGBUFFER_APPEND)))
291 given |= s;
292 continue;
294 if (nobug_env_parse_drop_option (&env))
295 return -1;
297 if (given < 0)
298 return -1;
299 if (given)
301 FILE* new = fopen (name, flags?"a":"w");
302 if (new)
304 if (flag->file_target)
305 fclose (flag->file_target);
306 flag->file_target = new;
309 break;
310 case NOBUG_TARGET_SYSLOG:
311 while (*env == '(' && given >= 0)
313 /* (facility=name) unimplemented */
314 //given |= nobug_env_parse_string_option (&env, "facility", .. );
316 /* (ident=string) */
317 if ((s = nobug_env_parse_string_option (&env, "ident", name)))
319 given |= s;
320 continue;
323 /* (cons) (pid) */
324 if ((s = nobug_env_parse_flag_option (&env, "cons",
325 &flags, LOG_CONS)))
327 given |= s;
328 continue;
330 if ((s = nobug_env_parse_flag_option (&env, "pid",
331 &flags, LOG_PID)))
333 given |= s;
334 continue;
336 if ((s = nobug_env_parse_flag_option (&env, "perror",
337 &flags, LOG_PERROR)))
339 given |= s;
340 continue;
342 if (nobug_env_parse_drop_option (&env))
343 return -1;
345 if (given < 0)
346 return -1;
347 if (given)
349 closelog ();
350 openlog (*name?strdup (name): NULL, flags, LOG_USER);
352 break;
353 case NOBUG_TARGET_APPLICATION:
354 // TODO
355 break;
357 ret = flag->limits[target] = nobug_limits[limit].value;
361 else
363 /* flag:LIMIT with no @target */
364 ret = flag->limits[default_target] = nobug_limits[limit].value;
368 else
370 /* flag with no :LIMIT */
371 ret = flag->limits[default_target] = default_limit;
374 env = strchr(env, ',');
375 if (env)
376 ++env;
378 while (env);
379 return ret;
384 nobug_env_init_flag (struct nobug_flag* flag, int default_target, int default_limit)
386 int i;
387 nobug_init();
389 if (flag->initialized)
390 return 1;
391 flag->initialized = 1;
393 /* set some defaults */
394 flag->ringbuffer_target = &nobug_default_ringbuffer;
395 flag->console_target = stderr;
396 flag->file_target = nobug_default_file;
398 if (flag->parent)
400 nobug_env_init_flag (flag->parent, default_target, default_limit);
402 for (i = NOBUG_TARGET_CONSOLE; i <= NOBUG_TARGET_APPLICATION; ++i)
404 flag->limits[i] = flag->parent->limits[i];
406 flag->ringbuffer_target = flag->parent->ringbuffer_target;
407 flag->console_target = flag->parent->console_target;
408 flag->file_target = flag->parent->file_target;
411 /* parse $NOBUG_LOG */
412 int ret = nobug_env_parse_flag (getenv("NOBUG_LOG"), flag, default_target, default_limit);
414 /* ensure that the ringbuffer is the most verbose */
415 int max;
417 for (max = i = NOBUG_TARGET_CONSOLE; i <= NOBUG_TARGET_APPLICATION; ++i)
419 max = max > flag->limits[i] ? max : flag->limits[i];
422 flag->limits[NOBUG_TARGET_RINGBUFFER] = max > flag->limits[NOBUG_TARGET_RINGBUFFER]
423 ? max : flag->limits[NOBUG_TARGET_RINGBUFFER];
425 return ret;