xref: /dflybsd-src/contrib/dhcpcd/src/logerr.c (revision 6a6d63c5317abf314a78f8c8300ef73c2bc0c39e)
18d36e1dfSRoy Marples /* SPDX-License-Identifier: BSD-2-Clause */
27827cba2SAaron LI /*
37827cba2SAaron LI  * logerr: errx with logging
480aa9461SRoy Marples  * Copyright (c) 2006-2023 Roy Marples <roy@marples.name>
57827cba2SAaron LI  * All rights reserved
67827cba2SAaron LI 
77827cba2SAaron LI  * Redistribution and use in source and binary forms, with or without
87827cba2SAaron LI  * modification, are permitted provided that the following conditions
97827cba2SAaron LI  * are met:
107827cba2SAaron LI  * 1. Redistributions of source code must retain the above copyright
117827cba2SAaron LI  *    notice, this list of conditions and the following disclaimer.
127827cba2SAaron LI  * 2. Redistributions in binary form must reproduce the above copyright
137827cba2SAaron LI  *    notice, this list of conditions and the following disclaimer in the
147827cba2SAaron LI  *    documentation and/or other materials provided with the distribution.
157827cba2SAaron LI  *
167827cba2SAaron LI  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
177827cba2SAaron LI  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
187827cba2SAaron LI  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
197827cba2SAaron LI  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
207827cba2SAaron LI  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
217827cba2SAaron LI  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
227827cba2SAaron LI  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
237827cba2SAaron LI  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
247827cba2SAaron LI  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
257827cba2SAaron LI  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
267827cba2SAaron LI  * SUCH DAMAGE.
277827cba2SAaron LI  */
287827cba2SAaron LI 
297827cba2SAaron LI #include <sys/time.h>
307827cba2SAaron LI #include <errno.h>
317827cba2SAaron LI #include <stdbool.h>
327827cba2SAaron LI #include <stdarg.h>
337827cba2SAaron LI #include <stdio.h>
347827cba2SAaron LI #include <stdlib.h>
357827cba2SAaron LI #include <string.h>
367827cba2SAaron LI #include <syslog.h>
377827cba2SAaron LI #include <time.h>
387827cba2SAaron LI #include <unistd.h>
397827cba2SAaron LI 
407827cba2SAaron LI #include "logerr.h"
417827cba2SAaron LI 
427827cba2SAaron LI #ifndef	LOGERR_SYSLOG_FACILITY
437827cba2SAaron LI #define	LOGERR_SYSLOG_FACILITY	LOG_DAEMON
447827cba2SAaron LI #endif
457827cba2SAaron LI 
467827cba2SAaron LI #ifdef SMALL
477827cba2SAaron LI #undef LOGERR_TAG
487827cba2SAaron LI #endif
497827cba2SAaron LI 
5039994b17SRoy Marples /* syslog protocol is 1k message max, RFC 3164 section 4.1 */
5139994b17SRoy Marples #define LOGERR_SYSLOGBUF	1024 + sizeof(int) + sizeof(pid_t)
5239994b17SRoy Marples 
537827cba2SAaron LI #define UNUSED(a)		(void)(a)
547827cba2SAaron LI 
557827cba2SAaron LI struct logctx {
567f8103cdSRoy Marples 	char		 log_buf[BUFSIZ];
577827cba2SAaron LI 	unsigned int	 log_opts;
5839994b17SRoy Marples 	int		 log_fd;
5939994b17SRoy Marples 	pid_t		 log_pid;
607827cba2SAaron LI #ifndef SMALL
617827cba2SAaron LI 	FILE		*log_file;
627827cba2SAaron LI #ifdef LOGERR_TAG
637827cba2SAaron LI 	const char	*log_tag;
647827cba2SAaron LI #endif
657827cba2SAaron LI #endif
667827cba2SAaron LI };
677827cba2SAaron LI 
687827cba2SAaron LI static struct logctx _logctx = {
697827cba2SAaron LI 	/* syslog style, but without the hostname or tag. */
707827cba2SAaron LI 	.log_opts = LOGERR_LOG | LOGERR_LOG_DATE | LOGERR_LOG_PID,
7139994b17SRoy Marples 	.log_fd = -1,
7239994b17SRoy Marples 	.log_pid = 0,
737827cba2SAaron LI };
747827cba2SAaron LI 
7539994b17SRoy Marples #if defined(__linux__)
767827cba2SAaron LI /* Poor man's getprogname(3). */
777827cba2SAaron LI static char *_logprog;
787827cba2SAaron LI static const char *
getprogname(void)797827cba2SAaron LI getprogname(void)
807827cba2SAaron LI {
817827cba2SAaron LI 	const char *p;
827827cba2SAaron LI 
837827cba2SAaron LI 	/* Use PATH_MAX + 1 to avoid truncation. */
847827cba2SAaron LI 	if (_logprog == NULL) {
857827cba2SAaron LI 		/* readlink(2) does not append a NULL byte,
867827cba2SAaron LI 		 * so zero the buffer. */
877827cba2SAaron LI 		if ((_logprog = calloc(1, PATH_MAX + 1)) == NULL)
887827cba2SAaron LI 			return NULL;
8939994b17SRoy Marples 		if (readlink("/proc/self/exe", _logprog, PATH_MAX + 1) == -1) {
9039994b17SRoy Marples 			free(_logprog);
9139994b17SRoy Marples 			_logprog = NULL;
927827cba2SAaron LI 			return NULL;
9339994b17SRoy Marples 		}
9439994b17SRoy Marples 	}
957827cba2SAaron LI 	if (_logprog[0] == '[')
967827cba2SAaron LI 		return NULL;
977827cba2SAaron LI 	p = strrchr(_logprog, '/');
987827cba2SAaron LI 	if (p == NULL)
997827cba2SAaron LI 		return _logprog;
1007827cba2SAaron LI 	return p + 1;
1017827cba2SAaron LI }
1027827cba2SAaron LI #endif
1037827cba2SAaron LI 
1047827cba2SAaron LI #ifndef SMALL
1057827cba2SAaron LI /* Write the time, syslog style. month day time - */
1068d36e1dfSRoy Marples static int
logprintdate(FILE * stream)1077827cba2SAaron LI logprintdate(FILE *stream)
1087827cba2SAaron LI {
1097827cba2SAaron LI 	struct timeval tv;
1107827cba2SAaron LI 	time_t now;
1117827cba2SAaron LI 	struct tm tmnow;
1127827cba2SAaron LI 	char buf[32];
1137827cba2SAaron LI 
1147827cba2SAaron LI 	if (gettimeofday(&tv, NULL) == -1)
1158d36e1dfSRoy Marples 		return -1;
1167827cba2SAaron LI 
1177827cba2SAaron LI 	now = tv.tv_sec;
1188d36e1dfSRoy Marples 	if (localtime_r(&now, &tmnow) == NULL)
1198d36e1dfSRoy Marples 		return -1;
1208d36e1dfSRoy Marples 	if (strftime(buf, sizeof(buf), "%b %d %T ", &tmnow) == 0)
1218d36e1dfSRoy Marples 		return -1;
1228d36e1dfSRoy Marples 	return fprintf(stream, "%s", buf);
1237827cba2SAaron LI }
1247827cba2SAaron LI #endif
1257827cba2SAaron LI 
1268d36e1dfSRoy Marples __printflike(3, 0) static int
vlogprintf_r(struct logctx * ctx,FILE * stream,const char * fmt,va_list args)1277827cba2SAaron LI vlogprintf_r(struct logctx *ctx, FILE *stream, const char *fmt, va_list args)
1287827cba2SAaron LI {
1298d36e1dfSRoy Marples 	int len = 0, e;
1307827cba2SAaron LI 	va_list a;
1317827cba2SAaron LI #ifndef SMALL
1327827cba2SAaron LI 	bool log_pid;
1337827cba2SAaron LI #ifdef LOGERR_TAG
1347827cba2SAaron LI 	bool log_tag;
1357827cba2SAaron LI #endif
1367827cba2SAaron LI 
137b8b69544SRoy Marples 	if ((stream == stderr && ctx->log_opts & LOGERR_ERR_DATE) ||
138b8b69544SRoy Marples 	    (stream != stderr && ctx->log_opts & LOGERR_LOG_DATE))
1398d36e1dfSRoy Marples 	{
1408d36e1dfSRoy Marples 		if ((e = logprintdate(stream)) == -1)
1418d36e1dfSRoy Marples 			return -1;
1428d36e1dfSRoy Marples 		len += e;
1438d36e1dfSRoy Marples 	}
1447827cba2SAaron LI 
1457827cba2SAaron LI #ifdef LOGERR_TAG
146b8b69544SRoy Marples 	log_tag = ((stream == stderr && ctx->log_opts & LOGERR_ERR_TAG) ||
147b8b69544SRoy Marples 	    (stream != stderr && ctx->log_opts & LOGERR_LOG_TAG));
1487827cba2SAaron LI 	if (log_tag) {
1497827cba2SAaron LI 		if (ctx->log_tag == NULL)
1507827cba2SAaron LI 			ctx->log_tag = getprogname();
1518d36e1dfSRoy Marples 		if ((e = fprintf(stream, "%s", ctx->log_tag)) == -1)
1528d36e1dfSRoy Marples 			return -1;
1538d36e1dfSRoy Marples 		len += e;
1547827cba2SAaron LI 	}
1557827cba2SAaron LI #endif
1567827cba2SAaron LI 
157b8b69544SRoy Marples 	log_pid = ((stream == stderr && ctx->log_opts & LOGERR_ERR_PID) ||
158b8b69544SRoy Marples 	    (stream != stderr && ctx->log_opts & LOGERR_LOG_PID));
1598d36e1dfSRoy Marples 	if (log_pid) {
16039994b17SRoy Marples 		pid_t pid;
16139994b17SRoy Marples 
16239994b17SRoy Marples 		if (ctx->log_pid == 0)
16339994b17SRoy Marples 			pid = getpid();
16439994b17SRoy Marples 		else
16539994b17SRoy Marples 			pid = ctx->log_pid;
16639994b17SRoy Marples 		if ((e = fprintf(stream, "[%d]", pid)) == -1)
1678d36e1dfSRoy Marples 			return -1;
1688d36e1dfSRoy Marples 		len += e;
1698d36e1dfSRoy Marples 	}
1707827cba2SAaron LI 
1717827cba2SAaron LI #ifdef LOGERR_TAG
1727827cba2SAaron LI 	if (log_tag || log_pid)
1737827cba2SAaron LI #else
1747827cba2SAaron LI 	if (log_pid)
1757827cba2SAaron LI #endif
1768d36e1dfSRoy Marples 	{
1778d36e1dfSRoy Marples 		if ((e = fprintf(stream, ": ")) == -1)
1788d36e1dfSRoy Marples 			return -1;
1798d36e1dfSRoy Marples 		len += e;
1808d36e1dfSRoy Marples 	}
1817827cba2SAaron LI #else
1827827cba2SAaron LI 	UNUSED(ctx);
1837827cba2SAaron LI #endif
1847827cba2SAaron LI 
1857827cba2SAaron LI 	va_copy(a, args);
1868d36e1dfSRoy Marples 	e = vfprintf(stream, fmt, a);
1878d36e1dfSRoy Marples 	if (fputc('\n', stream) == EOF)
1888d36e1dfSRoy Marples 		e = -1;
1898d36e1dfSRoy Marples 	else if (e != -1)
1908d36e1dfSRoy Marples 		e++;
1917827cba2SAaron LI 	va_end(a);
1928d36e1dfSRoy Marples 
1938d36e1dfSRoy Marples 	return e == -1 ? -1 : len + e;
1947827cba2SAaron LI }
1957827cba2SAaron LI 
1967827cba2SAaron LI /*
1977827cba2SAaron LI  * NetBSD's gcc has been modified to check for the non standard %m in printf
1987827cba2SAaron LI  * like functions and warn noisily about it that they should be marked as
1997827cba2SAaron LI  * syslog like instead.
2007827cba2SAaron LI  * This is all well and good, but our logger also goes via vfprintf and
2017827cba2SAaron LI  * when marked as a sysloglike funcion, gcc will then warn us that the
2027827cba2SAaron LI  * function should be printflike instead!
2037827cba2SAaron LI  * This creates an infinte loop of gcc warnings.
2047827cba2SAaron LI  * Until NetBSD solves this issue, we have to disable a gcc diagnostic
2057827cba2SAaron LI  * for our fully standards compliant code in the logger function.
2067827cba2SAaron LI  */
2077827cba2SAaron LI #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5))
2087827cba2SAaron LI #pragma GCC diagnostic push
2097827cba2SAaron LI #pragma GCC diagnostic ignored "-Wmissing-format-attribute"
2107827cba2SAaron LI #endif
2118d36e1dfSRoy Marples __printflike(2, 0) static int
vlogmessage(int pri,const char * fmt,va_list args)2127827cba2SAaron LI vlogmessage(int pri, const char *fmt, va_list args)
2137827cba2SAaron LI {
2147827cba2SAaron LI 	struct logctx *ctx = &_logctx;
2158d36e1dfSRoy Marples 	int len = 0;
2167827cba2SAaron LI 
21739994b17SRoy Marples 	if (ctx->log_fd != -1) {
21839994b17SRoy Marples 		char buf[LOGERR_SYSLOGBUF];
21939994b17SRoy Marples 		pid_t pid;
22039994b17SRoy Marples 
22139994b17SRoy Marples 		memcpy(buf, &pri, sizeof(pri));
22239994b17SRoy Marples 		pid = getpid();
22339994b17SRoy Marples 		memcpy(buf + sizeof(pri), &pid, sizeof(pid));
22439994b17SRoy Marples 		len = vsnprintf(buf + sizeof(pri) + sizeof(pid),
22539994b17SRoy Marples 		    sizeof(buf) - sizeof(pri) - sizeof(pid),
22639994b17SRoy Marples 		    fmt, args);
22739994b17SRoy Marples 		if (len != -1)
22839994b17SRoy Marples 			len = (int)write(ctx->log_fd, buf,
22939994b17SRoy Marples 			    ((size_t)++len) + sizeof(pri) + sizeof(pid));
23039994b17SRoy Marples 		return len;
23139994b17SRoy Marples 	}
23239994b17SRoy Marples 
2337827cba2SAaron LI 	if (ctx->log_opts & LOGERR_ERR &&
2347827cba2SAaron LI 	    (pri <= LOG_ERR ||
2357827cba2SAaron LI 	    (!(ctx->log_opts & LOGERR_QUIET) && pri <= LOG_INFO) ||
2367827cba2SAaron LI 	    (ctx->log_opts & LOGERR_DEBUG && pri <= LOG_DEBUG)))
237b8b69544SRoy Marples 		len = vlogprintf_r(ctx, stderr, fmt, args);
2387827cba2SAaron LI 
2396e63cc1fSRoy Marples #ifndef SMALL
2406e63cc1fSRoy Marples 	if (ctx->log_file != NULL &&
2416e63cc1fSRoy Marples 	    (pri != LOG_DEBUG || (ctx->log_opts & LOGERR_DEBUG)))
2426e63cc1fSRoy Marples 		len = vlogprintf_r(ctx, ctx->log_file, fmt, args);
2437827cba2SAaron LI #endif
2446e63cc1fSRoy Marples 
24539994b17SRoy Marples 	if (ctx->log_opts & LOGERR_LOG)
2466e63cc1fSRoy Marples 		vsyslog(pri, fmt, args);
24739994b17SRoy Marples 
2486e63cc1fSRoy Marples 	return len;
2497827cba2SAaron LI }
2507827cba2SAaron LI #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5))
2517827cba2SAaron LI #pragma GCC diagnostic pop
2527827cba2SAaron LI #endif
2537827cba2SAaron LI 
2546e63cc1fSRoy Marples __printflike(2, 3) void
logmessage(int pri,const char * fmt,...)2557827cba2SAaron LI logmessage(int pri, const char *fmt, ...)
2567827cba2SAaron LI {
2577827cba2SAaron LI 	va_list args;
2587827cba2SAaron LI 
2597827cba2SAaron LI 	va_start(args, fmt);
2607827cba2SAaron LI 	vlogmessage(pri, fmt, args);
2617827cba2SAaron LI 	va_end(args);
2627827cba2SAaron LI }
2637827cba2SAaron LI 
2647827cba2SAaron LI __printflike(2, 0) static void
vlogerrmessage(int pri,const char * fmt,va_list args)2657827cba2SAaron LI vlogerrmessage(int pri, const char *fmt, va_list args)
2667827cba2SAaron LI {
2677827cba2SAaron LI 	int _errno = errno;
2687827cba2SAaron LI 	char buf[1024];
2697827cba2SAaron LI 
2707827cba2SAaron LI 	vsnprintf(buf, sizeof(buf), fmt, args);
2717827cba2SAaron LI 	logmessage(pri, "%s: %s", buf, strerror(_errno));
272d4fb1e02SRoy Marples 	errno = _errno;
2737827cba2SAaron LI }
2747827cba2SAaron LI 
2756e63cc1fSRoy Marples __printflike(2, 3) void
logerrmessage(int pri,const char * fmt,...)2766e63cc1fSRoy Marples logerrmessage(int pri, const char *fmt, ...)
2776e63cc1fSRoy Marples {
2786e63cc1fSRoy Marples 	va_list args;
2796e63cc1fSRoy Marples 
2806e63cc1fSRoy Marples 	va_start(args, fmt);
2816e63cc1fSRoy Marples 	vlogerrmessage(pri, fmt, args);
2826e63cc1fSRoy Marples 	va_end(args);
2836e63cc1fSRoy Marples }
2846e63cc1fSRoy Marples 
2857827cba2SAaron LI void
log_debug(const char * fmt,...)2866e63cc1fSRoy Marples log_debug(const char *fmt, ...)
2877827cba2SAaron LI {
2887827cba2SAaron LI 	va_list args;
2897827cba2SAaron LI 
2907827cba2SAaron LI 	va_start(args, fmt);
2917827cba2SAaron LI 	vlogerrmessage(LOG_DEBUG, fmt, args);
2927827cba2SAaron LI 	va_end(args);
2937827cba2SAaron LI }
2947827cba2SAaron LI 
2957827cba2SAaron LI void
log_debugx(const char * fmt,...)2966e63cc1fSRoy Marples log_debugx(const char *fmt, ...)
2977827cba2SAaron LI {
2987827cba2SAaron LI 	va_list args;
2997827cba2SAaron LI 
3007827cba2SAaron LI 	va_start(args, fmt);
3017827cba2SAaron LI 	vlogmessage(LOG_DEBUG, fmt, args);
3027827cba2SAaron LI 	va_end(args);
3037827cba2SAaron LI }
3047827cba2SAaron LI 
3057827cba2SAaron LI void
log_info(const char * fmt,...)3066e63cc1fSRoy Marples log_info(const char *fmt, ...)
3077827cba2SAaron LI {
3087827cba2SAaron LI 	va_list args;
3097827cba2SAaron LI 
3107827cba2SAaron LI 	va_start(args, fmt);
3117827cba2SAaron LI 	vlogerrmessage(LOG_INFO, fmt, args);
3127827cba2SAaron LI 	va_end(args);
3137827cba2SAaron LI }
3147827cba2SAaron LI 
3157827cba2SAaron LI void
log_infox(const char * fmt,...)3166e63cc1fSRoy Marples log_infox(const char *fmt, ...)
3177827cba2SAaron LI {
3187827cba2SAaron LI 	va_list args;
3197827cba2SAaron LI 
3207827cba2SAaron LI 	va_start(args, fmt);
3217827cba2SAaron LI 	vlogmessage(LOG_INFO, fmt, args);
3227827cba2SAaron LI 	va_end(args);
3237827cba2SAaron LI }
3247827cba2SAaron LI 
3257827cba2SAaron LI void
log_warn(const char * fmt,...)3266e63cc1fSRoy Marples log_warn(const char *fmt, ...)
3277827cba2SAaron LI {
3287827cba2SAaron LI 	va_list args;
3297827cba2SAaron LI 
3307827cba2SAaron LI 	va_start(args, fmt);
3317827cba2SAaron LI 	vlogerrmessage(LOG_WARNING, fmt, args);
3327827cba2SAaron LI 	va_end(args);
3337827cba2SAaron LI }
3347827cba2SAaron LI 
3357827cba2SAaron LI void
log_warnx(const char * fmt,...)3366e63cc1fSRoy Marples log_warnx(const char *fmt, ...)
3377827cba2SAaron LI {
3387827cba2SAaron LI 	va_list args;
3397827cba2SAaron LI 
3407827cba2SAaron LI 	va_start(args, fmt);
3417827cba2SAaron LI 	vlogmessage(LOG_WARNING, fmt, args);
3427827cba2SAaron LI 	va_end(args);
3437827cba2SAaron LI }
3447827cba2SAaron LI 
3457827cba2SAaron LI void
log_err(const char * fmt,...)3466e63cc1fSRoy Marples log_err(const char *fmt, ...)
3477827cba2SAaron LI {
3487827cba2SAaron LI 	va_list args;
3497827cba2SAaron LI 
3507827cba2SAaron LI 	va_start(args, fmt);
3517827cba2SAaron LI 	vlogerrmessage(LOG_ERR, fmt, args);
3527827cba2SAaron LI 	va_end(args);
3537827cba2SAaron LI }
3547827cba2SAaron LI 
3557827cba2SAaron LI void
log_errx(const char * fmt,...)3566e63cc1fSRoy Marples log_errx(const char *fmt, ...)
3577827cba2SAaron LI {
3587827cba2SAaron LI 	va_list args;
3597827cba2SAaron LI 
3607827cba2SAaron LI 	va_start(args, fmt);
3617827cba2SAaron LI 	vlogmessage(LOG_ERR, fmt, args);
3627827cba2SAaron LI 	va_end(args);
3637827cba2SAaron LI }
3647827cba2SAaron LI 
36539994b17SRoy Marples int
loggetfd(void)36639994b17SRoy Marples loggetfd(void)
36739994b17SRoy Marples {
36839994b17SRoy Marples 	struct logctx *ctx = &_logctx;
36939994b17SRoy Marples 
37039994b17SRoy Marples 	return ctx->log_fd;
37139994b17SRoy Marples }
37239994b17SRoy Marples 
37339994b17SRoy Marples void
logsetfd(int fd)37439994b17SRoy Marples logsetfd(int fd)
37539994b17SRoy Marples {
37639994b17SRoy Marples 	struct logctx *ctx = &_logctx;
37739994b17SRoy Marples 
37839994b17SRoy Marples 	ctx->log_fd = fd;
379*54175cefSRoy Marples 	if (fd != -1)
380*54175cefSRoy Marples 		closelog();
38139994b17SRoy Marples #ifndef SMALL
38239994b17SRoy Marples 	if (fd != -1 && ctx->log_file != NULL) {
38339994b17SRoy Marples 		fclose(ctx->log_file);
38439994b17SRoy Marples 		ctx->log_file = NULL;
38539994b17SRoy Marples 	}
38639994b17SRoy Marples #endif
38739994b17SRoy Marples }
38839994b17SRoy Marples 
38939994b17SRoy Marples int
logreadfd(int fd)39039994b17SRoy Marples logreadfd(int fd)
39139994b17SRoy Marples {
39239994b17SRoy Marples 	struct logctx *ctx = &_logctx;
39339994b17SRoy Marples 	char buf[LOGERR_SYSLOGBUF];
39439994b17SRoy Marples 	int len, pri;
39539994b17SRoy Marples 
39639994b17SRoy Marples 	len = (int)read(fd, buf, sizeof(buf));
39739994b17SRoy Marples 	if (len == -1)
39839994b17SRoy Marples 		return -1;
39939994b17SRoy Marples 
40039994b17SRoy Marples 	/* Ensure we have pri, pid and a terminator */
40139994b17SRoy Marples 	if (len < (int)(sizeof(pri) + sizeof(pid_t) + 1) ||
40239994b17SRoy Marples 	    buf[len - 1] != '\0')
40339994b17SRoy Marples 	{
40439994b17SRoy Marples 		errno = EINVAL;
40539994b17SRoy Marples 		return -1;
40639994b17SRoy Marples 	}
40739994b17SRoy Marples 
40839994b17SRoy Marples 	memcpy(&pri, buf, sizeof(pri));
40939994b17SRoy Marples 	memcpy(&ctx->log_pid, buf + sizeof(pri), sizeof(ctx->log_pid));
41039994b17SRoy Marples 	logmessage(pri, "%s", buf + sizeof(pri) + sizeof(ctx->log_pid));
41139994b17SRoy Marples 	ctx->log_pid = 0;
41239994b17SRoy Marples 	return len;
41339994b17SRoy Marples }
41439994b17SRoy Marples 
4156e63cc1fSRoy Marples unsigned int
loggetopts(void)4166e63cc1fSRoy Marples loggetopts(void)
4176e63cc1fSRoy Marples {
4186e63cc1fSRoy Marples 	struct logctx *ctx = &_logctx;
4196e63cc1fSRoy Marples 
4206e63cc1fSRoy Marples 	return ctx->log_opts;
4216e63cc1fSRoy Marples }
4226e63cc1fSRoy Marples 
4237827cba2SAaron LI void
logsetopts(unsigned int opts)4247827cba2SAaron LI logsetopts(unsigned int opts)
4257827cba2SAaron LI {
4267827cba2SAaron LI 	struct logctx *ctx = &_logctx;
4277827cba2SAaron LI 
4287827cba2SAaron LI 	ctx->log_opts = opts;
4297827cba2SAaron LI 	setlogmask(LOG_UPTO(opts & LOGERR_DEBUG ? LOG_DEBUG : LOG_INFO));
4307827cba2SAaron LI }
4317827cba2SAaron LI 
4327827cba2SAaron LI #ifdef LOGERR_TAG
4337827cba2SAaron LI void
logsettag(const char * tag)4347827cba2SAaron LI logsettag(const char *tag)
4357827cba2SAaron LI {
4367827cba2SAaron LI #if !defined(SMALL)
4377827cba2SAaron LI 	struct logctx *ctx = &_logctx;
4387827cba2SAaron LI 
4397827cba2SAaron LI 	ctx->log_tag = tag;
4407827cba2SAaron LI #else
4417827cba2SAaron LI 	UNUSED(tag);
4427827cba2SAaron LI #endif
4437827cba2SAaron LI }
4447827cba2SAaron LI #endif
4457827cba2SAaron LI 
4467827cba2SAaron LI int
logopen(const char * path)4477827cba2SAaron LI logopen(const char *path)
4487827cba2SAaron LI {
4497827cba2SAaron LI 	struct logctx *ctx = &_logctx;
45093ddca5eSRoy Marples 	int opts = 0;
4517827cba2SAaron LI 
452d4fb1e02SRoy Marples 	/* Cache timezone */
453d4fb1e02SRoy Marples 	tzset();
454d4fb1e02SRoy Marples 
4557f8103cdSRoy Marples 	(void)setvbuf(stderr, ctx->log_buf, _IOLBF, sizeof(ctx->log_buf));
4567f8103cdSRoy Marples 
45739994b17SRoy Marples #ifndef SMALL
45839994b17SRoy Marples 	if (ctx->log_file != NULL) {
45939994b17SRoy Marples 		fclose(ctx->log_file);
46039994b17SRoy Marples 		ctx->log_file = NULL;
46139994b17SRoy Marples 	}
46293ddca5eSRoy Marples #endif
46339994b17SRoy Marples 
4647827cba2SAaron LI 	if (ctx->log_opts & LOGERR_LOG_PID)
4657827cba2SAaron LI 		opts |= LOG_PID;
46639994b17SRoy Marples 	openlog(getprogname(), opts, LOGERR_SYSLOG_FACILITY);
46793ddca5eSRoy Marples 	if (path == NULL)
4687827cba2SAaron LI 		return 1;
4697827cba2SAaron LI 
4707827cba2SAaron LI #ifndef SMALL
471a0d9933aSRoy Marples 	if ((ctx->log_file = fopen(path, "ae")) == NULL)
4727827cba2SAaron LI 		return -1;
4737827cba2SAaron LI 	setlinebuf(ctx->log_file);
4747827cba2SAaron LI 	return fileno(ctx->log_file);
4757827cba2SAaron LI #else
4767827cba2SAaron LI 	errno = ENOTSUP;
4777827cba2SAaron LI 	return -1;
4787827cba2SAaron LI #endif
4797827cba2SAaron LI }
4807827cba2SAaron LI 
4817827cba2SAaron LI void
logclose(void)4827827cba2SAaron LI logclose(void)
4837827cba2SAaron LI {
4847827cba2SAaron LI #ifndef SMALL
4857827cba2SAaron LI 	struct logctx *ctx = &_logctx;
4867827cba2SAaron LI #endif
4877827cba2SAaron LI 
4887827cba2SAaron LI 	closelog();
4890a68f8d2SRoy Marples #if defined(__linux__)
4900a68f8d2SRoy Marples 	free(_logprog);
4910a68f8d2SRoy Marples 	_logprog = NULL;
4920a68f8d2SRoy Marples #endif
4937827cba2SAaron LI #ifndef SMALL
4947827cba2SAaron LI 	if (ctx->log_file == NULL)
4957827cba2SAaron LI 		return;
4967827cba2SAaron LI 	fclose(ctx->log_file);
4977827cba2SAaron LI 	ctx->log_file = NULL;
4987827cba2SAaron LI #endif
4997827cba2SAaron LI }
500