Initial revision 6759
[qball-mpd.git] / src / .svn / text-base / log.c.svn-base
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
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  * 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
17  */
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;
79         }
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)
101         {
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;
109                 }
111                 warningBuffer = NULL;
112         }
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;
129         }
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);
141         }
144 void open_log_files(const int use_stdout)
146         mode_t prev;
147         ConfigParam *param;
149         if (use_stdout) {
150                 flushWarningLog();
151                 return;
152         }
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();
179         }
180         redirect_stdin();
183 #define log_func(func,level,fp) \
184 mpd_printf void func(const char *fmt, ...) \
185 { \
186         if (logLevel >= level) { \
187                 va_list args; \
188                 va_start(args, fmt); \
189                 do_log(fp, fmt, args); \
190                 va_end(args); \
191         } \
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;
239         }
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;
245         }
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);