1/* MiniDLNA media server
2 * Copyright (C) 2008-2010 NETGEAR, Inc. All Rights Reserved.
3 *
4 * This file is part of MiniDLNA.
5 *
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.
10 *
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.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20#include "config.h"
21
22#include <stdlib.h>
23#include <stdio.h>
24#include <stdarg.h>
25#include <string.h>
26#include <time.h>
27
28#include "upnpglobalvars.h"
29#include "log.h"
30
31static FILE *log_fp = NULL;
32static const int _default_log_level = E_WARN;
33int log_level[L_MAX];
34
35const char *facility_name[] = {
36	"general",
37	"artwork",
38	"database",
39	"inotify",
40	"scanner",
41	"metadata",
42	"http",
43	"ssdp",
44	"tivo",
45	0
46};
47
48const char *level_name[] = {
49	"off",					// E_OFF
50	"fatal",				// E_FATAL
51	"error",				// E_ERROR
52	"warn",					// E_WARN
53	"info",					// E_INFO
54	"debug",				// E_DEBUG
55	"maxdebug",				// E_MAXDEBUG
56	0
57};
58
59void
60log_close(void)
61{
62	if (log_fp)
63		fclose(log_fp);
64}
65
66int find_matching_name(const char* str, const char* names[]) {
67	if (str == NULL) return -1;
68
69	const char* start = strpbrk(str, ",=");
70	int level, c = (start != NULL) ? start - str : strlen(str);
71	for (level = 0; names[level] != 0; level++) {
72		if (!(strncasecmp(names[level], str, c)))
73			return level;
74	}
75	return -1;
76}
77
78int
79log_init(const char *fname, const char *debug)
80{
81	int i;
82	FILE *fp;
83
84	int level = find_matching_name(debug, level_name);
85	int default_log_level = (level == -1) ? _default_log_level : level;
86
87	for (i=0; i<L_MAX; i++)
88		log_level[i] = default_log_level;
89
90	if (debug)
91	{
92		const char *rhs, *lhs, *nlhs;
93		int level, facility;
94
95		rhs = nlhs = debug;
96		while (rhs && (rhs = strchr(rhs, '='))) {
97			rhs++;
98			level = find_matching_name(rhs, level_name);
99			if (level == -1) {
100				DPRINTF(E_WARN, L_GENERAL, "unknown level in debug string: %s", debug);
101				continue;
102			}
103
104			lhs = nlhs;
105			rhs = nlhs = strchr(rhs, ',');
106			do {
107				if (*lhs==',') lhs++;
108				facility = find_matching_name(lhs, facility_name);
109				if (facility == -1) {
110					DPRINTF(E_WARN, L_GENERAL, "unknown debug facility in debug string: %s", debug);
111				} else {
112					log_level[facility] = level;
113				}
114
115				lhs = strpbrk(lhs, ",=");
116			} while (*lhs && *lhs==',');
117		}
118	}
119
120	if (!fname)					// use default i.e. stdout
121		return 0;
122
123	if (!(fp = fopen(fname, "a")))
124		return 1;
125	log_fp = fp;
126	return 0;
127}
128
129void
130log_err(int level, enum _log_facility facility, char *fname, int lineno, char *fmt, ...)
131{
132	va_list ap;
133
134	if (level && level>log_level[facility] && level>E_FATAL)
135		return;
136
137	if (!log_fp)
138		log_fp = stdout;
139
140	// timestamp
141	if (!GETFLAG(SYSTEMD_MASK))
142	{
143		time_t t;
144		struct tm *tm;
145		t = time(NULL);
146		tm = localtime(&t);
147		fprintf(log_fp, "[%04d/%02d/%02d %02d:%02d:%02d] ",
148		        tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
149		        tm->tm_hour, tm->tm_min, tm->tm_sec);
150	}
151
152	if (level)
153		fprintf(log_fp, "%s:%d: %s: ", fname, lineno, level_name[level]);
154	else
155		fprintf(log_fp, "%s:%d: ", fname, lineno);
156
157	// user log
158	va_start(ap, fmt);
159	if (vfprintf(log_fp, fmt, ap) == -1)
160	{
161		va_end(ap);
162		return;
163	}
164	va_end(ap);
165
166	fflush(log_fp);
167
168	if (level==E_FATAL)
169		exit(-1);
170
171	return;
172}
173