1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361
|
/*
* Copyright (c) 1983, 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
*/
/*
* SYSLOG -- print message on log file
*
* This routine looks a lot like printf, except that it outputs to the
* log file instead of the standard output. Also:
* adds a timestamp,
* prints the module name in front of the message,
* has some other formatting types (or will sometime),
* adds a newline on the end of the message.
*
* The output of this routine is intended to be read by syslogd(8).
*
* Author: Eric Allman
* Modified to use UNIX domain IPC by Ralph Campbell
* Patched March 12, 1996 by A. Ian Vogelesang <vogelesang@hdshq.com>
* - to correct the handling of message & format string truncation,
* - to visibly tag truncated records to facilitate
* investigation of such Bad Things with grep, and,
* - to correct the handling of case where "write"
* returns after writing only part of the message.
* Rewritten by Martin Mares <mj@atrey.karlin.mff.cuni.cz> on May 14, 1997
* - better buffer overrun checks.
* - special handling of "%m" removed as we use GNU sprintf which handles
* it automatically.
* - Major code cleanup.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/file.h>
#include <sys/signal.h>
#include <sys/syslog.h>
#include <sys/uio.h>
#include <sys/wait.h>
#include <netdb.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <errno.h>
#include <stdarg.h>
#include <paths.h>
#include <stdio.h>
#include <ctype.h>
#include <signal.h>
#include <bits/uClibc_mutex.h>
__UCLIBC_MUTEX_STATIC(mylock, PTHREAD_MUTEX_INITIALIZER);
/* !glibc_compat: glibc uses argv[0] by default
* (default: if there was no openlog or if openlog passed NULL),
* not string "syslog"
*/
static const char *LogTag = "syslog"; /* string to tag the entry with */
static int LogFile = -1; /* fd for log */
static smalluint connected; /* have done connect */
/* all bits in option argument for openlog fit in 8 bits */
static smalluint LogStat = 0; /* status bits, set by openlog */
/* default facility code if openlog is not called */
/* (this fits in 8 bits even without >> 3 shift, but playing extra safe) */
static smalluint LogFacility = LOG_USER >> 3;
/* bits mask of priorities to be logged (eight prios - 8 bits is enough) */
static smalluint LogMask = 0xff;
/* AF_UNIX address of local logger (we use struct sockaddr
* instead of struct sockaddr_un since "/dev/log" is small enough) */
static const struct sockaddr SyslogAddr = {
.sa_family = AF_UNIX, /* sa_family_t (usually a short) */
.sa_data = _PATH_LOG /* char [14] */
};
static void
closelog_intern(int sig)
{
/* mylock must be held by the caller */
if (LogFile != -1) {
(void) close(LogFile);
}
LogFile = -1;
connected = 0;
if (sig == 0) { /* called from closelog()? - reset to defaults */
LogStat = 0;
LogTag = "syslog";
LogFacility = LOG_USER >> 3;
LogMask = 0xff;
}
}
static void
openlog_intern(void)
{
int fd;
int logType = SOCK_DGRAM;
static const struct timeval tv = { 1, 0 };
fd = LogFile;
if (fd == -1) {
retry:
if (1) { /* if statement left in to make .diff cleaner */
LogFile = fd = socket(AF_UNIX, logType, 0);
if (fd == -1) {
return;
}
fcntl(fd, F_SETFD, FD_CLOEXEC);
/* We don't want to block if e.g. syslogd is SIGSTOPed */
fcntl(fd, F_SETFL, O_NONBLOCK | fcntl(fd, F_GETFL));
}
}
if (fd != -1 && !connected) {
if (connect(fd, &SyslogAddr, sizeof(SyslogAddr)) != -1) {
/* We want to block send if e.g. syslogd is SIGSTOPed */
fcntl(fd, F_SETFL, ~O_NONBLOCK & fcntl(fd, F_GETFL));
setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
connected = 1;
} else {
if (fd != -1) {
close(fd);
LogFile = fd = -1;
}
if (logType == SOCK_DGRAM) {
logType = SOCK_STREAM;
goto retry;
}
}
}
}
/*
* OPENLOG -- open system log
*/
void
openlog(const char *ident, int logstat, int logfac)
{
__UCLIBC_MUTEX_LOCK(mylock);
if (ident != NULL)
LogTag = ident;
LogStat = logstat;
/* (we were checking also for logfac != 0, but it breaks
* openlog(xx, LOG_KERN) since LOG_KERN == 0) */
if ((logfac & ~LOG_FACMASK) == 0) /* if we don't have invalid bits */
LogFacility = (unsigned)logfac >> 3;
if (logstat & LOG_NDELAY)
openlog_intern();
__UCLIBC_MUTEX_UNLOCK(mylock);
}
/*
* syslog, vsyslog --
* print message on log file; output is intended for syslogd(8).
*/
static
#ifndef __USE_BSD
__always_inline
#endif
void
__vsyslog(int pri, const char *fmt, va_list ap)
{
register char *p;
char *last_chr, *head_end, *end, *stdp;
time_t now;
int fd, saved_errno;
int rc;
char tbuf[1024]; /* syslogd is unable to handle longer messages */
/* Just throw out this message if pri has bad bits. */
if ((pri & ~(LOG_PRIMASK|LOG_FACMASK)) != 0)
return;
saved_errno = errno;
__UCLIBC_MUTEX_LOCK(mylock);
/* See if we should just throw out this message according to LogMask. */
if ((LogMask & LOG_MASK(LOG_PRI(pri))) == 0)
goto getout;
if (LogFile < 0 || !connected)
openlog_intern();
/* Set default facility if none specified. */
if ((pri & LOG_FACMASK) == 0)
pri |= ((int)LogFacility << 3);
/* Build the message. We know the starting part of the message can take
* no longer than 64 characters plus length of the LogTag. So it's
* safe to test only LogTag and use normal sprintf everywhere else.
*/
(void)time(&now);
stdp = p = tbuf + sprintf(tbuf, "<%d>%.15s ", pri, ctime(&now) + 4);
/*if (LogTag) - always true */ {
if (strlen(LogTag) < sizeof(tbuf) - 64)
p += sprintf(p, "%s", LogTag);
else
p += sprintf(p, "<BUFFER OVERRUN ATTEMPT>");
}
if (LogStat & LOG_PID)
p += sprintf(p, "[%d]", getpid());
/*if (LogTag) - always true */ {
*p++ = ':';
*p++ = ' ';
}
head_end = p;
/* We format the rest of the message. If the buffer becomes full, we mark
* the message as truncated. Note that we require at least 2 free bytes
* in the buffer as we might want to add "\r\n" there.
*/
end = tbuf + sizeof(tbuf) - 1;
__set_errno(saved_errno);
p += vsnprintf(p, end - p, fmt, ap);
if (p >= end || p < head_end) { /* Returned -1 in case of error... */
static const char truncate_msg[12] = "[truncated] "; /* no NUL! */
memmove(head_end + sizeof(truncate_msg), head_end,
end - head_end - sizeof(truncate_msg));
memcpy(head_end, truncate_msg, sizeof(truncate_msg));
if (p < head_end) {
while (p < end && *p) {
p++;
}
}
else {
p = end - 1;
}
}
last_chr = p;
/* Output to stderr if requested. */
if (LogStat & LOG_PERROR) {
*last_chr = '\n';
(void)write(STDERR_FILENO, stdp, last_chr - stdp + 1);
}
/* Output the message to the local logger using NUL as a message delimiter. */
p = tbuf;
*last_chr = '\0';
retry:
if (LogFile >= 0) {
do {
/* can't just use write, it can result in SIGPIPE */
rc = send(LogFile, p, last_chr + 1 - p, MSG_NOSIGNAL);
if (rc < 0) {
switch (errno) {
case EINTR:
break;
case ECONNRESET:
/* syslogd restarted, reopen log */
closelog_intern(1);
openlog_intern();
goto retry;
case EAGAIN:
/* syslogd stalled, noting we can do */
default:
closelog_intern(1); /* 1: do not reset LogXXX globals to default */
goto write_err;
}
rc = 0;
}
p += rc;
} while (p <= last_chr);
goto getout;
}
write_err:
/*
* Output the message to the console; don't worry about blocking,
* if console blocks everything will. Make sure the error reported
* is the one from the syslogd failure.
*/
/* should mode be O_WRONLY | O_NOCTTY? -- Uli */
/* yes, but in Linux "/dev/console" never becomes ctty anyway -- vda */
if ((LogStat & LOG_CONS) &&
(fd = open(_PATH_CONSOLE, O_WRONLY | O_NOCTTY)) >= 0) {
p = strchr(tbuf, '>') + 1;
last_chr[0] = '\r';
last_chr[1] = '\n';
(void)write(fd, p, last_chr - p + 2);
(void)close(fd);
}
getout:
__UCLIBC_MUTEX_UNLOCK(mylock);
}
#ifdef __USE_BSD
strong_alias(__vsyslog,vsyslog)
#endif
void
syslog(int pri, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
__vsyslog(pri, fmt, ap);
va_end(ap);
}
libc_hidden_def(syslog)
/*
* CLOSELOG -- close the system log
*/
void
closelog(void)
{
__UCLIBC_MUTEX_LOCK(mylock);
closelog_intern(0); /* 0: reset LogXXX globals to default */
__UCLIBC_MUTEX_UNLOCK(mylock);
}
/* setlogmask -- set the log mask level */
int setlogmask(int pmask)
{
int omask;
omask = LogMask;
if (pmask != 0) {
/* __UCLIBC_MUTEX_LOCK(mylock);*/
LogMask = pmask;
/* __UCLIBC_MUTEX_UNLOCK(mylock);*/
}
return omask;
}
|