ksgi
/
logging.c
317 строк · 6.2 Кб
1/* $Id$ */
2/*
3* Copyright (c) 2016--2018, 2020 Kristaps Dzonsons <kristaps@bsd.lv>
4*
5* Permission to use, copy, modify, and distribute this software for any
6* purpose with or without fee is hereby granted, provided that the above
7* copyright notice and this permission notice appear in all copies.
8*
9* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16*/
17#include "config.h"18
19#include <ctype.h>20#include <errno.h>21#include <stdarg.h>22#include <stdio.h>23#include <stdint.h>24#include <stdlib.h>25#include <string.h>26#include <time.h>27
28#include "kcgi.h"29
30enum llevel {31LLEVEL_INFO,32LLEVEL_WARN,33LLEVEL_ERROR,34LLEVEL__MAX
35};36
37static const char *llevels[LLEVEL__MAX] = {38"INFO", /* LLEVEL_INFO */39"WARN", /* LLEVEL_WARN */40"ERROR", /* LLEVEL_ERROR */41};42
43/*
44* Actual logging function.
45* Only the optional error string is trusted to have "good" characters;
46* all others may contain anything and are filtered.
47*/
48static void49logmsg(const struct kreq *r, const char *err, const char *lvl,50const char *ident, const char *fmt, va_list ap)51{
52int i, cmpsz, sz;53char date[64];54char *msg, *var = NULL, *cmp, *p;55
56/*57* Convert to GMT.
58* We can't use localtime because we're probably going to be
59* chrooted, and maybe sandboxed, and touching our timezone
60* files will crash us (or at least not be applicable).
61*/
62
63khttp_epoch2str(time(NULL), date, sizeof(date));64
65/*66* Format the variable args, then compose with the log prefix
67* to form the basic message.
68*/
69
70if (fmt != NULL) {71kvasprintf(&var, fmt, ap);72cmpsz = kasprintf73(&cmp, "%s %s [%s] %s %s",74r == NULL ? "-" : r->remote,75ident == NULL ? "-" : ident, date,76lvl == NULL ? "-" : lvl, var);77free(var);78} else79cmpsz = kasprintf80(&cmp, "%s %s [%s] %s -",81r == NULL ? "-" : r->remote,82ident == NULL ? "-" : ident, date,83lvl == NULL ? "-" : lvl);84
85/*86* Allocate the required memory for the message, leaving room
87* for whitespace character expansion and optional error message.
88* Start by buffering for \n\0.
89*/
90
91sz = cmpsz + 2;92
93for (i = 0; i < cmpsz; i++)94switch (cmp[i]) {95case '\n':96case '\r':97case '\t':98sz++;99break;100default:101break;102}103
104/* Next, buffer for ": ". */105
106if (err != NULL)107sz += 2 + strlen(err);108
109p = msg = kmalloc(sz);110
111/*112* Copy message into final buffer, filtering unprintables
113* and whitespace.
114* This draws from strvis(3).
115*/
116
117for (i = 0; i < cmpsz; i++)118switch (cmp[i]) {119case '\a':120*p++ = '\\';121*p++ = 'a';122break;123case '\b':124*p++ = '\\';125*p++ = 'b';126break;127case '\f':128*p++ = '\\';129*p++ = 'f';130break;131case '\n':132*p++ = '\\';133*p++ = 'n';134break;135case '\r':136*p++ = '\\';137*p++ = 'r';138break;139case '\t':140*p++ = '\\';141*p++ = 't';142break;143case '\v':144*p++ = '\\';145*p++ = 'v';146break;147case '\0':148*p++ = '\\';149*p++ = '0';150break;151default:152if (isprint((unsigned char)cmp[i]))153*p++ = cmp[i];154else155*p++ = '?';156break;157}158*p = '\0';159free(cmp);160
161/* Append optional error message, and newline */162
163if (err != NULL) {164(void)strlcat(msg, ": ", sz);165(void)strlcat(msg, err, sz);166}167(void)strlcat(msg, "\n", sz);168
169fputs(msg, stderr);170free(msg);171}
172
173int
174kutil_openlog(const char *file)175{
176
177if (file != NULL && freopen(file, "a", stderr) == NULL)178return 0;179return setvbuf(stderr, NULL, _IOLBF, 0) != EOF;180}
181
182void
183kutil_vlog(const struct kreq *r, const char *lvl,184const char *ident, const char *fmt, va_list ap)185{
186
187logmsg(r, strerror(errno), lvl, ident, fmt, ap);188}
189
190void
191kutil_vlogx(const struct kreq *r, const char *lvl,192const char *ident, const char *fmt, va_list ap)193{
194
195logmsg(r, NULL, lvl, ident, fmt, ap);196}
197
198void
199kutil_warnx(const struct kreq *r,200const char *ident, const char *fmt, ...)201{
202va_list ap;203
204va_start(ap, fmt);205kutil_vlogx(r, llevels[LLEVEL_WARN], ident, fmt, ap);206va_end(ap);207}
208
209void
210kutil_errx(const struct kreq *r,211const char *ident, const char *fmt, ...)212{
213va_list ap;214
215va_start(ap, fmt);216kutil_vlogx(r, llevels[LLEVEL_ERROR], ident, fmt, ap);217va_end(ap);218exit(EXIT_FAILURE);219}
220
221void
222kutil_verrx(const struct kreq *r,223const char *ident, const char *fmt, va_list ap)224{
225
226kutil_vlogx(r, llevels[LLEVEL_ERROR], ident, fmt, ap);227exit(EXIT_FAILURE);228}
229
230void
231kutil_vwarnx(const struct kreq *r,232const char *ident, const char *fmt, va_list ap)233{
234
235kutil_vlogx(r, llevels[LLEVEL_WARN], ident, fmt, ap);236}
237
238void
239kutil_err(const struct kreq *r,240const char *ident, const char *fmt, ...)241{
242va_list ap;243
244va_start(ap, fmt);245kutil_vlog(r, llevels[LLEVEL_ERROR], ident, fmt, ap);246va_end(ap);247exit(EXIT_FAILURE);248}
249
250void
251kutil_warn(const struct kreq *r,252const char *ident, const char *fmt, ...)253{
254va_list ap;255
256va_start(ap, fmt);257kutil_vlog(r, llevels[LLEVEL_WARN], ident, fmt, ap);258va_end(ap);259}
260
261void
262kutil_verr(const struct kreq *r,263const char *ident, const char *fmt, va_list ap)264{
265
266kutil_vlog(r, llevels[LLEVEL_ERROR], ident, fmt, ap);267exit(EXIT_FAILURE);268}
269
270void
271kutil_vwarn(const struct kreq *r,272const char *ident, const char *fmt, va_list ap)273{
274
275kutil_vlog(r, llevels[LLEVEL_WARN], ident, fmt, ap);276}
277
278void
279kutil_info(const struct kreq *r,280const char *ident, const char *fmt, ...)281{
282va_list ap;283
284va_start(ap, fmt);285kutil_vlogx(r, llevels[LLEVEL_INFO], ident, fmt, ap);286va_end(ap);287}
288
289void
290kutil_vinfo(const struct kreq *r,291const char *ident, const char *fmt, va_list ap)292{
293
294kutil_vlogx(r, llevels[LLEVEL_INFO], ident, fmt, ap);295}
296
297void
298kutil_logx(const struct kreq *r, const char *lvl,299const char *ident, const char *fmt, ...)300{
301va_list ap;302
303va_start(ap, fmt);304kutil_vlogx(r, lvl, ident, fmt, ap);305va_end(ap);306}
307
308void
309kutil_log(const struct kreq *r, const char *lvl,310const char *ident, const char *fmt, ...)311{
312va_list ap;313
314va_start(ap, fmt);315kutil_vlog(r, lvl, ident, fmt, ap);316va_end(ap);317}
318