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