1 /*
2  * logging.c:
3  * Logging for tpop3d.
4  *
5  * Copyright (c) 2001 Chris Lightfoot.
6  * Email: chris@ex-parrot.com; WWW: http://www.ex-parrot.com/~chris/
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2, or (at your option)
11  * any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21  */
22 
23 static const char rcsid[] = "$Id$";
24 
25 #include <errno.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <syslog.h>
31 
32 #include "config.h"
33 #include "util.h"
34 
35 extern int log_stderr;      /* in main.c */
36 
37 /* facil:
38  * Log facility names and constants, used to allow configurable logging at
39  * run time. Not all those defined in openlog(3) make sense, so only a few
40  * are listed here. */
41 static struct logfac {
42     char *name;
43     int fac;
44 } facil[] = {
45         {"mail",        LOG_MAIL},
46 #ifdef LOG_AUTHPRIV
47         {"authpriv",    LOG_AUTHPRIV},
48 #endif
49 #ifdef LOG_AUTH
50         {"auth",        LOG_AUTH},
51 #endif
52         {"daemon",      LOG_DAEMON},
53         {"user",        LOG_USER},
54 
55         {"local0",      LOG_LOCAL0},
56         {"local1",      LOG_LOCAL1},
57         {"local2",      LOG_LOCAL2},
58         {"local3",      LOG_LOCAL3},
59         {"local4",      LOG_LOCAL4},
60         {"local5",      LOG_LOCAL5},
61         {"local6",      LOG_LOCAL6},
62         {"local7",      LOG_LOCAL7},
63     };
64 
65 #define NFACIL      (sizeof(facil) / sizeof(struct logfac))
66 
67 /* level:
68  * Log level names and constants, used to allow configurable logging at
69  * run time. */
70 static struct loglev {
71     char *name;
72     int lev;
73 } level[] = {
74         {"debug",       LOG_DEBUG},
75         {"info",        LOG_INFO},
76         {"notice",      LOG_NOTICE},
77         {"warning",     LOG_WARNING},
78         {"warn",        LOG_WARNING}, /* DEPRECATED */
79         {"err",         LOG_ERR},
80         {"error",       LOG_ERR},     /* DEPRECATED */
81         {"crit",        LOG_CRIT},
82         {"alert",       LOG_ALERT},
83         {"emerg",       LOG_EMERG},
84         {"panic",       LOG_EMERG},   /* DEPRECATED */
85     };
86 
87 #define NLEVEL      (sizeof(level) / sizeof(struct loglev))
88 
89 static int log_fac;
90 static int log_lev;
91 
92 /* log_init:
93  * Start up logging. */
log_init(void)94 void log_init(void) {
95     int fac = LOG_MAIL, lev = LOG_DEBUG, warn_fac = 0, warn_lev = 0;
96     char *sfac, *slev;
97 
98     if ((sfac = config_get_string("log-facility"))) {
99         struct logfac *l;
100         warn_fac = 1;
101         for (l = facil; l < facil + NFACIL; ++l)
102             if (strcasecmp(l->name, sfac) == 0) {
103                 warn_fac = 0;
104                 fac = l->fac;
105                 break;
106             }
107     }
108 
109     if ((slev = config_get_string("log-level"))) {
110         struct loglev *l;
111         warn_lev = 1;
112         for (l = level; l < level + NLEVEL; ++l)
113             if (strcasecmp(l->name, slev) == 0) {
114                 warn_lev = 0;
115                 lev = l->lev;
116                 break;
117             }
118     }
119 
120     log_fac = fac;
121     log_lev = lev;
122 
123     openlog("tpop3d", LOG_PID | LOG_NDELAY, fac);
124 
125     if (warn_fac == 1)
126         log_print(LOG_ERR, _("log_init: log-facility `%s' unknown, using `mail'"), sfac);
127     if (warn_lev == 1)
128         log_print(LOG_ERR, _("log_init: log-level `%s' unknown, using `debug'"), slev);
129 
130 }
131 
132 
133 /* verrprintf:
134  * Returns a static string with the appropriate arguments printed into it.
135  * (Replaced the dynamically allocating one with a static-buffer based
136  * alternative, since it isn't possible to call vsnprintf(..., ap) in a loop,
137  * as the arg list can't be reset. D'oh.) */
verrprintf(const char * fmt,va_list ap)138 static char *verrprintf(const char *fmt, va_list ap) {
139     char *e = strerror(errno);
140     const char *p, *q;
141     char fmtbuf[1024];
142     static char errbuf[1024];
143 
144     *fmtbuf = 0;
145 
146     /* First, we need to substitute errors into the string. This would not be
147      * safe in the presence of very long format strings in the rest of the
148      * code, but we can guarantee that won't happen.... */
149     for (p = fmt, q = strstr(p, "%m"); q; p = q, q = strstr(p, "%m")) {
150         strncat(fmtbuf, p, q - p);
151         strcat(fmtbuf, e);
152         q += 2;
153     }
154 
155     strcat(fmtbuf, p);
156 
157     vsnprintf(errbuf, sizeof(errbuf), fmtbuf, ap);
158 
159     return errbuf;
160 }
161 
162 /* log_print:
163  * Print a line to the log. */
log_print(int priority,const char * fmt,...)164 void log_print(int priority, const char *fmt, ...) {
165     char *s;
166     va_list ap;
167 
168     if(priority > log_lev)
169         return;
170 
171     va_start(ap, fmt);
172     s = verrprintf(fmt, ap);
173     va_end(ap);
174     syslog(priority | log_fac, "%s", s);
175     if (log_stderr) fprintf(stderr, "%s\n", s);
176 }
177 
178 
179