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