Initial revision 6759
[qball-mpd.git] / src / log.c
blob7701da3a5335b2e1ba55cdacdb44f5b7f347c46f
1 /* the Music Player Daemon (MPD)
2 * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
3 * This project's homepage is: http://www.musicpd.org
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.
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 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include "log.h"
21 #include "conf.h"
22 #include "myfprintf.h"
23 #include "utils.h"
25 #include <assert.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdarg.h>
29 #include <time.h>
31 static unsigned int logLevel = LOG_LEVEL_LOW;
32 static int warningFlushed;
33 static int stdout_mode = 1;
34 static char *warningBuffer;
35 static int out_fd = -1;
36 static int err_fd = -1;
37 static const char *out_filename;
38 static const char *err_filename;
40 /* redirect stdin to /dev/null to work around a libao bug */
41 static void redirect_stdin(void)
43 int fd;
44 if ((fd = open("/dev/null", O_RDONLY)) < 0)
45 FATAL("failed to open /dev/null %s\n", strerror(errno));
46 if (dup2(fd, STDIN_FILENO) < 0)
47 FATAL("dup2 stdin: %s\n", strerror(errno));
50 static void redirect_logs(void)
52 assert(out_fd > 0);
53 assert(err_fd > 0);
54 if (dup2(out_fd, STDOUT_FILENO) < 0)
55 FATAL("problems dup2 stdout : %s\n", strerror(errno));
56 if (dup2(err_fd, STDERR_FILENO) < 0)
57 FATAL("problems dup2 stderr : %s\n", strerror(errno));
60 static const char *log_date(void)
62 static char buf[16];
63 time_t t = time(NULL);
64 strftime(buf, 16, "%b %d %H:%M : ", localtime(&t));
65 return buf;
68 #define BUFFER_LENGTH 4096
69 static void buffer_warning(const char *fmt, va_list args)
71 char buffer[BUFFER_LENGTH];
72 char *tmp = buffer;
73 size_t len = BUFFER_LENGTH;
75 if (!stdout_mode) {
76 memcpy(buffer, log_date(), 15);
77 tmp += 15;
78 len -= 15;
81 vsnprintf(tmp, len, fmt, args);
82 warningBuffer = appendToString(warningBuffer, buffer);
84 va_end(args);
87 static void do_log(FILE *fp, const char *fmt, va_list args)
89 if (!stdout_mode)
90 fwrite(log_date(), 15, 1, fp);
91 vfprintf(fp, fmt, args);
94 void flushWarningLog(void)
96 char *s = warningBuffer;
98 DEBUG("flushing warning messages\n");
100 if (warningBuffer != NULL)
102 while (s != NULL) {
103 char *next = strchr(s, '\n');
104 if (next == NULL) break;
105 *next = '\0';
106 next++;
107 fprintf(stderr, "%s\n", s);
108 s = next;
111 warningBuffer = NULL;
114 warningFlushed = 1;
116 DEBUG("done flushing warning messages\n");
119 void initLog(const int verbose)
121 ConfigParam *param;
123 /* unbuffer stdout, stderr is unbuffered by default, leave it */
124 setvbuf(stdout, (char *)NULL, _IONBF, 0);
126 if (verbose) {
127 logLevel = LOG_LEVEL_DEBUG;
128 return;
130 if (!(param = getConfigParam(CONF_LOG_LEVEL)))
131 return;
132 if (0 == strcmp(param->value, "default")) {
133 logLevel = LOG_LEVEL_LOW;
134 } else if (0 == strcmp(param->value, "secure")) {
135 logLevel = LOG_LEVEL_SECURE;
136 } else if (0 == strcmp(param->value, "verbose")) {
137 logLevel = LOG_LEVEL_DEBUG;
138 } else {
139 FATAL("unknown log level \"%s\" at line %i\n",
140 param->value, param->line);
144 void open_log_files(const int use_stdout)
146 mode_t prev;
147 ConfigParam *param;
149 if (use_stdout) {
150 flushWarningLog();
151 return;
154 prev = umask(0066);
155 param = parseConfigFilePath(CONF_LOG_FILE, 1);
156 out_filename = param->value;
157 out_fd = open(out_filename, O_CREAT | O_WRONLY | O_APPEND, 0666);
158 if (out_fd < 0)
159 FATAL("problem opening log file \"%s\" (config line %i) for "
160 "writing\n", param->value, param->line);
162 param = parseConfigFilePath(CONF_ERROR_FILE, 1);
163 err_filename = param->value;
164 err_fd = open(err_filename, O_CREAT | O_WRONLY | O_APPEND, 0666);
165 if (err_fd < 0)
166 FATAL("problem opening error file \"%s\" (config line %i) for "
167 "writing\n", param->value, param->line);
169 umask(prev);
172 void setup_log_output(const int use_stdout)
174 fflush(NULL);
175 if (!use_stdout) {
176 redirect_logs();
177 stdout_mode = 0;
178 flushWarningLog();
180 redirect_stdin();
183 #define log_func(func,level,fp) \
184 mpd_printf void func(const char *fmt, ...) \
186 if (logLevel >= level) { \
187 va_list args; \
188 va_start(args, fmt); \
189 do_log(fp, fmt, args); \
190 va_end(args); \
194 log_func(ERROR, 0, stderr)
195 log_func(LOG, 0, stdout)
196 log_func(SECURE, LOG_LEVEL_SECURE, stdout)
197 log_func(DEBUG, LOG_LEVEL_DEBUG, stdout)
199 #undef log_func
201 void WARNING(const char *fmt, ...)
203 va_list args;
204 va_start(args, fmt);
205 if (warningFlushed) {
206 do_log(stderr, fmt, args);
207 } else
208 buffer_warning(fmt, args);
209 va_end(args);
212 mpd_printf mpd_noreturn void FATAL(const char *fmt, ...)
214 va_list args;
215 va_start(args, fmt);
216 do_log(stderr, fmt, args);
217 va_end(args);
218 exit(EXIT_FAILURE);
221 int cycle_log_files(void)
223 mode_t prev;
225 if (stdout_mode)
226 return 0;
227 assert(out_filename);
228 assert(err_filename);
230 DEBUG("Cycling log files...\n");
231 close_log_files();
233 prev = umask(0066);
235 out_fd = open(out_filename, O_CREAT | O_WRONLY | O_APPEND, 0666);
236 if (out_fd < 0) {
237 ERROR("error re-opening log file: %s\n", out_filename);
238 return -1;
241 err_fd = open(err_filename, O_CREAT | O_WRONLY | O_APPEND, 0666);
242 if (err_fd < 0) {
243 ERROR("error re-opening error file: %s\n", err_filename);
244 return -1;
247 umask(prev);
249 redirect_logs();
250 DEBUG("Done cycling log files\n");
251 return 0;
254 void close_log_files(void)
256 if (stdout_mode)
257 return;
258 assert(out_fd > 0);
259 assert(err_fd > 0);
260 xclose(out_fd);
261 xclose(err_fd);