syslog_r.c revision 1.6
1/* $OpenBSD: syslog_r.c,v 1.6 2014/10/03 15:41:18 bluhm Exp $ */ 2/* 3 * Copyright (c) 1983, 1988, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of the University nor the names of its contributors 15 * may be used to endorse or promote products derived from this software 16 * without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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#include <sys/types.h> 32#include <sys/syslog.h> 33#include <sys/uio.h> 34#include <netdb.h> 35 36#include <errno.h> 37#include <fcntl.h> 38#include <paths.h> 39#include <stdio.h> 40#include <string.h> 41#include <time.h> 42#include <unistd.h> 43#include <stdarg.h> 44 45extern char *__progname; /* Program name, from crt0. */ 46 47int sendsyslog(const char *, size_t); 48 49void __vsyslog_r(int pri, struct syslog_data *, size_t (*)(char *, size_t), 50 const char *, va_list); 51 52/* Reentrant version of syslog, i.e. syslog_r() */ 53 54/* PRINTFLIKE3 */ 55void 56syslog_r(int pri, struct syslog_data *data, const char *fmt, ...) 57{ 58 va_list ap; 59 60 va_start(ap, fmt); 61 vsyslog_r(pri, data, fmt, ap); 62 va_end(ap); 63} 64 65void 66vsyslog_r(int pri, struct syslog_data *data, const char *fmt, va_list ap) 67{ 68 const char *ident; 69 70 __vsyslog_r(pri, data, NULL, fmt, ap); 71 72 /* close the socket without losing log_tag */ 73 ident = data->log_tag; 74 closelog_r(data); 75 data->log_tag = ident; 76} 77 78/* 79 * This is used by both syslog_r and syslog. The latter supplies 80 * a non-NULL gettime callback for filling in the date, but we also 81 * use the presence of that callback to decide whether it's safe 82 * to call strerror and what the name of the caller is 83 */ 84void 85__vsyslog_r(int pri, struct syslog_data *data, 86 size_t (*gettime)(char *, size_t), const char *fmt, va_list ap) 87{ 88 int cnt; 89 char ch, *p, *t; 90 int fd, saved_errno, error; 91#define TBUF_LEN 2048 92#define FMT_LEN 1024 93 char *conp = NULL, *stdp = NULL, tbuf[TBUF_LEN], fmt_cpy[FMT_LEN]; 94 int tbuf_left, fmt_left, prlen; 95 96#define INTERNALLOG LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID 97 /* Check for invalid bits. */ 98 if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) { 99 syslog_r(INTERNALLOG, data, 100 "syslog%s: unknown facility/priority: %x", 101 gettime != NULL ? "" : "_r", pri); 102 pri &= LOG_PRIMASK|LOG_FACMASK; 103 } 104 105 /* Check priority against setlogmask values. */ 106 if (!(LOG_MASK(LOG_PRI(pri)) & data->log_mask)) 107 return; 108 109 saved_errno = errno; 110 111 /* Set default facility if none specified. */ 112 if ((pri & LOG_FACMASK) == 0) 113 pri |= data->log_fac; 114 115 p = tbuf; 116 tbuf_left = TBUF_LEN; 117 118#define DEC() \ 119 do { \ 120 if (prlen < 0) \ 121 prlen = 0; \ 122 if (prlen >= tbuf_left) \ 123 prlen = tbuf_left - 1; \ 124 p += prlen; \ 125 tbuf_left -= prlen; \ 126 } while (0) 127 128 prlen = snprintf(p, tbuf_left, "<%d>", pri); 129 DEC(); 130 if (data->log_stat & LOG_CONS) 131 conp = p; 132 133 /* 134 * syslogd will expand time automagically for reentrant case, and 135 * for normal case, invoke the callback to do it just do like before 136 */ 137 if (gettime != NULL) { 138 prlen = gettime(p, tbuf_left); 139 DEC(); 140 } 141 142 if (data->log_stat & LOG_PERROR) 143 stdp = p; 144 if (data->log_tag == NULL) 145 data->log_tag = __progname; 146 if (data->log_tag != NULL) { 147 prlen = snprintf(p, tbuf_left, "%s", data->log_tag); 148 DEC(); 149 } 150 if (data->log_stat & LOG_PID) { 151 prlen = snprintf(p, tbuf_left, "[%ld]", (long)getpid()); 152 DEC(); 153 } 154 if (data->log_tag != NULL) { 155 if (tbuf_left > 1) { 156 *p++ = ':'; 157 tbuf_left--; 158 } 159 if (tbuf_left > 1) { 160 *p++ = ' '; 161 tbuf_left--; 162 } 163 } 164 165 /* strerror() is not reentrant */ 166 167 for (t = fmt_cpy, fmt_left = FMT_LEN; (ch = *fmt); ++fmt) { 168 if (ch == '%' && fmt[1] == 'm') { 169 ++fmt; 170 if (gettime != NULL) { 171 prlen = snprintf(t, fmt_left, "%s", 172 strerror(saved_errno)); 173 } else { 174 prlen = snprintf(t, fmt_left, "Error %d", 175 saved_errno); 176 } 177 if (prlen < 0) 178 prlen = 0; 179 if (prlen >= fmt_left) 180 prlen = fmt_left - 1; 181 t += prlen; 182 fmt_left -= prlen; 183 } else if (ch == '%' && fmt[1] == '%' && fmt_left > 2) { 184 *t++ = '%'; 185 *t++ = '%'; 186 fmt++; 187 fmt_left -= 2; 188 } else { 189 if (fmt_left > 1) { 190 *t++ = ch; 191 fmt_left--; 192 } 193 } 194 } 195 *t = '\0'; 196 197 prlen = vsnprintf(p, tbuf_left, fmt_cpy, ap); 198 DEC(); 199 cnt = p - tbuf; 200 while (cnt > 0 && p[-1] == '\n') { 201 *(--p) = '\0'; 202 --cnt; 203 } 204 205 /* Output to stderr if requested. */ 206 if (data->log_stat & LOG_PERROR) { 207 struct iovec iov[2]; 208 209 iov[0].iov_base = stdp; 210 iov[0].iov_len = cnt > stdp - tbuf ? cnt - (stdp - tbuf) : 0; 211 iov[1].iov_base = "\n"; 212 iov[1].iov_len = 1; 213 (void)writev(STDERR_FILENO, iov, 2); 214 } 215 216 /* 217 * If the sendsyslog() fails, it means that syslogd 218 * is not running. 219 */ 220 error = sendsyslog(tbuf, cnt); 221 222 /* 223 * Output the message to the console; try not to block 224 * as a blocking console should not stop other processes. 225 * Make sure the error reported is the one from the syslogd failure. 226 */ 227 if (error == -1 && (data->log_stat & LOG_CONS) && 228 (fd = open(_PATH_CONSOLE, O_WRONLY|O_NONBLOCK, 0)) >= 0) { 229 struct iovec iov[2]; 230 231 iov[0].iov_base = conp; 232 iov[0].iov_len = cnt > conp - tbuf ? cnt - (conp - tbuf) : 0; 233 iov[1].iov_base = "\r\n"; 234 iov[1].iov_len = 2; 235 (void)writev(fd, iov, 2); 236 (void)close(fd); 237 } 238} 239 240void 241openlog_r(const char *ident, int logstat, int logfac, struct syslog_data *data) 242{ 243 if (ident != NULL) 244 data->log_tag = ident; 245 data->log_stat = logstat; 246 if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0) 247 data->log_fac = logfac; 248} 249 250void 251closelog_r(struct syslog_data *data) 252{ 253 data->log_tag = NULL; 254} 255 256