1/*	$NetBSD: log.c,v 1.3 2018/01/13 12:36:35 christos Exp $	*/
2
3/*-
4 * Copyright (c) 2017 The NetBSD Foundation, Inc.
5 * Copyright (c) 2016 The DragonFly Project
6 * Copyright (c) 2012 The FreeBSD Foundation
7 * All rights reserved.
8 *
9 * This code is derived from software contributed to The NetBSD Foundation
10 * by Tomohiro Kusumi <kusumi.tomohiro@gmail.com>.
11 *
12 * This software was developed by Edward Tomasz Napierala under sponsorship
13 * from the FreeBSD Foundation.
14 *
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
17 * are met:
18 * 1. Redistributions of source code must retain the above copyright
19 *    notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 *    notice, this list of conditions and the following disclaimer in the
22 *    documentation and/or other materials provided with the distribution.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 */
37#include <sys/cdefs.h>
38__RCSID("$NetBSD: log.c,v 1.3 2018/01/13 12:36:35 christos Exp $");
39
40#include <errno.h>
41#include <stdarg.h>
42#include <stdio.h>
43#include <stdlib.h>
44#include <string.h>
45#include <syslog.h>
46#include <vis.h>
47
48#include "common.h"
49
50static int log_level = 0;
51static char *peer_name = NULL;
52static char *peer_addr = NULL;
53
54#define	MSGBUF_LEN	1024
55
56void
57log_init(int level)
58{
59
60	log_level = level;
61	openlog(getprogname(), LOG_NDELAY | LOG_PID, LOG_DAEMON);
62}
63
64void
65log_set_peer_name(const char *name)
66{
67
68	/*
69	 * XXX: Turn it into assertion?
70	 */
71	if (peer_name != NULL)
72		log_errx(1, "%s called twice", __func__);
73	if (peer_addr == NULL)
74		log_errx(1, "%s called before log_set_peer_addr", __func__);
75
76	peer_name = checked_strdup(name);
77}
78
79void
80log_set_peer_addr(const char *addr)
81{
82
83	/*
84	 * XXX: Turn it into assertion?
85	 */
86	if (peer_addr != NULL)
87		log_errx(1, "%s called twice", __func__);
88
89	peer_addr = checked_strdup(addr);
90}
91
92static __printflike(3, 0) void
93log_common(int priority, int log_errno, const char *fmt, va_list ap)
94{
95	static char msgbuf[MSGBUF_LEN];
96	static char msgbuf_strvised[MSGBUF_LEN * 4 + 1];
97	char *errstr;
98	int ret;
99
100	ret = vsnprintf(msgbuf, sizeof(msgbuf), fmt, ap);
101	if (ret < 0) {
102		fprintf(stderr, "%s: snprintf failed", getprogname());
103		syslog(LOG_CRIT, "snprintf failed");
104		exit(EXIT_FAILURE);
105	}
106
107	ret = strnvis(msgbuf_strvised, sizeof(msgbuf_strvised), msgbuf, VIS_NL);
108	if (ret < 0) {
109		fprintf(stderr, "%s: strnvis failed", getprogname());
110		syslog(LOG_CRIT, "strnvis failed");
111		exit(EXIT_FAILURE);
112	}
113
114	if (log_errno == -1) {
115		if (peer_name != NULL) {
116			fprintf(stderr, "%s: %s (%s): %s\n", getprogname(),
117			    peer_addr, peer_name, msgbuf_strvised);
118			syslog(priority, "%s (%s): %s",
119			    peer_addr, peer_name, msgbuf_strvised);
120		} else if (peer_addr != NULL) {
121			fprintf(stderr, "%s: %s: %s\n", getprogname(),
122			    peer_addr, msgbuf_strvised);
123			syslog(priority, "%s: %s",
124			    peer_addr, msgbuf_strvised);
125		} else {
126			fprintf(stderr, "%s: %s\n", getprogname(),
127			    msgbuf_strvised);
128			syslog(priority, "%s", msgbuf_strvised);
129		}
130
131	} else {
132		errstr = strerror(log_errno);
133
134		if (peer_name != NULL) {
135			fprintf(stderr, "%s: %s (%s): %s: %s\n", getprogname(),
136			    peer_addr, peer_name, msgbuf_strvised, errstr);
137			syslog(priority, "%s (%s): %s: %s",
138			    peer_addr, peer_name, msgbuf_strvised, errstr);
139		} else if (peer_addr != NULL) {
140			fprintf(stderr, "%s: %s: %s: %s\n", getprogname(),
141			    peer_addr, msgbuf_strvised, errstr);
142			syslog(priority, "%s: %s: %s",
143			    peer_addr, msgbuf_strvised, errstr);
144		} else {
145			fprintf(stderr, "%s: %s: %s\n", getprogname(),
146			    msgbuf_strvised, errstr);
147			syslog(priority, "%s: %s",
148			    msgbuf_strvised, errstr);
149		}
150	}
151}
152
153__dead void
154log_err(int eval, const char *fmt, ...)
155{
156	va_list ap;
157
158	va_start(ap, fmt);
159	log_common(LOG_CRIT, errno, fmt, ap);
160	va_end(ap);
161
162	exit(eval);
163}
164
165__dead void
166log_errx(int eval, const char *fmt, ...)
167{
168	va_list ap;
169
170	va_start(ap, fmt);
171	log_common(LOG_CRIT, -1, fmt, ap);
172	va_end(ap);
173
174	exit(eval);
175}
176
177void
178log_warn(const char *fmt, ...)
179{
180	va_list ap;
181
182	va_start(ap, fmt);
183	log_common(LOG_WARNING, errno, fmt, ap);
184	va_end(ap);
185}
186
187void
188log_warnx(const char *fmt, ...)
189{
190	va_list ap;
191
192	va_start(ap, fmt);
193	log_common(LOG_WARNING, -1, fmt, ap);
194	va_end(ap);
195}
196
197void
198log_debugx(const char *fmt, ...)
199{
200	va_list ap;
201
202	if (log_level == 0)
203		return;
204
205	va_start(ap, fmt);
206	log_common(LOG_DEBUG, -1, fmt, ap);
207	va_end(ap);
208}
209