Index: head/contrib/blacklist/bin/blacklistctl.c =================================================================== --- head/contrib/blacklist/bin/blacklistctl.c (revision 335887) +++ head/contrib/blacklist/bin/blacklistctl.c (revision 335888) @@ -1,151 +1,152 @@ /* $NetBSD: blacklistctl.c,v 1.21 2016/11/02 03:15:07 jnemeth Exp $ */ /*- * Copyright (c) 2015 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Christos Zoulas. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include __RCSID("$NetBSD: blacklistctl.c,v 1.21 2016/11/02 03:15:07 jnemeth Exp $"); +#include #include #include #ifdef HAVE_LIBUTIL_H #include #endif #ifdef HAVE_UTIL_H #include #endif #include #include #include #include #include #include #include #include "conf.h" #include "state.h" #include "internal.h" #include "support.h" static __dead void usage(int c) { if (c == 0) warnx("Missing/unknown command"); else warnx("Unknown option `%c'", (char)c); fprintf(stderr, "Usage: %s dump [-abdnrw]\n", getprogname()); exit(EXIT_FAILURE); } int main(int argc, char *argv[]) { const char *dbname = _PATH_BLSTATE; DB *db; struct conf c; struct dbinfo dbi; unsigned int i; struct timespec ts; int all, blocked, remain, wide, noheader; int o; noheader = wide = blocked = all = remain = 0; lfun = dlog; if (argc == 1 || strcmp(argv[1], "dump") != 0) usage(0); argc--; argv++; while ((o = getopt(argc, argv, "abD:dnrw")) != -1) switch (o) { case 'a': all = 1; blocked = 0; break; case 'b': blocked = 1; break; case 'D': dbname = optarg; break; case 'd': debug++; break; case 'n': noheader = 1; break; case 'r': remain = 1; break; case 'w': wide = 1; break; default: usage(o); break; } db = state_open(dbname, O_RDONLY, 0); if (db == NULL) err(EXIT_FAILURE, "Can't open `%s'", dbname); clock_gettime(CLOCK_REALTIME, &ts); wide = wide ? 8 * 4 + 7 : 4 * 3 + 3; if (!noheader) printf("%*.*s/ma:port\tid\tnfail\t%s\n", wide, wide, "address", remain ? "remaining time" : "last access"); for (i = 1; state_iterate(db, &c, &dbi, i) != 0; i = 0) { char buf[BUFSIZ]; if (!all) { if (blocked) { if (dbi.count < c.c_nfail) continue; } else { if (dbi.count >= c.c_nfail) continue; } } sockaddr_snprintf(buf, sizeof(buf), "%a", (void *)&c.c_ss); printf("%*.*s/%d:%d\t", wide, wide, buf, c.c_lmask, c.c_port); if (remain) fmtydhms(buf, sizeof(buf), c.c_duration - (ts.tv_sec - dbi.last)); else fmttime(buf, sizeof(buf), dbi.last); printf("%s\t%d/%d\t%-s\n", dbi.id, dbi.count, c.c_nfail, buf); } state_close(db); return EXIT_SUCCESS; } Index: head/lib/libpjdlog/pjdlog.c =================================================================== --- head/lib/libpjdlog/pjdlog.c (revision 335887) +++ head/lib/libpjdlog/pjdlog.c (revision 335888) @@ -1,811 +1,811 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2009-2010 The FreeBSD Foundation * Copyright (c) 2011 Pawel Jakub Dawidek * All rights reserved. * * This software was developed by Pawel Jakub Dawidek under sponsorship from * the FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include -#include #include +#include #include #include #include #include #include #include #ifdef notyet #include #endif #include "pjdlog.h" #ifndef MAX #define MAX(a, b) ((a) > (b) ? (a) : (b)) #endif #define PJDLOG_MAX_MSGSIZE 4096 #define PJDLOG_PREFIX_STACK 4 #define PJDLOG_PREFIX_MAXSIZE 128 #define PJDLOG_NEVER_INITIALIZED 0 #define PJDLOG_NOT_INITIALIZED 1 #define PJDLOG_INITIALIZED 2 static int pjdlog_initialized = PJDLOG_NEVER_INITIALIZED; static int pjdlog_mode, pjdlog_debug_level, pjdlog_sock; static int pjdlog_prefix_current; static char pjdlog_prefix[PJDLOG_PREFIX_STACK][PJDLOG_PREFIX_MAXSIZE]; static int pjdlog_printf_arginfo_humanized_number(const struct printf_info *pi __unused, size_t n, int *argt) { assert(n >= 1); argt[0] = PA_INT | PA_FLAG_INTMAX; return (1); } static int pjdlog_printf_render_humanized_number(struct __printf_io *io, const struct printf_info *pi, const void * const *arg) { char buf[5]; intmax_t num; int ret; num = *(const intmax_t *)arg[0]; humanize_number(buf, sizeof(buf), (int64_t)num, "", HN_AUTOSCALE, HN_NOSPACE | HN_DECIMAL); ret = __printf_out(io, pi, buf, strlen(buf)); __printf_flush(io); return (ret); } static int pjdlog_printf_arginfo_sockaddr(const struct printf_info *pi __unused, size_t n, int *argt) { assert(n >= 1); argt[0] = PA_POINTER; return (1); } static int pjdlog_printf_render_sockaddr_ip(struct __printf_io *io, const struct printf_info *pi, const void * const *arg) { const struct sockaddr_storage *ss; char addr[MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)]; int ret; ss = *(const struct sockaddr_storage * const *)arg[0]; switch (ss->ss_family) { case AF_INET: { const struct sockaddr_in *sin; sin = (const struct sockaddr_in *)ss; if (inet_ntop(ss->ss_family, &sin->sin_addr, addr, sizeof(addr)) == NULL) { PJDLOG_ABORT("inet_ntop(AF_INET) failed: %s.", strerror(errno)); } break; } case AF_INET6: { const struct sockaddr_in6 *sin; sin = (const struct sockaddr_in6 *)ss; if (inet_ntop(ss->ss_family, &sin->sin6_addr, addr, sizeof(addr)) == NULL) { PJDLOG_ABORT("inet_ntop(AF_INET6) failed: %s.", strerror(errno)); } break; } default: snprintf(addr, sizeof(addr), "[unsupported family %hhu]", ss->ss_family); break; } ret = __printf_out(io, pi, addr, strlen(addr)); __printf_flush(io); return (ret); } static int pjdlog_printf_render_sockaddr(struct __printf_io *io, const struct printf_info *pi, const void * const *arg) { const struct sockaddr_storage *ss; char buf[PATH_MAX]; int ret; ss = *(const struct sockaddr_storage * const *)arg[0]; switch (ss->ss_family) { case AF_UNIX: { const struct sockaddr_un *sun; sun = (const struct sockaddr_un *)ss; if (sun->sun_path[0] == '\0') snprintf(buf, sizeof(buf), "N/A"); else snprintf(buf, sizeof(buf), "%s", sun->sun_path); break; } case AF_INET: { char addr[INET_ADDRSTRLEN]; const struct sockaddr_in *sin; unsigned int port; sin = (const struct sockaddr_in *)ss; port = ntohs(sin->sin_port); if (inet_ntop(ss->ss_family, &sin->sin_addr, addr, sizeof(addr)) == NULL) { PJDLOG_ABORT("inet_ntop(AF_INET) failed: %s.", strerror(errno)); } snprintf(buf, sizeof(buf), "%s:%u", addr, port); break; } case AF_INET6: { char addr[INET6_ADDRSTRLEN]; const struct sockaddr_in6 *sin; unsigned int port; sin = (const struct sockaddr_in6 *)ss; port = ntohs(sin->sin6_port); if (inet_ntop(ss->ss_family, &sin->sin6_addr, addr, sizeof(addr)) == NULL) { PJDLOG_ABORT("inet_ntop(AF_INET6) failed: %s.", strerror(errno)); } snprintf(buf, sizeof(buf), "[%s]:%u", addr, port); break; } default: snprintf(buf, sizeof(buf), "[unsupported family %hhu]", ss->ss_family); break; } ret = __printf_out(io, pi, buf, strlen(buf)); __printf_flush(io); return (ret); } void pjdlog_init(int mode) { int saved_errno; assert(pjdlog_initialized == PJDLOG_NEVER_INITIALIZED || pjdlog_initialized == PJDLOG_NOT_INITIALIZED); #ifdef notyet assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG || mode == PJDLOG_MODE_SOCK); #else assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG); #endif saved_errno = errno; if (pjdlog_initialized == PJDLOG_NEVER_INITIALIZED) { __use_xprintf = 1; register_printf_render_std("T"); register_printf_render('N', pjdlog_printf_render_humanized_number, pjdlog_printf_arginfo_humanized_number); register_printf_render('I', pjdlog_printf_render_sockaddr_ip, pjdlog_printf_arginfo_sockaddr); register_printf_render('S', pjdlog_printf_render_sockaddr, pjdlog_printf_arginfo_sockaddr); } if (mode == PJDLOG_MODE_SYSLOG) openlog(NULL, LOG_PID | LOG_NDELAY, LOG_LOCAL0); pjdlog_mode = mode; pjdlog_debug_level = 0; pjdlog_prefix_current = 0; pjdlog_prefix[0][0] = '\0'; pjdlog_initialized = PJDLOG_INITIALIZED; pjdlog_sock = -1; errno = saved_errno; } void pjdlog_fini(void) { int saved_errno; assert(pjdlog_initialized == PJDLOG_INITIALIZED); saved_errno = errno; if (pjdlog_mode == PJDLOG_MODE_SYSLOG) closelog(); pjdlog_initialized = PJDLOG_NOT_INITIALIZED; pjdlog_sock = -1; errno = saved_errno; } /* * Configure where the logs should go. * By default they are send to stdout/stderr, but after going into background * (eg. by calling daemon(3)) application is responsible for changing mode to * PJDLOG_MODE_SYSLOG, so logs will be send to syslog. */ void pjdlog_mode_set(int mode) { int saved_errno; assert(pjdlog_initialized == PJDLOG_INITIALIZED); #ifdef notyet assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG || mode == PJDLOG_MODE_SOCK); #else assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG); #endif if (pjdlog_mode == mode) return; saved_errno = errno; if (mode == PJDLOG_MODE_SYSLOG) openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON); else if (mode == PJDLOG_MODE_STD) closelog(); if (mode != PJDLOG_MODE_SOCK) pjdlog_sock = -1; pjdlog_mode = mode; errno = saved_errno; } /* * Return current mode. */ int pjdlog_mode_get(void) { assert(pjdlog_initialized == PJDLOG_INITIALIZED); return (pjdlog_mode); } #ifdef notyet /* * Sets socket number to use for PJDLOG_MODE_SOCK mode. */ void pjdlog_sock_set(int sock) { assert(pjdlog_initialized == PJDLOG_INITIALIZED); assert(pjdlog_mode == PJDLOG_MODE_SOCK); assert(sock >= 0); pjdlog_sock = sock; } #endif #ifdef notyet /* * Returns socket number used for PJDLOG_MODE_SOCK mode. */ int pjdlog_sock_get(void) { assert(pjdlog_initialized == PJDLOG_INITIALIZED); assert(pjdlog_mode == PJDLOG_MODE_SOCK); assert(pjdlog_sock >= 0); return (pjdlog_sock); } #endif /* * Set debug level. All the logs above the level specified here will be * ignored. */ void pjdlog_debug_set(int level) { assert(pjdlog_initialized == PJDLOG_INITIALIZED); assert(level >= 0); assert(level <= 127); pjdlog_debug_level = level; } /* * Return current debug level. */ int pjdlog_debug_get(void) { assert(pjdlog_initialized == PJDLOG_INITIALIZED); return (pjdlog_debug_level); } /* * Set prefix that will be used before each log. */ void pjdlog_prefix_set(const char *fmt, ...) { va_list ap; assert(pjdlog_initialized == PJDLOG_INITIALIZED); va_start(ap, fmt); pjdlogv_prefix_set(fmt, ap); va_end(ap); } /* * Set prefix that will be used before each log. */ void pjdlogv_prefix_set(const char *fmt, va_list ap) { int saved_errno; assert(pjdlog_initialized == PJDLOG_INITIALIZED); assert(fmt != NULL); saved_errno = errno; vsnprintf(pjdlog_prefix[pjdlog_prefix_current], sizeof(pjdlog_prefix[pjdlog_prefix_current]), fmt, ap); errno = saved_errno; } /* * Get current prefix. */ const char * pjdlog_prefix_get(void) { assert(pjdlog_initialized == PJDLOG_INITIALIZED); return (pjdlog_prefix[pjdlog_prefix_current]); } /* * Set new prefix and put the current one on the stack. */ void pjdlog_prefix_push(const char *fmt, ...) { va_list ap; assert(pjdlog_initialized == PJDLOG_INITIALIZED); va_start(ap, fmt); pjdlogv_prefix_push(fmt, ap); va_end(ap); } /* * Set new prefix and put the current one on the stack. */ void pjdlogv_prefix_push(const char *fmt, va_list ap) { assert(pjdlog_initialized == PJDLOG_INITIALIZED); assert(pjdlog_prefix_current < PJDLOG_PREFIX_STACK - 1); pjdlog_prefix_current++; pjdlogv_prefix_set(fmt, ap); } /* * Removes current prefix and recovers previous one from the stack. */ void pjdlog_prefix_pop(void) { assert(pjdlog_initialized == PJDLOG_INITIALIZED); assert(pjdlog_prefix_current > 0); pjdlog_prefix_current--; } /* * Convert log level into string. */ static const char * pjdlog_level_to_string(int loglevel) { switch (loglevel) { case LOG_EMERG: return ("EMERG"); case LOG_ALERT: return ("ALERT"); case LOG_CRIT: return ("CRIT"); case LOG_ERR: return ("ERROR"); case LOG_WARNING: return ("WARNING"); case LOG_NOTICE: return ("NOTICE"); case LOG_INFO: return ("INFO"); case LOG_DEBUG: return ("DEBUG"); } assert(!"Invalid log level."); abort(); /* XXX: gcc */ } static int vsnprlcat(char *str, size_t size, const char *fmt, va_list ap) { size_t len; len = strlen(str); assert(len < size); return (vsnprintf(str + len, size - len, fmt, ap)); } static int snprlcat(char *str, size_t size, const char *fmt, ...) { va_list ap; int result; va_start(ap, fmt); result = vsnprlcat(str, size, fmt, ap); va_end(ap); return (result); } static void pjdlogv_common_single_line(const char *func, const char *file, int line, int loglevel, int debuglevel, int error, const char *msg) { static char log[2 * PJDLOG_MAX_MSGSIZE]; char *logp; size_t logs; assert(pjdlog_initialized == PJDLOG_INITIALIZED); #ifdef notyet assert(pjdlog_mode == PJDLOG_MODE_STD || pjdlog_mode == PJDLOG_MODE_SYSLOG || pjdlog_mode == PJDLOG_MODE_SOCK); #else assert(pjdlog_mode == PJDLOG_MODE_STD || pjdlog_mode == PJDLOG_MODE_SYSLOG); #endif assert(pjdlog_mode != PJDLOG_MODE_SOCK || pjdlog_sock >= 0); assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT || loglevel == LOG_CRIT || loglevel == LOG_ERR || loglevel == LOG_WARNING || loglevel == LOG_NOTICE || loglevel == LOG_INFO || loglevel == LOG_DEBUG); assert(loglevel != LOG_DEBUG || debuglevel > 0); assert(loglevel != LOG_DEBUG || debuglevel <= pjdlog_debug_level); assert(debuglevel <= 127); assert(error >= -1); assert((file != NULL && line > 0) || (func == NULL && file == NULL && line == 0)); switch (pjdlog_mode) { case PJDLOG_MODE_STD: case PJDLOG_MODE_SYSLOG: logp = log; logs = sizeof(log); break; case PJDLOG_MODE_SOCK: logp = log + 4; logs = sizeof(log) - 4; break; default: assert(!"Invalid mode."); } *logp = '\0'; if (pjdlog_mode != PJDLOG_MODE_SOCK) { if (loglevel == LOG_DEBUG) { /* Attach debuglevel if this is debug log. */ snprlcat(logp, logs, "[%s%d] ", pjdlog_level_to_string(loglevel), debuglevel); } else { snprlcat(logp, logs, "[%s] ", pjdlog_level_to_string(loglevel)); } if (pjdlog_mode != PJDLOG_MODE_SYSLOG && pjdlog_debug_level >= 1) { snprlcat(logp, logs, "(pid=%d) ", getpid()); } } /* Attach file, func, line if debuglevel is 2 or more. */ if (pjdlog_debug_level >= 2 && file != NULL) { if (func == NULL) snprlcat(logp, logs, "(%s:%d) ", file, line); else snprlcat(logp, logs, "(%s:%d:%s) ", file, line, func); } if (pjdlog_mode != PJDLOG_MODE_SOCK) { snprlcat(logp, logs, "%s", pjdlog_prefix[pjdlog_prefix_current]); } strlcat(logp, msg, logs); /* Attach error description. */ if (error != -1) snprlcat(logp, logs, ": %s.", strerror(error)); switch (pjdlog_mode) { case PJDLOG_MODE_STD: fprintf(stderr, "%s\n", logp); fflush(stderr); break; case PJDLOG_MODE_SYSLOG: syslog(loglevel, "%s", logp); break; #ifdef notyet case PJDLOG_MODE_SOCK: { char ack[2]; uint16_t dlen; log[2] = loglevel; log[3] = debuglevel; dlen = strlen(logp) + 3; /* +3 = loglevel, debuglevel and terminating \0 */ bcopy(&dlen, log, sizeof(dlen)); if (robust_send(pjdlog_sock, log, (size_t)dlen + 2) == -1) /* +2 for size */ assert(!"Unable to send log."); if (robust_recv(pjdlog_sock, ack, sizeof(ack)) == -1) assert(!"Unable to send log."); break; } #endif default: assert(!"Invalid mode."); } } /* * Common log routine, which can handle regular log level as well as debug * level. We decide here where to send the logs (stdout/stderr or syslog). */ void _pjdlogv_common(const char *func, const char *file, int line, int loglevel, int debuglevel, int error, const char *fmt, va_list ap) { char log[PJDLOG_MAX_MSGSIZE]; char *logp, *curline; const char *prvline; int saved_errno; assert(pjdlog_initialized == PJDLOG_INITIALIZED); assert(pjdlog_mode == PJDLOG_MODE_STD || pjdlog_mode == PJDLOG_MODE_SYSLOG || pjdlog_mode == PJDLOG_MODE_SOCK); assert(pjdlog_mode != PJDLOG_MODE_SOCK || pjdlog_sock >= 0); assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT || loglevel == LOG_CRIT || loglevel == LOG_ERR || loglevel == LOG_WARNING || loglevel == LOG_NOTICE || loglevel == LOG_INFO || loglevel == LOG_DEBUG); assert(loglevel != LOG_DEBUG || debuglevel > 0); assert(debuglevel <= 127); assert(error >= -1); /* Ignore debug above configured level. */ if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level) return; saved_errno = errno; vsnprintf(log, sizeof(log), fmt, ap); logp = log; prvline = NULL; while ((curline = strsep(&logp, "\n")) != NULL) { if (*curline == '\0') continue; if (prvline != NULL) { pjdlogv_common_single_line(func, file, line, loglevel, debuglevel, -1, prvline); } prvline = curline; } if (prvline == NULL) prvline = ""; pjdlogv_common_single_line(func, file, line, loglevel, debuglevel, error, prvline); errno = saved_errno; } /* * Common log routine. */ void _pjdlog_common(const char *func, const char *file, int line, int loglevel, int debuglevel, int error, const char *fmt, ...) { va_list ap; assert(pjdlog_initialized == PJDLOG_INITIALIZED); va_start(ap, fmt); _pjdlogv_common(func, file, line, loglevel, debuglevel, error, fmt, ap); va_end(ap); } /* * Log error, errno and exit. */ void _pjdlogv_exit(const char *func, const char *file, int line, int exitcode, int error, const char *fmt, va_list ap) { assert(pjdlog_initialized == PJDLOG_INITIALIZED); _pjdlogv_common(func, file, line, exitcode == 0 ? LOG_INFO : LOG_ERR, 0, error, fmt, ap); exit(exitcode); /* NOTREACHED */ } /* * Log error, errno and exit. */ void _pjdlog_exit(const char *func, const char *file, int line, int exitcode, int error, const char *fmt, ...) { va_list ap; assert(pjdlog_initialized == PJDLOG_INITIALIZED); va_start(ap, fmt); _pjdlogv_exit(func, file, line, exitcode, error, fmt, ap); /* NOTREACHED */ va_end(ap); } /* * Log failure message and exit. */ void _pjdlog_abort(const char *func, const char *file, int line, int error, const char *failedexpr, const char *fmt, ...) { va_list ap; assert(pjdlog_initialized == PJDLOG_INITIALIZED); /* * Set pjdlog_debug_level to 2, so that file, line and func are * included in log. This is fine as we will exit anyway. */ if (pjdlog_debug_level < 2) pjdlog_debug_level = 2; /* * When there is no message we pass __func__ as 'fmt'. * It would be cleaner to pass NULL or "", but gcc generates a warning * for both of those. */ if (fmt != func) { va_start(ap, fmt); _pjdlogv_common(func, file, line, LOG_CRIT, 0, -1, fmt, ap); va_end(ap); } if (failedexpr == NULL) { _pjdlog_common(func, file, line, LOG_CRIT, 0, -1, "Aborted."); } else { _pjdlog_common(func, file, line, LOG_CRIT, 0, -1, "Assertion failed: (%s).", failedexpr); } if (error != -1) _pjdlog_common(func, file, line, LOG_CRIT, 0, error, "Errno"); abort(); } #ifdef notyet /* * Receive log from the given socket. */ int pjdlog_receive(int sock) { char log[PJDLOG_MAX_MSGSIZE]; int loglevel, debuglevel; uint16_t dlen; if (robust_recv(sock, &dlen, sizeof(dlen)) == -1) return (-1); PJDLOG_ASSERT(dlen > 0); PJDLOG_ASSERT(dlen <= PJDLOG_MAX_MSGSIZE - 3); if (robust_recv(sock, log, (size_t)dlen) == -1) return (-1); log[dlen - 1] = '\0'; loglevel = log[0]; debuglevel = log[1]; _pjdlog_common(NULL, NULL, 0, loglevel, debuglevel, -1, "%s", log + 2); if (robust_send(sock, "ok", 2) == -1) return (-1); return (0); } #endif Index: head/sbin/hastd/pjdlog.c =================================================================== --- head/sbin/hastd/pjdlog.c (revision 335887) +++ head/sbin/hastd/pjdlog.c (revision 335888) @@ -1,616 +1,616 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2009-2010 The FreeBSD Foundation * Copyright (c) 2011 Pawel Jakub Dawidek * All rights reserved. * * This software was developed by Pawel Jakub Dawidek under sponsorship from * the FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include -#include #include +#include #include #include #include #include #include #include "pjdlog.h" #define PJDLOG_NEVER_INITIALIZED 0 #define PJDLOG_NOT_INITIALIZED 1 #define PJDLOG_INITIALIZED 2 static int pjdlog_initialized = PJDLOG_NEVER_INITIALIZED; static int pjdlog_mode, pjdlog_debug_level; static char pjdlog_prefix[128]; static int pjdlog_printf_arginfo_humanized_number(const struct printf_info *pi __unused, size_t n, int *argt) { assert(n >= 1); argt[0] = PA_INT | PA_FLAG_INTMAX; return (1); } static int pjdlog_printf_render_humanized_number(struct __printf_io *io, const struct printf_info *pi, const void * const *arg) { char buf[5]; intmax_t num; int ret; num = *(const intmax_t *)arg[0]; humanize_number(buf, sizeof(buf), (int64_t)num, "", HN_AUTOSCALE, HN_NOSPACE | HN_DECIMAL); ret = __printf_out(io, pi, buf, strlen(buf)); __printf_flush(io); return (ret); } static int pjdlog_printf_arginfo_sockaddr(const struct printf_info *pi __unused, size_t n, int *argt) { assert(n >= 1); argt[0] = PA_POINTER; return (1); } static int pjdlog_printf_render_sockaddr(struct __printf_io *io, const struct printf_info *pi, const void * const *arg) { const struct sockaddr_storage *ss; char buf[64]; int ret; ss = *(const struct sockaddr_storage * const *)arg[0]; switch (ss->ss_family) { case AF_INET: { char addr[INET_ADDRSTRLEN]; const struct sockaddr_in *sin; unsigned int port; sin = (const struct sockaddr_in *)ss; port = ntohs(sin->sin_port); if (inet_ntop(ss->ss_family, &sin->sin_addr, addr, sizeof(addr)) == NULL) { PJDLOG_ABORT("inet_ntop(AF_INET) failed: %s.", strerror(errno)); } snprintf(buf, sizeof(buf), "%s:%u", addr, port); break; } case AF_INET6: { char addr[INET6_ADDRSTRLEN]; const struct sockaddr_in6 *sin; unsigned int port; sin = (const struct sockaddr_in6 *)ss; port = ntohs(sin->sin6_port); if (inet_ntop(ss->ss_family, &sin->sin6_addr, addr, sizeof(addr)) == NULL) { PJDLOG_ABORT("inet_ntop(AF_INET6) failed: %s.", strerror(errno)); } snprintf(buf, sizeof(buf), "[%s]:%u", addr, port); break; } default: snprintf(buf, sizeof(buf), "[unsupported family %hhu]", ss->ss_family); break; } ret = __printf_out(io, pi, buf, strlen(buf)); __printf_flush(io); return (ret); } void pjdlog_init(int mode) { int saved_errno; assert(pjdlog_initialized == PJDLOG_NEVER_INITIALIZED || pjdlog_initialized == PJDLOG_NOT_INITIALIZED); assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG); saved_errno = errno; if (pjdlog_initialized == PJDLOG_NEVER_INITIALIZED) { __use_xprintf = 1; register_printf_render_std("T"); register_printf_render('N', pjdlog_printf_render_humanized_number, pjdlog_printf_arginfo_humanized_number); register_printf_render('S', pjdlog_printf_render_sockaddr, pjdlog_printf_arginfo_sockaddr); } if (mode == PJDLOG_MODE_SYSLOG) openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON); pjdlog_mode = mode; pjdlog_debug_level = 0; bzero(pjdlog_prefix, sizeof(pjdlog_prefix)); pjdlog_initialized = PJDLOG_INITIALIZED; errno = saved_errno; } void pjdlog_fini(void) { int saved_errno; assert(pjdlog_initialized == PJDLOG_INITIALIZED); saved_errno = errno; if (pjdlog_mode == PJDLOG_MODE_SYSLOG) closelog(); pjdlog_initialized = PJDLOG_NOT_INITIALIZED; errno = saved_errno; } /* * Configure where the logs should go. * By default they are send to stdout/stderr, but after going into background * (eg. by calling daemon(3)) application is responsible for changing mode to * PJDLOG_MODE_SYSLOG, so logs will be send to syslog. */ void pjdlog_mode_set(int mode) { int saved_errno; assert(pjdlog_initialized == PJDLOG_INITIALIZED); assert(mode == PJDLOG_MODE_STD || mode == PJDLOG_MODE_SYSLOG); if (pjdlog_mode == mode) return; saved_errno = errno; if (mode == PJDLOG_MODE_SYSLOG) openlog(NULL, LOG_PID | LOG_NDELAY, LOG_DAEMON); else /* if (mode == PJDLOG_MODE_STD) */ closelog(); pjdlog_mode = mode; errno = saved_errno; } /* * Return current mode. */ int pjdlog_mode_get(void) { assert(pjdlog_initialized == PJDLOG_INITIALIZED); return (pjdlog_mode); } /* * Set debug level. All the logs above the level specified here will be * ignored. */ void pjdlog_debug_set(int level) { assert(pjdlog_initialized == PJDLOG_INITIALIZED); assert(level >= 0); pjdlog_debug_level = level; } /* * Return current debug level. */ int pjdlog_debug_get(void) { assert(pjdlog_initialized == PJDLOG_INITIALIZED); return (pjdlog_debug_level); } /* * Set prefix that will be used before each log. * Setting prefix to NULL will remove it. */ void pjdlog_prefix_set(const char *fmt, ...) { va_list ap; assert(pjdlog_initialized == PJDLOG_INITIALIZED); va_start(ap, fmt); pjdlogv_prefix_set(fmt, ap); va_end(ap); } /* * Set prefix that will be used before each log. * Setting prefix to NULL will remove it. */ void pjdlogv_prefix_set(const char *fmt, va_list ap) { int saved_errno; assert(pjdlog_initialized == PJDLOG_INITIALIZED); assert(fmt != NULL); saved_errno = errno; vsnprintf(pjdlog_prefix, sizeof(pjdlog_prefix), fmt, ap); errno = saved_errno; } /* * Convert log level into string. */ static const char * pjdlog_level_string(int loglevel) { switch (loglevel) { case LOG_EMERG: return ("EMERG"); case LOG_ALERT: return ("ALERT"); case LOG_CRIT: return ("CRIT"); case LOG_ERR: return ("ERROR"); case LOG_WARNING: return ("WARNING"); case LOG_NOTICE: return ("NOTICE"); case LOG_INFO: return ("INFO"); case LOG_DEBUG: return ("DEBUG"); } assert(!"Invalid log level."); abort(); /* XXX: gcc */ } /* * Common log routine. */ void pjdlog_common(int loglevel, int debuglevel, int error, const char *fmt, ...) { va_list ap; assert(pjdlog_initialized == PJDLOG_INITIALIZED); va_start(ap, fmt); pjdlogv_common(loglevel, debuglevel, error, fmt, ap); va_end(ap); } /* * Common log routine, which can handle regular log level as well as debug * level. We decide here where to send the logs (stdout/stderr or syslog). */ void pjdlogv_common(int loglevel, int debuglevel, int error, const char *fmt, va_list ap) { int saved_errno; assert(pjdlog_initialized == PJDLOG_INITIALIZED); assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT || loglevel == LOG_CRIT || loglevel == LOG_ERR || loglevel == LOG_WARNING || loglevel == LOG_NOTICE || loglevel == LOG_INFO || loglevel == LOG_DEBUG); assert(loglevel != LOG_DEBUG || debuglevel > 0); assert(error >= -1); /* Ignore debug above configured level. */ if (loglevel == LOG_DEBUG && debuglevel > pjdlog_debug_level) return; saved_errno = errno; switch (pjdlog_mode) { case PJDLOG_MODE_STD: { FILE *out; /* * We send errors and warning to stderr and the rest to stdout. */ switch (loglevel) { case LOG_EMERG: case LOG_ALERT: case LOG_CRIT: case LOG_ERR: case LOG_WARNING: out = stderr; break; case LOG_NOTICE: case LOG_INFO: case LOG_DEBUG: out = stdout; break; default: assert(!"Invalid loglevel."); abort(); /* XXX: gcc */ } fprintf(out, "[%s]", pjdlog_level_string(loglevel)); /* Attach debuglevel if this is debug log. */ if (loglevel == LOG_DEBUG) fprintf(out, "[%d]", debuglevel); fprintf(out, " %s", pjdlog_prefix); vfprintf(out, fmt, ap); if (error != -1) fprintf(out, ": %s.", strerror(error)); fprintf(out, "\n"); fflush(out); break; } case PJDLOG_MODE_SYSLOG: { char log[1024]; int len; len = snprintf(log, sizeof(log), "%s", pjdlog_prefix); if ((size_t)len < sizeof(log)) len += vsnprintf(log + len, sizeof(log) - len, fmt, ap); if (error != -1 && (size_t)len < sizeof(log)) { (void)snprintf(log + len, sizeof(log) - len, ": %s.", strerror(error)); } syslog(loglevel, "%s", log); break; } default: assert(!"Invalid mode."); } errno = saved_errno; } /* * Regular logs. */ void pjdlogv(int loglevel, const char *fmt, va_list ap) { assert(pjdlog_initialized == PJDLOG_INITIALIZED); /* LOG_DEBUG is invalid here, pjdlogv?_debug() should be used. */ assert(loglevel == LOG_EMERG || loglevel == LOG_ALERT || loglevel == LOG_CRIT || loglevel == LOG_ERR || loglevel == LOG_WARNING || loglevel == LOG_NOTICE || loglevel == LOG_INFO); pjdlogv_common(loglevel, 0, -1, fmt, ap); } /* * Regular logs. */ void pjdlog(int loglevel, const char *fmt, ...) { va_list ap; assert(pjdlog_initialized == PJDLOG_INITIALIZED); va_start(ap, fmt); pjdlogv(loglevel, fmt, ap); va_end(ap); } /* * Debug logs. */ void pjdlogv_debug(int debuglevel, const char *fmt, va_list ap) { assert(pjdlog_initialized == PJDLOG_INITIALIZED); pjdlogv_common(LOG_DEBUG, debuglevel, -1, fmt, ap); } /* * Debug logs. */ void pjdlog_debug(int debuglevel, const char *fmt, ...) { va_list ap; assert(pjdlog_initialized == PJDLOG_INITIALIZED); va_start(ap, fmt); pjdlogv_debug(debuglevel, fmt, ap); va_end(ap); } /* * Error logs with errno logging. */ void pjdlogv_errno(int loglevel, const char *fmt, va_list ap) { assert(pjdlog_initialized == PJDLOG_INITIALIZED); pjdlogv_common(loglevel, 0, errno, fmt, ap); } /* * Error logs with errno logging. */ void pjdlog_errno(int loglevel, const char *fmt, ...) { va_list ap; assert(pjdlog_initialized == PJDLOG_INITIALIZED); va_start(ap, fmt); pjdlogv_errno(loglevel, fmt, ap); va_end(ap); } /* * Log error, errno and exit. */ void pjdlogv_exit(int exitcode, const char *fmt, va_list ap) { assert(pjdlog_initialized == PJDLOG_INITIALIZED); pjdlogv_errno(LOG_ERR, fmt, ap); exit(exitcode); /* NOTREACHED */ } /* * Log error, errno and exit. */ void pjdlog_exit(int exitcode, const char *fmt, ...) { va_list ap; assert(pjdlog_initialized == PJDLOG_INITIALIZED); va_start(ap, fmt); pjdlogv_exit(exitcode, fmt, ap); /* NOTREACHED */ va_end(ap); } /* * Log error and exit. */ void pjdlogv_exitx(int exitcode, const char *fmt, va_list ap) { assert(pjdlog_initialized == PJDLOG_INITIALIZED); pjdlogv(LOG_ERR, fmt, ap); exit(exitcode); /* NOTREACHED */ } /* * Log error and exit. */ void pjdlog_exitx(int exitcode, const char *fmt, ...) { va_list ap; assert(pjdlog_initialized == PJDLOG_INITIALIZED); va_start(ap, fmt); pjdlogv_exitx(exitcode, fmt, ap); /* NOTREACHED */ va_end(ap); } /* * Log failure message and exit. */ void pjdlog_abort(const char *func, const char *file, int line, const char *failedexpr, const char *fmt, ...) { va_list ap; assert(pjdlog_initialized == PJDLOG_INITIALIZED); /* * When there is no message we pass __func__ as 'fmt'. * It would be cleaner to pass NULL or "", but gcc generates a warning * for both of those. */ if (fmt != func) { va_start(ap, fmt); pjdlogv_critical(fmt, ap); va_end(ap); } if (failedexpr == NULL) { if (func == NULL) { pjdlog_critical("Aborted at file %s, line %d.", file, line); } else { pjdlog_critical("Aborted at function %s, file %s, line %d.", func, file, line); } } else { if (func == NULL) { pjdlog_critical("Assertion failed: (%s), file %s, line %d.", failedexpr, file, line); } else { pjdlog_critical("Assertion failed: (%s), function %s, file %s, line %d.", failedexpr, func, file, line); } } abort(); }