You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

270 lines
6.6 KiB

  1. /***************************************************************************
  2. * Copyright (C) 2005 by Dominic Rath *
  3. * Dominic.Rath@gmx.de *
  4. * *
  5. * This program is free software; you can redistribute it and/or modify *
  6. * it under the terms of the GNU General Public License as published by *
  7. * the Free Software Foundation; either version 2 of the License, or *
  8. * (at your option) any later version. *
  9. * *
  10. * This program is distributed in the hope that it will be useful, *
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  13. * GNU General Public License for more details. *
  14. * *
  15. * You should have received a copy of the GNU General Public License *
  16. * along with this program; if not, write to the *
  17. * Free Software Foundation, Inc., *
  18. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
  19. ***************************************************************************/
  20. #ifdef HAVE_CONFIG_H
  21. #include "config.h"
  22. #endif
  23. #include "log.h"
  24. #include "configuration.h"
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <stdarg.h>
  29. #include <time.h>
  30. int debug_level = -1;
  31. static FILE* log_output;
  32. static log_callback_t *log_callbacks = NULL;
  33. static time_t start;
  34. static char *log_strings[5] =
  35. {
  36. "User: ",
  37. "Error: ",
  38. "Warning:",
  39. "Info: ",
  40. "Debug: "
  41. };
  42. static int count = 0;
  43. static void log_printfv(enum log_levels level, const char *file, int line, const char *function, const char *format, va_list args)
  44. {
  45. char buffer[512];
  46. log_callback_t *cb;
  47. vsnprintf(buffer, 512, format, args);
  48. if (level == LOG_OUTPUT)
  49. {
  50. /* do not prepend any headers, just print out what we were given and return */
  51. fputs(buffer, log_output);
  52. fflush(log_output);
  53. return;
  54. }
  55. char *f = strrchr(file, '/');
  56. if (f != NULL)
  57. file = f + 1;
  58. if (debug_level >= LOG_DEBUG)
  59. {
  60. /* print with count and time information */
  61. int t=(int)(time(NULL)-start);
  62. fprintf(log_output, "%s %d %d %s:%d %s(): %s\n", log_strings[level+1], count, t, file, line, function, buffer);
  63. }
  64. else
  65. {
  66. /* do not print count and time */
  67. fprintf(log_output, "%s %s:%d %s(): %s\n", log_strings[level+1], file, line, function, buffer);
  68. }
  69. fflush(log_output);
  70. /* Never forward LOG_DEBUG, too verbose and they can be found in the log if need be */
  71. if (level <= LOG_INFO)
  72. {
  73. for (cb = log_callbacks; cb; cb = cb->next)
  74. {
  75. cb->fn(cb->priv, file, line, function, format, args);
  76. }
  77. }
  78. }
  79. void log_printf(enum log_levels level, const char *file, int line, const char *function, const char *format, ...)
  80. {
  81. count++;
  82. if (level > debug_level)
  83. return;
  84. va_list args;
  85. va_start(args, format);
  86. log_printfv(level, file, line, function, format, args);
  87. va_end(args);
  88. }
  89. void log_printfnl(enum log_levels level, const char *file, int line, const char *function, const char *format, ...)
  90. {
  91. count++;
  92. if (level > debug_level)
  93. return;
  94. char *t=malloc(strlen(format)+2);
  95. strcpy(t, format);
  96. strcat(t, "\n");
  97. va_list args;
  98. va_start(args, format);
  99. log_printfv(level, file, line, function, t, args);
  100. va_end(args);
  101. }
  102. /* change the current debug level on the fly
  103. * 0: only ERRORS
  104. * 1: + WARNINGS
  105. * 2: + INFORMATIONAL MSGS
  106. * 3: + DEBUG MSGS
  107. */
  108. int handle_debug_level_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
  109. {
  110. if (argc == 0)
  111. command_print(cmd_ctx, "debug_level: %i", debug_level);
  112. if (argc > 0)
  113. debug_level = strtoul(args[0], NULL, 0);
  114. if (debug_level < 0)
  115. debug_level = 0;
  116. if (debug_level > 3)
  117. debug_level = 3;
  118. return ERROR_OK;
  119. }
  120. int handle_log_output_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
  121. {
  122. if (argc == 1)
  123. {
  124. FILE* file = fopen(args[0], "w");
  125. if (file)
  126. {
  127. log_output = file;
  128. }
  129. }
  130. return ERROR_OK;
  131. }
  132. int log_register_commands(struct command_context_s *cmd_ctx)
  133. {
  134. start = time(NULL);
  135. register_command(cmd_ctx, NULL, "log_output", handle_log_output_command,
  136. COMMAND_ANY, "redirect logging to <file> (default: stderr)");
  137. register_command(cmd_ctx, NULL, "debug_level", handle_debug_level_command,
  138. COMMAND_ANY, "adjust debug level <0-3>");
  139. return ERROR_OK;
  140. }
  141. int log_init(struct command_context_s *cmd_ctx)
  142. {
  143. /* set defaults for daemon configuration, if not set by cmdline or cfgfile */
  144. if (debug_level == -1)
  145. debug_level = LOG_INFO;
  146. if (log_output == NULL)
  147. {
  148. log_output = stderr;
  149. }
  150. return ERROR_OK;
  151. }
  152. int set_log_output(struct command_context_s *cmd_ctx, FILE *output)
  153. {
  154. log_output = output;
  155. return ERROR_OK;
  156. }
  157. /* add/remove log callback handler */
  158. int log_add_callback(log_callback_fn fn, void *priv)
  159. {
  160. log_callback_t *cb;
  161. /* prevent the same callback to be registered more than once, just for sure */
  162. for (cb = log_callbacks; cb; cb = cb->next)
  163. {
  164. if (cb->fn == fn && cb->priv == priv)
  165. return ERROR_INVALID_ARGUMENTS;
  166. }
  167. /* alloc memory, it is safe just to return in case of an error, no need for the caller to check this */
  168. if ((cb = malloc(sizeof(log_callback_t))) == NULL)
  169. return ERROR_BUF_TOO_SMALL;
  170. /* add item to the beginning of the linked list */
  171. cb->fn = fn;
  172. cb->priv = priv;
  173. cb->next = log_callbacks;
  174. log_callbacks = cb;
  175. return ERROR_OK;
  176. }
  177. int log_remove_callback(log_callback_fn fn, void *priv)
  178. {
  179. log_callback_t *cb, **p;
  180. for (p = &log_callbacks; (cb = *p); p = &(*p)->next)
  181. {
  182. if (cb->fn == fn && cb->priv == priv)
  183. {
  184. *p = cb->next;
  185. free(cb);
  186. return ERROR_OK;
  187. }
  188. }
  189. /* no such item */
  190. return ERROR_INVALID_ARGUMENTS;
  191. }
  192. /* return allocated string w/printf() result */
  193. char *alloc_printf(const char *fmt, va_list ap)
  194. {
  195. char *string = NULL;
  196. /* start by 0 to exercise all the code paths. Need minimum 2 bytes to
  197. * fit 1 char and 0 terminator. */
  198. int size = 0;
  199. int first = 1;
  200. for (;;)
  201. {
  202. if ((string == NULL) || (!first))
  203. {
  204. size = size * 2 + 2;
  205. char *t = string;
  206. string = realloc(string, size);
  207. if (string == NULL)
  208. {
  209. if (t != NULL)
  210. free(t);
  211. return NULL;
  212. }
  213. }
  214. int ret;
  215. ret = vsnprintf(string, size, fmt, ap);
  216. /* NB! The result of the vsnprintf() might be an *EMPTY* string! */
  217. if ((ret >= 0) && ((ret + 1) < size))
  218. {
  219. return string;
  220. }
  221. /* there was just enough or not enough space, allocate more. */
  222. first = 0;
  223. }
  224. }