Update to 6762
[qball-mpd.git] / src / .svn / text-base / log.c.svn-base
blob72c58622eaf65af482f3411896e044596d8f7ce9
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, st;
44         struct stat ss;
46         if ((st = fstat(STDIN_FILENO, &ss)) < 0 ||      /* If STDIN is already closed (e.g. mpd launched in a non-interactive shell) */
47                         ! isatty(STDIN_FILENO)) {       /* ... or FD 0 does not correspond to a tty device */
48                 return;                                 /* ... do nothing and return. */
49         }
50         if ((fd = open("/dev/null", O_RDONLY)) < 0)
51                 FATAL("failed to open /dev/null %s\n", strerror(errno));
52         if (dup2(fd, STDIN_FILENO) < 0)
53                 FATAL("dup2 stdin: %s\n", strerror(errno));
56 static void redirect_logs(void)
58         assert(out_fd > 0);
59         assert(err_fd > 0);
60         if (dup2(out_fd, STDOUT_FILENO) < 0)
61                 FATAL("problems dup2 stdout : %s\n", strerror(errno));
62         if (dup2(err_fd, STDERR_FILENO) < 0)
63                 FATAL("problems dup2 stderr : %s\n", strerror(errno));
66 static const char *log_date(void)
68         static char buf[16];
69         time_t t = time(NULL);
70         strftime(buf, 16, "%b %d %H:%M : ", localtime(&t));
71         return buf;
74 #define BUFFER_LENGTH   4096
75 static void buffer_warning(const char *fmt, va_list args)
77         char buffer[BUFFER_LENGTH];
78         char *tmp = buffer;
79         size_t len = BUFFER_LENGTH;
81         if (!stdout_mode) {
82                 memcpy(buffer, log_date(), 15);
83                 tmp += 15;
84                 len -= 15;
85         }
87         vsnprintf(tmp, len, fmt, args);
88         warningBuffer = appendToString(warningBuffer, buffer);
90         va_end(args);
93 static void do_log(FILE *fp, const char *fmt, va_list args)
95         if (!stdout_mode)
96                 fwrite(log_date(), 15, 1, fp);
97         vfprintf(fp, fmt, args);
100 void flushWarningLog(void)
102         char *s = warningBuffer;
104         DEBUG("flushing warning messages\n");
106         if (warningBuffer != NULL)
107         {
108                 while (s != NULL) {
109                         char *next = strchr(s, '\n');
110                         if (next == NULL) break;
111                         *next = '\0';
112                         next++;
113                         fprintf(stderr, "%s\n", s);
114                         s = next;
115                 }
117                 warningBuffer = NULL;
118         }
120         warningFlushed = 1;
122         DEBUG("done flushing warning messages\n");
125 void initLog(const int verbose)
127         ConfigParam *param;
129         /* unbuffer stdout, stderr is unbuffered by default, leave it */
130         setvbuf(stdout, (char *)NULL, _IONBF, 0);
132         if (verbose) {
133                 logLevel = LOG_LEVEL_DEBUG;
134                 return;
135         }
136         if (!(param = getConfigParam(CONF_LOG_LEVEL)))
137                 return;
138         if (0 == strcmp(param->value, "default")) {
139                 logLevel = LOG_LEVEL_LOW;
140         } else if (0 == strcmp(param->value, "secure")) {
141                 logLevel = LOG_LEVEL_SECURE;
142         } else if (0 == strcmp(param->value, "verbose")) {
143                 logLevel = LOG_LEVEL_DEBUG;
144         } else {
145                 FATAL("unknown log level \"%s\" at line %i\n",
146                       param->value, param->line);
147         }
150 void open_log_files(const int use_stdout)
152         mode_t prev;
153         ConfigParam *param;
155         if (use_stdout) {
156                 flushWarningLog();
157                 return;
158         }
160         prev = umask(0066);
161         param = parseConfigFilePath(CONF_LOG_FILE, 1);
162         out_filename = param->value;
163         out_fd = open(out_filename, O_CREAT | O_WRONLY | O_APPEND, 0666);
164         if (out_fd < 0)
165                 FATAL("problem opening log file \"%s\" (config line %i) for "
166                       "writing\n", param->value, param->line);
168         param = parseConfigFilePath(CONF_ERROR_FILE, 1);
169         err_filename = param->value;
170         err_fd = open(err_filename, O_CREAT | O_WRONLY | O_APPEND, 0666);
171         if (err_fd < 0)
172                 FATAL("problem opening error file \"%s\" (config line %i) for "
173                       "writing\n", param->value, param->line);
175         umask(prev);
178 void setup_log_output(const int use_stdout)
180         fflush(NULL);
181         if (!use_stdout) {
182                 redirect_logs();
183                 stdout_mode = 0;
184                 flushWarningLog();
185         }
186         redirect_stdin();
189 #define log_func(func,level,fp) \
190 mpd_printf void func(const char *fmt, ...) \
191 { \
192         if (logLevel >= level) { \
193                 va_list args; \
194                 va_start(args, fmt); \
195                 do_log(fp, fmt, args); \
196                 va_end(args); \
197         } \
200 log_func(ERROR, 0, stderr)
201 log_func(LOG, 0, stdout)
202 log_func(SECURE, LOG_LEVEL_SECURE, stdout)
203 log_func(DEBUG, LOG_LEVEL_DEBUG, stdout)
205 #undef log_func
207 void WARNING(const char *fmt, ...)
209         va_list args;
210         va_start(args, fmt);
211         if (warningFlushed) {
212                 do_log(stderr, fmt, args);
213         } else
214                 buffer_warning(fmt, args);
215         va_end(args);
218 mpd_printf mpd_noreturn void FATAL(const char *fmt, ...)
220         va_list args;
221         va_start(args, fmt);
222         do_log(stderr, fmt, args);
223         va_end(args);
224         exit(EXIT_FAILURE);
227 int cycle_log_files(void)
229         mode_t prev;
231         if (stdout_mode)
232                 return 0;
233         assert(out_filename);
234         assert(err_filename);
236         DEBUG("Cycling log files...\n");
237         close_log_files();
239         prev = umask(0066);
241         out_fd = open(out_filename, O_CREAT | O_WRONLY | O_APPEND, 0666);
242         if (out_fd < 0) {
243                 ERROR("error re-opening log file: %s\n", out_filename);
244                 return -1;
245         }
247         err_fd = open(err_filename, O_CREAT | O_WRONLY | O_APPEND, 0666);
248         if (err_fd < 0) {
249                 ERROR("error re-opening error file: %s\n", err_filename);
250                 return -1;
251         }
253         umask(prev);
255         redirect_logs();
256         DEBUG("Done cycling log files\n");
257         return 0;
260 void close_log_files(void)
262         if (stdout_mode)
263                 return;
264         assert(out_fd > 0);
265         assert(err_fd > 0);
266         xclose(out_fd);
267         xclose(err_fd);