18a16b7a1SPedro F. Giffuni /*- 28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 38a16b7a1SPedro F. Giffuni * 458f0484fSRodney W. Grimes * Copyright (c) 1983, 1988, 1993 558f0484fSRodney W. Grimes * The Regents of the University of California. All rights reserved. 658f0484fSRodney W. Grimes * 758f0484fSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 858f0484fSRodney W. Grimes * modification, are permitted provided that the following conditions 958f0484fSRodney W. Grimes * are met: 1058f0484fSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 1158f0484fSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 1258f0484fSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 1358f0484fSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 1458f0484fSRodney W. Grimes * documentation and/or other materials provided with the distribution. 15fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 1658f0484fSRodney W. Grimes * may be used to endorse or promote products derived from this software 1758f0484fSRodney W. Grimes * without specific prior written permission. 1858f0484fSRodney W. Grimes * 1958f0484fSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2058f0484fSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2158f0484fSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2258f0484fSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2358f0484fSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2458f0484fSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2558f0484fSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2658f0484fSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2758f0484fSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2858f0484fSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2958f0484fSRodney W. Grimes * SUCH DAMAGE. 3058f0484fSRodney W. Grimes */ 3158f0484fSRodney W. Grimes 32b231cb39SDavid E. O'Brien #include <sys/cdefs.h> 33c1920558SJohn Baldwin __SCCSID("@(#)syslog.c 8.5 (Berkeley) 4/29/95"); 34b231cb39SDavid E. O'Brien __FBSDID("$FreeBSD$"); 3558f0484fSRodney W. Grimes 36d201fe46SDaniel Eischen #include "namespace.h" 378129693eSEd Schouten #include <sys/param.h> 3858f0484fSRodney W. Grimes #include <sys/socket.h> 3958f0484fSRodney W. Grimes #include <sys/syslog.h> 408129693eSEd Schouten #include <sys/time.h> 4158f0484fSRodney W. Grimes #include <sys/uio.h> 42d584948eSBrian Somers #include <sys/un.h> 4358f0484fSRodney W. Grimes #include <netdb.h> 4458f0484fSRodney W. Grimes 4558f0484fSRodney W. Grimes #include <errno.h> 4658f0484fSRodney W. Grimes #include <fcntl.h> 4758f0484fSRodney W. Grimes #include <paths.h> 4896575206SGleb Smirnoff #include <pthread.h> 49ddc68905SGleb Smirnoff #include <stdbool.h> 5058f0484fSRodney W. Grimes #include <stdio.h> 514cd01193SMark Murray #include <stdlib.h> 5258f0484fSRodney W. Grimes #include <string.h> 5358f0484fSRodney W. Grimes #include <time.h> 5458f0484fSRodney W. Grimes #include <unistd.h> 5558f0484fSRodney W. Grimes 5658f0484fSRodney W. Grimes #include <stdarg.h> 57d201fe46SDaniel Eischen #include "un-namespace.h" 5858f0484fSRodney W. Grimes 594cd01193SMark Murray #include "libc_private.h" 604cd01193SMark Murray 6188105995SDmitry Wagin /* Maximum number of characters of syslog message */ 6288105995SDmitry Wagin #define MAXLINE 8192 6388105995SDmitry Wagin 6458f0484fSRodney W. Grimes static int LogFile = -1; /* fd for log */ 65ddc68905SGleb Smirnoff static bool connected; /* have done connect */ 667e6ace85SPeter Wemm static int opened; /* have done openlog() */ 6758f0484fSRodney W. Grimes static int LogStat = 0; /* status bits, set by openlog() */ 68e9ae9fa9SEugene Grosbein static pid_t LogPid = -1; /* process id to tag the entry with */ 6958f0484fSRodney W. Grimes static const char *LogTag = NULL; /* string to tag the entry with */ 70e9ae9fa9SEugene Grosbein static int LogTagLength = -1; /* usable part of LogTag */ 7158f0484fSRodney W. Grimes static int LogFacility = LOG_USER; /* default facility code */ 7258f0484fSRodney W. Grimes static int LogMask = 0xff; /* mask of priorities to be logged */ 7396575206SGleb Smirnoff static pthread_mutex_t syslog_mutex = PTHREAD_MUTEX_INITIALIZER; 7496575206SGleb Smirnoff 7596575206SGleb Smirnoff #define THREAD_LOCK() \ 7696575206SGleb Smirnoff do { \ 7796575206SGleb Smirnoff if (__isthreaded) _pthread_mutex_lock(&syslog_mutex); \ 7896575206SGleb Smirnoff } while(0) 7996575206SGleb Smirnoff #define THREAD_UNLOCK() \ 8096575206SGleb Smirnoff do { \ 8196575206SGleb Smirnoff if (__isthreaded) _pthread_mutex_unlock(&syslog_mutex); \ 8296575206SGleb Smirnoff } while(0) 8358f0484fSRodney W. Grimes 842933cd31SBryan Drewery /* RFC5424 defined value. */ 852933cd31SBryan Drewery #define NILVALUE "-" 862933cd31SBryan Drewery 87b231cb39SDavid E. O'Brien static void disconnectlog(void); /* disconnect from syslogd */ 88b231cb39SDavid E. O'Brien static void connectlog(void); /* (re)connect to syslogd */ 8996575206SGleb Smirnoff static void openlog_unlocked(const char *, int, int); 90e9ae9fa9SEugene Grosbein static void parse_tag(void); /* parse ident[NNN] if needed */ 917e6ace85SPeter Wemm 9258f0484fSRodney W. Grimes /* 937c8e2aa4SPeter Wemm * Format of the magic cookie passed through the stdio hook 947c8e2aa4SPeter Wemm */ 957c8e2aa4SPeter Wemm struct bufcookie { 967c8e2aa4SPeter Wemm char *base; /* start of buffer */ 977c8e2aa4SPeter Wemm int left; 987c8e2aa4SPeter Wemm }; 997c8e2aa4SPeter Wemm 1007c8e2aa4SPeter Wemm /* 1017c8e2aa4SPeter Wemm * stdio write hook for writing to a static string buffer 1027c8e2aa4SPeter Wemm * XXX: Maybe one day, dynamically allocate it so that the line length 1037c8e2aa4SPeter Wemm * is `unlimited'. 1047c8e2aa4SPeter Wemm */ 105fd42c4d8SStefan Farfeleder static int 106fd42c4d8SStefan Farfeleder writehook(void *cookie, const char *buf, int len) 1077c8e2aa4SPeter Wemm { 1087c8e2aa4SPeter Wemm struct bufcookie *h; /* private `handle' */ 1097c8e2aa4SPeter Wemm 1107c8e2aa4SPeter Wemm h = (struct bufcookie *)cookie; 1117c8e2aa4SPeter Wemm if (len > h->left) { 1127c8e2aa4SPeter Wemm /* clip in case of wraparound */ 1137c8e2aa4SPeter Wemm len = h->left; 1147c8e2aa4SPeter Wemm } 1157c8e2aa4SPeter Wemm if (len > 0) { 1167c8e2aa4SPeter Wemm (void)memcpy(h->base, buf, len); /* `write' it. */ 1177c8e2aa4SPeter Wemm h->base += len; 1187c8e2aa4SPeter Wemm h->left -= len; 1197c8e2aa4SPeter Wemm } 1205b1deb3cSPoul-Henning Kamp return len; 1217c8e2aa4SPeter Wemm } 1227c8e2aa4SPeter Wemm 1237c8e2aa4SPeter Wemm /* 12458f0484fSRodney W. Grimes * syslog, vsyslog -- 12558f0484fSRodney W. Grimes * print message on log file; output is intended for syslogd(8). 12658f0484fSRodney W. Grimes */ 12758f0484fSRodney W. Grimes void 12858f0484fSRodney W. Grimes syslog(int pri, const char *fmt, ...) 12958f0484fSRodney W. Grimes { 13058f0484fSRodney W. Grimes va_list ap; 13158f0484fSRodney W. Grimes 13258f0484fSRodney W. Grimes va_start(ap, fmt); 13358f0484fSRodney W. Grimes vsyslog(pri, fmt, ap); 13458f0484fSRodney W. Grimes va_end(ap); 13558f0484fSRodney W. Grimes } 13658f0484fSRodney W. Grimes 137f3990417SKonstantin Belousov static void 138f3990417SKonstantin Belousov vsyslog1(int pri, const char *fmt, va_list ap) 13958f0484fSRodney W. Grimes { 1408129693eSEd Schouten struct timeval now; 1418129693eSEd Schouten struct tm tm; 142b231cb39SDavid E. O'Brien char ch, *p; 1438129693eSEd Schouten long tz_offset; 1448129693eSEd Schouten int cnt, fd, saved_errno; 14588105995SDmitry Wagin char hostname[MAXHOSTNAMELEN], *stdp, tbuf[MAXLINE], fmt_cpy[MAXLINE], 1468129693eSEd Schouten errstr[64], tz_sign; 1477c8e2aa4SPeter Wemm FILE *fp, *fmt_fp; 1487c8e2aa4SPeter Wemm struct bufcookie tbuf_cookie; 1497c8e2aa4SPeter Wemm struct bufcookie fmt_cookie; 15058f0484fSRodney W. Grimes 15158f0484fSRodney W. Grimes #define INTERNALLOG LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID 15258f0484fSRodney W. Grimes /* Check for invalid bits. */ 15358f0484fSRodney W. Grimes if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) { 15458f0484fSRodney W. Grimes syslog(INTERNALLOG, 15558f0484fSRodney W. Grimes "syslog: unknown facility/priority: %x", pri); 15658f0484fSRodney W. Grimes pri &= LOG_PRIMASK|LOG_FACMASK; 15758f0484fSRodney W. Grimes } 15858f0484fSRodney W. Grimes 1593a31b448SDavid Xu saved_errno = errno; 1603a31b448SDavid Xu 16158f0484fSRodney W. Grimes /* Check priority against setlogmask values. */ 162f3990417SKonstantin Belousov if (!(LOG_MASK(LOG_PRI(pri)) & LogMask)) 16358f0484fSRodney W. Grimes return; 16458f0484fSRodney W. Grimes 16558f0484fSRodney W. Grimes /* Set default facility if none specified. */ 16658f0484fSRodney W. Grimes if ((pri & LOG_FACMASK) == 0) 16758f0484fSRodney W. Grimes pri |= LogFacility; 16858f0484fSRodney W. Grimes 1697c8e2aa4SPeter Wemm /* Create the primary stdio hook */ 1707c8e2aa4SPeter Wemm tbuf_cookie.base = tbuf; 1717c8e2aa4SPeter Wemm tbuf_cookie.left = sizeof(tbuf); 1727c8e2aa4SPeter Wemm fp = fwopen(&tbuf_cookie, writehook); 173f3990417SKonstantin Belousov if (fp == NULL) 1747c8e2aa4SPeter Wemm return; 1757c8e2aa4SPeter Wemm 1768129693eSEd Schouten /* Build the message according to RFC 5424. Tag and version. */ 1778129693eSEd Schouten (void)fprintf(fp, "<%d>1 ", pri); 1788129693eSEd Schouten /* Timestamp similar to RFC 3339. */ 1798129693eSEd Schouten if (gettimeofday(&now, NULL) == 0 && 1808129693eSEd Schouten localtime_r(&now.tv_sec, &tm) != NULL) { 1818129693eSEd Schouten if (tm.tm_gmtoff < 0) { 1828129693eSEd Schouten tz_sign = '-'; 1838129693eSEd Schouten tz_offset = -tm.tm_gmtoff; 1848129693eSEd Schouten } else { 1858129693eSEd Schouten tz_sign = '+'; 1868129693eSEd Schouten tz_offset = tm.tm_gmtoff; 1878129693eSEd Schouten } 1888129693eSEd Schouten 1898129693eSEd Schouten (void)fprintf(fp, 1908129693eSEd Schouten "%04d-%02d-%02d" /* Date. */ 1918129693eSEd Schouten "T%02d:%02d:%02d.%06ld" /* Time. */ 1928129693eSEd Schouten "%c%02ld:%02ld ", /* Time zone offset. */ 1938129693eSEd Schouten tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, 1948129693eSEd Schouten tm.tm_hour, tm.tm_min, tm.tm_sec, now.tv_usec, 1958129693eSEd Schouten tz_sign, tz_offset / 3600, (tz_offset % 3600) / 60); 1968129693eSEd Schouten } else 1972933cd31SBryan Drewery (void)fputs(NILVALUE " ", fp); 1988129693eSEd Schouten /* Hostname. */ 1998129693eSEd Schouten (void)gethostname(hostname, sizeof(hostname)); 2002933cd31SBryan Drewery (void)fprintf(fp, "%s ", 2012933cd31SBryan Drewery hostname[0] == '\0' ? NILVALUE : hostname); 2027c8e2aa4SPeter Wemm if (LogStat & LOG_PERROR) { 2037c8e2aa4SPeter Wemm /* Transfer to string buffer */ 2047c8e2aa4SPeter Wemm (void)fflush(fp); 2057c8e2aa4SPeter Wemm stdp = tbuf + (sizeof(tbuf) - tbuf_cookie.left); 2067c8e2aa4SPeter Wemm } 2072933cd31SBryan Drewery /* Application name. */ 2082933cd31SBryan Drewery if (LogTag == NULL) 2092933cd31SBryan Drewery LogTag = _getprogname(); 210e9ae9fa9SEugene Grosbein else if (LogTagLength == -1) 211e9ae9fa9SEugene Grosbein parse_tag(); 212e9ae9fa9SEugene Grosbein if (LogTagLength > 0) 213e9ae9fa9SEugene Grosbein (void)fprintf(fp, "%.*s ", LogTagLength, LogTag); 214e9ae9fa9SEugene Grosbein else 2152933cd31SBryan Drewery (void)fprintf(fp, "%s ", LogTag == NULL ? NILVALUE : LogTag); 2168129693eSEd Schouten /* 2178129693eSEd Schouten * Provide the process ID regardless of whether LOG_PID has been 2188129693eSEd Schouten * specified, as it provides valuable information. Many 2198129693eSEd Schouten * applications tend not to use this, even though they should. 2208129693eSEd Schouten */ 221*2ce3ef55SEugene Grosbein if (LogTagLength <= 0) 222e9ae9fa9SEugene Grosbein LogPid = getpid(); 223e9ae9fa9SEugene Grosbein (void)fprintf(fp, "%d ", (int)LogPid); 2242933cd31SBryan Drewery /* Message ID. */ 2252933cd31SBryan Drewery (void)fputs(NILVALUE " ", fp); 2262933cd31SBryan Drewery /* Structured data. */ 2272933cd31SBryan Drewery (void)fputs(NILVALUE " ", fp); 2287c8e2aa4SPeter Wemm 2297c8e2aa4SPeter Wemm /* Check to see if we can skip expanding the %m */ 2307c8e2aa4SPeter Wemm if (strstr(fmt, "%m")) { 2317c8e2aa4SPeter Wemm 2327c8e2aa4SPeter Wemm /* Create the second stdio hook */ 2337c8e2aa4SPeter Wemm fmt_cookie.base = fmt_cpy; 2347c8e2aa4SPeter Wemm fmt_cookie.left = sizeof(fmt_cpy) - 1; 2357c8e2aa4SPeter Wemm fmt_fp = fwopen(&fmt_cookie, writehook); 2367c8e2aa4SPeter Wemm if (fmt_fp == NULL) { 2377c8e2aa4SPeter Wemm fclose(fp); 2387c8e2aa4SPeter Wemm return; 23958f0484fSRodney W. Grimes } 24058f0484fSRodney W. Grimes 241e6cfb1ccSAlfred Perlstein /* 242e6cfb1ccSAlfred Perlstein * Substitute error message for %m. Be careful not to 243e6cfb1ccSAlfred Perlstein * molest an escaped percent "%%m". We want to pass it 244e6cfb1ccSAlfred Perlstein * on untouched as the format is later parsed by vfprintf. 245e6cfb1ccSAlfred Perlstein */ 246e6cfb1ccSAlfred Perlstein for ( ; (ch = *fmt); ++fmt) { 24758f0484fSRodney W. Grimes if (ch == '%' && fmt[1] == 'm') { 24858f0484fSRodney W. Grimes ++fmt; 24996575206SGleb Smirnoff strerror_r(saved_errno, errstr, sizeof(errstr)); 25096575206SGleb Smirnoff fputs(errstr, fmt_fp); 251e6cfb1ccSAlfred Perlstein } else if (ch == '%' && fmt[1] == '%') { 252e6cfb1ccSAlfred Perlstein ++fmt; 2537c8e2aa4SPeter Wemm fputc(ch, fmt_fp); 254e6cfb1ccSAlfred Perlstein fputc(ch, fmt_fp); 255e6cfb1ccSAlfred Perlstein } else { 256e6cfb1ccSAlfred Perlstein fputc(ch, fmt_fp); 257e6cfb1ccSAlfred Perlstein } 258e6cfb1ccSAlfred Perlstein } 25958f0484fSRodney W. Grimes 2607c8e2aa4SPeter Wemm /* Null terminate if room */ 2617c8e2aa4SPeter Wemm fputc(0, fmt_fp); 2627c8e2aa4SPeter Wemm fclose(fmt_fp); 2637c8e2aa4SPeter Wemm 2647c8e2aa4SPeter Wemm /* Guarantee null termination */ 2657c8e2aa4SPeter Wemm fmt_cpy[sizeof(fmt_cpy) - 1] = '\0'; 2667c8e2aa4SPeter Wemm 2677c8e2aa4SPeter Wemm fmt = fmt_cpy; 2687c8e2aa4SPeter Wemm } 2697c8e2aa4SPeter Wemm 2702933cd31SBryan Drewery /* Message. */ 2717c8e2aa4SPeter Wemm (void)vfprintf(fp, fmt, ap); 2727c8e2aa4SPeter Wemm (void)fclose(fp); 2737c8e2aa4SPeter Wemm 2747c8e2aa4SPeter Wemm cnt = sizeof(tbuf) - tbuf_cookie.left; 27558f0484fSRodney W. Grimes 276857b57eaSDiomidis Spinellis /* Remove a trailing newline */ 277857b57eaSDiomidis Spinellis if (tbuf[cnt - 1] == '\n') 278857b57eaSDiomidis Spinellis cnt--; 279857b57eaSDiomidis Spinellis 28058f0484fSRodney W. Grimes /* Output to stderr if requested. */ 28158f0484fSRodney W. Grimes if (LogStat & LOG_PERROR) { 28258f0484fSRodney W. Grimes struct iovec iov[2]; 283b231cb39SDavid E. O'Brien struct iovec *v = iov; 28458f0484fSRodney W. Grimes 28558f0484fSRodney W. Grimes v->iov_base = stdp; 28658f0484fSRodney W. Grimes v->iov_len = cnt - (stdp - tbuf); 28758f0484fSRodney W. Grimes ++v; 28858f0484fSRodney W. Grimes v->iov_base = "\n"; 28958f0484fSRodney W. Grimes v->iov_len = 1; 290d201fe46SDaniel Eischen (void)_writev(STDERR_FILENO, iov, 2); 29158f0484fSRodney W. Grimes } 29258f0484fSRodney W. Grimes 29358f0484fSRodney W. Grimes /* Get connected, output the message to the local logger. */ 2947e6ace85SPeter Wemm if (!opened) 29596575206SGleb Smirnoff openlog_unlocked(LogTag, LogStat | LOG_NDELAY, 0); 2967e6ace85SPeter Wemm connectlog(); 2977e6ace85SPeter Wemm 2987e6ace85SPeter Wemm /* 299ddc68905SGleb Smirnoff * If the send() failed, there are two likely scenarios: 300ddc68905SGleb Smirnoff * 1) syslogd was restarted. In this case make one (only) attempt 301ddc68905SGleb Smirnoff * to reconnect. 302ddc68905SGleb Smirnoff * 2) We filled our buffer due to syslogd not being able to read 303ddc68905SGleb Smirnoff * as fast as we write. In this case prefer to lose the current 304ddc68905SGleb Smirnoff * message rather than whole buffer of previously logged data. 3057e6ace85SPeter Wemm */ 3062e89951bSGleb Smirnoff if (send(LogFile, tbuf, cnt, 0) < 0) { 3072e89951bSGleb Smirnoff if (errno != ENOBUFS) { 3087e6ace85SPeter Wemm disconnectlog(); 3097e6ace85SPeter Wemm connectlog(); 310f3990417SKonstantin Belousov if (send(LogFile, tbuf, cnt, 0) >= 0) 31152e05d9aSXin LI return; 31296575206SGleb Smirnoff } 313f3990417SKonstantin Belousov } else 3148ba85e77SGleb Smirnoff return; 31558f0484fSRodney W. Grimes 31658f0484fSRodney W. Grimes /* 31794998878SDavid Malone * Output the message to the console; try not to block 31894998878SDavid Malone * as a blocking console should not stop other processes. 31994998878SDavid Malone * Make sure the error reported is the one from the syslogd failure. 32058f0484fSRodney W. Grimes */ 32158f0484fSRodney W. Grimes if (LogStat & LOG_CONS && 32205eb11cbSJilles Tjoelker (fd = _open(_PATH_CONSOLE, O_WRONLY|O_NONBLOCK|O_CLOEXEC, 0)) >= 32305eb11cbSJilles Tjoelker 0) { 32411e67a9fSPeter Wemm struct iovec iov[2]; 325b231cb39SDavid E. O'Brien struct iovec *v = iov; 32611e67a9fSPeter Wemm 3278129693eSEd Schouten p = strchr(tbuf, '>') + 3; 32811e67a9fSPeter Wemm v->iov_base = p; 32911e67a9fSPeter Wemm v->iov_len = cnt - (p - tbuf); 33011e67a9fSPeter Wemm ++v; 33111e67a9fSPeter Wemm v->iov_base = "\r\n"; 33211e67a9fSPeter Wemm v->iov_len = 2; 333d201fe46SDaniel Eischen (void)_writev(fd, iov, 2); 3349233c4d9SJason Evans (void)_close(fd); 33558f0484fSRodney W. Grimes } 336f3990417SKonstantin Belousov } 337f3990417SKonstantin Belousov 338f3990417SKonstantin Belousov static void 339f3990417SKonstantin Belousov syslog_cancel_cleanup(void *arg __unused) 340f3990417SKonstantin Belousov { 34196575206SGleb Smirnoff 34296575206SGleb Smirnoff THREAD_UNLOCK(); 34358f0484fSRodney W. Grimes } 34496575206SGleb Smirnoff 345f3990417SKonstantin Belousov void 346f3990417SKonstantin Belousov vsyslog(int pri, const char *fmt, va_list ap) 347f3990417SKonstantin Belousov { 348f3990417SKonstantin Belousov 349f3990417SKonstantin Belousov THREAD_LOCK(); 350f3990417SKonstantin Belousov pthread_cleanup_push(syslog_cancel_cleanup, NULL); 351f3990417SKonstantin Belousov vsyslog1(pri, fmt, ap); 352f3990417SKonstantin Belousov pthread_cleanup_pop(1); 353f3990417SKonstantin Belousov } 354f3990417SKonstantin Belousov 35596575206SGleb Smirnoff /* Should be called with mutex acquired */ 3567e6ace85SPeter Wemm static void 357fd42c4d8SStefan Farfeleder disconnectlog(void) 3587e6ace85SPeter Wemm { 3597e6ace85SPeter Wemm /* 3607e6ace85SPeter Wemm * If the user closed the FD and opened another in the same slot, 3617e6ace85SPeter Wemm * that's their problem. They should close it before calling on 3627e6ace85SPeter Wemm * system services. 3637e6ace85SPeter Wemm */ 3647e6ace85SPeter Wemm if (LogFile != -1) { 3659233c4d9SJason Evans _close(LogFile); 3667e6ace85SPeter Wemm LogFile = -1; 3677e6ace85SPeter Wemm } 368ddc68905SGleb Smirnoff connected = false; /* retry connect */ 3697e6ace85SPeter Wemm } 3707e6ace85SPeter Wemm 37196575206SGleb Smirnoff /* Should be called with mutex acquired */ 3727e6ace85SPeter Wemm static void 373fd42c4d8SStefan Farfeleder connectlog(void) 3747e6ace85SPeter Wemm { 375d584948eSBrian Somers struct sockaddr_un SyslogAddr; /* AF_UNIX address of local logger */ 376cf49f439SJohn Polstra 3777e6ace85SPeter Wemm if (LogFile == -1) { 37888105995SDmitry Wagin socklen_t len; 37988105995SDmitry Wagin 3800b89df4aSJilles Tjoelker if ((LogFile = _socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 3810b89df4aSJilles Tjoelker 0)) == -1) 3827e6ace85SPeter Wemm return; 38388105995SDmitry Wagin if (_getsockopt(LogFile, SOL_SOCKET, SO_SNDBUF, &len, 38488105995SDmitry Wagin &(socklen_t){sizeof(len)}) == 0) { 38588105995SDmitry Wagin if (len < MAXLINE) { 38688105995SDmitry Wagin len = MAXLINE; 38788105995SDmitry Wagin (void)_setsockopt(LogFile, SOL_SOCKET, SO_SNDBUF, 38888105995SDmitry Wagin &len, sizeof(len)); 38988105995SDmitry Wagin } 39088105995SDmitry Wagin } 3917e6ace85SPeter Wemm } 392ddc68905SGleb Smirnoff if (!connected) { 393d584948eSBrian Somers SyslogAddr.sun_len = sizeof(SyslogAddr); 394d584948eSBrian Somers SyslogAddr.sun_family = AF_UNIX; 395240d5a9bSGleb Smirnoff 396d584948eSBrian Somers (void)strncpy(SyslogAddr.sun_path, _PATH_LOG, 3970b3b961eSBrian Somers sizeof SyslogAddr.sun_path); 398240d5a9bSGleb Smirnoff if (_connect(LogFile, (struct sockaddr *)&SyslogAddr, 399240d5a9bSGleb Smirnoff sizeof(SyslogAddr)) != -1) 400ddc68905SGleb Smirnoff connected = true; 401ddc68905SGleb Smirnoff else { 4029233c4d9SJason Evans (void)_close(LogFile); 4037e6ace85SPeter Wemm LogFile = -1; 404cf49f439SJohn Polstra } 4057e6ace85SPeter Wemm } 4067e6ace85SPeter Wemm } 4077e6ace85SPeter Wemm 40896575206SGleb Smirnoff static void 409fd42c4d8SStefan Farfeleder openlog_unlocked(const char *ident, int logstat, int logfac) 41058f0484fSRodney W. Grimes { 411e9ae9fa9SEugene Grosbein if (ident != NULL) { 41258f0484fSRodney W. Grimes LogTag = ident; 413e9ae9fa9SEugene Grosbein LogTagLength = -1; 414e9ae9fa9SEugene Grosbein } 41558f0484fSRodney W. Grimes LogStat = logstat; 416e9ae9fa9SEugene Grosbein parse_tag(); 41758f0484fSRodney W. Grimes if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0) 41858f0484fSRodney W. Grimes LogFacility = logfac; 41958f0484fSRodney W. Grimes 4207e6ace85SPeter Wemm if (LogStat & LOG_NDELAY) /* open immediately */ 4217e6ace85SPeter Wemm connectlog(); 4227e6ace85SPeter Wemm 4237e6ace85SPeter Wemm opened = 1; /* ident and facility has been set */ 42458f0484fSRodney W. Grimes } 42558f0484fSRodney W. Grimes 42658f0484fSRodney W. Grimes void 427fd42c4d8SStefan Farfeleder openlog(const char *ident, int logstat, int logfac) 42896575206SGleb Smirnoff { 429f3990417SKonstantin Belousov 43096575206SGleb Smirnoff THREAD_LOCK(); 431f3990417SKonstantin Belousov pthread_cleanup_push(syslog_cancel_cleanup, NULL); 43296575206SGleb Smirnoff openlog_unlocked(ident, logstat, logfac); 433f3990417SKonstantin Belousov pthread_cleanup_pop(1); 43496575206SGleb Smirnoff } 43596575206SGleb Smirnoff 43696575206SGleb Smirnoff 43796575206SGleb Smirnoff void 438fd42c4d8SStefan Farfeleder closelog(void) 43958f0484fSRodney W. Grimes { 44096575206SGleb Smirnoff THREAD_LOCK(); 441bf36cf8eSEitan Adler if (LogFile != -1) { 4429233c4d9SJason Evans (void)_close(LogFile); 44358f0484fSRodney W. Grimes LogFile = -1; 444bf36cf8eSEitan Adler } 445bedff4e8SRuslan Ermilov LogTag = NULL; 446e9ae9fa9SEugene Grosbein LogTagLength = -1; 447ddc68905SGleb Smirnoff connected = false; 44896575206SGleb Smirnoff THREAD_UNLOCK(); 44958f0484fSRodney W. Grimes } 45058f0484fSRodney W. Grimes 45158f0484fSRodney W. Grimes /* setlogmask -- set the log mask level */ 45258f0484fSRodney W. Grimes int 453fd42c4d8SStefan Farfeleder setlogmask(int pmask) 45458f0484fSRodney W. Grimes { 45558f0484fSRodney W. Grimes int omask; 45658f0484fSRodney W. Grimes 45796575206SGleb Smirnoff THREAD_LOCK(); 45858f0484fSRodney W. Grimes omask = LogMask; 45958f0484fSRodney W. Grimes if (pmask != 0) 46058f0484fSRodney W. Grimes LogMask = pmask; 46196575206SGleb Smirnoff THREAD_UNLOCK(); 46258f0484fSRodney W. Grimes return (omask); 46358f0484fSRodney W. Grimes } 464e9ae9fa9SEugene Grosbein 465e9ae9fa9SEugene Grosbein /* 4666ab555cfSEugene Grosbein * Obtain LogPid from LogTag formatted as per RFC 3164, 4676ab555cfSEugene Grosbein * Section 5.3 Originating Process Information: 4686ab555cfSEugene Grosbein * 4696ab555cfSEugene Grosbein * ident[NNN] 470e9ae9fa9SEugene Grosbein */ 471e9ae9fa9SEugene Grosbein static void 472e9ae9fa9SEugene Grosbein parse_tag(void) 473e9ae9fa9SEugene Grosbein { 474e9ae9fa9SEugene Grosbein char *begin, *end, *p; 475e9ae9fa9SEugene Grosbein pid_t pid; 476e9ae9fa9SEugene Grosbein 477e9ae9fa9SEugene Grosbein if (LogTag == NULL || (LogStat & LOG_PID) != 0) 478e9ae9fa9SEugene Grosbein return; 479e9ae9fa9SEugene Grosbein /* 480e9ae9fa9SEugene Grosbein * LogTagLength is -1 if LogTag was not parsed yet. 481e9ae9fa9SEugene Grosbein * Avoid multiple passes over same LogTag. 482e9ae9fa9SEugene Grosbein */ 483e9ae9fa9SEugene Grosbein LogTagLength = 0; 484e9ae9fa9SEugene Grosbein 485e9ae9fa9SEugene Grosbein /* Check for presence of opening [ and non-empty ident. */ 486e9ae9fa9SEugene Grosbein if ((begin = strchr(LogTag, '[')) == NULL || begin == LogTag) 487e9ae9fa9SEugene Grosbein return; 488e9ae9fa9SEugene Grosbein /* Check for presence of closing ] at the very end and non-empty pid. */ 489e9ae9fa9SEugene Grosbein if ((end = strchr(begin + 1, ']')) == NULL || end[1] != 0 || 490e9ae9fa9SEugene Grosbein (end - begin) < 2) 491e9ae9fa9SEugene Grosbein return; 492e9ae9fa9SEugene Grosbein 493e9ae9fa9SEugene Grosbein /* Check for pid to contain digits only. */ 494e9ae9fa9SEugene Grosbein pid = (pid_t)strtol(begin + 1, &p, 10); 495e9ae9fa9SEugene Grosbein if (p != end) 496e9ae9fa9SEugene Grosbein return; 497e9ae9fa9SEugene Grosbein 498e9ae9fa9SEugene Grosbein LogPid = pid; 499e9ae9fa9SEugene Grosbein LogTagLength = begin - LogTag; 500e9ae9fa9SEugene Grosbein } 501