11dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/*	$OpenBSD: syslog.c,v 1.28 2005/08/08 08:05:34 espie Exp $ */
21dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/*
31dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Copyright (c) 1983, 1988, 1993
41dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *	The Regents of the University of California.  All rights reserved.
51dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
61dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Redistribution and use in source and binary forms, with or without
71dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * modification, are permitted provided that the following conditions
81dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * are met:
91dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 1. Redistributions of source code must retain the above copyright
101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    notice, this list of conditions and the following disclaimer.
111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 2. Redistributions in binary form must reproduce the above copyright
121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    notice, this list of conditions and the following disclaimer in the
131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    documentation and/or other materials provided with the distribution.
141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 3. Neither the name of the University nor the names of its contributors
151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    may be used to endorse or promote products derived from this software
161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    without specific prior written permission.
171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * SUCH DAMAGE.
291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <sys/types.h>
321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <sys/socket.h>
331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <sys/uio.h>
341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <syslog.h>
351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <sys/un.h>
361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <netdb.h>
371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <errno.h>
391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <fcntl.h>
401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <paths.h>
411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <stdio.h>
421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <string.h>
431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <time.h>
441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <unistd.h>
451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <stdarg.h>
461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic struct syslog_data sdata = SYSLOG_DATA_INIT;
481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectextern char	*__progname;		/* Program name, from crt0. */
501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic void	disconnectlog_r(struct syslog_data *);	/* disconnect from syslogd */
521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic void	connectlog_r(struct syslog_data *);	/* (re)connect to syslogd */
531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/*
551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * syslog, vsyslog --
561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *	print message on log file; output is intended for syslogd(8).
571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectvoid
591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectsyslog(int pri, const char *fmt, ...)
601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	va_list ap;
621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	va_start(ap, fmt);
641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	vsyslog(pri, fmt, ap);
651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	va_end(ap);
661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectvoid
691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectvsyslog(int pri, const char *fmt, va_list ap)
701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	vsyslog_r(pri, &sdata, fmt, ap);
721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectvoid
751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectopenlog(const char *ident, int logstat, int logfac)
761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	openlog_r(ident, logstat, logfac, &sdata);
781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectvoid
811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectcloselog(void)
821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	closelog_r(&sdata);
841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* setlogmask -- set the log mask level */
871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint
881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectsetlogmask(int pmask)
891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	return setlogmask_r(pmask, &sdata);
911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* Reentrant version of syslog, i.e. syslog_r() */
941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectvoid
961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectsyslog_r(int pri, struct syslog_data *data, const char *fmt, ...)
971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	va_list ap;
991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	va_start(ap, fmt);
1011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	vsyslog_r(pri, data, fmt, ap);
1021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	va_end(ap);
1031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
1041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectvoid
1061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectvsyslog_r(int pri, struct syslog_data *data, const char *fmt, va_list ap)
1071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
1081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	int cnt;
1091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	char ch, *p, *t;
1101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	time_t now;
1111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	int fd, saved_errno, error;
1121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define	TBUF_LEN	2048
1131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define	FMT_LEN		1024
1141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	char *stdp = NULL, tbuf[TBUF_LEN], fmt_cpy[FMT_LEN];
1151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	int tbuf_left, fmt_left, prlen;
1161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define	INTERNALLOG	LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID
1181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	/* Check for invalid bits. */
1191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) {
1201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		if (data == &sdata) {
1211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			syslog(INTERNALLOG,
1221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			    "syslog: unknown facility/priority: %x", pri);
1231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		} else {
1241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			syslog_r(INTERNALLOG, data,
1251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			    "syslog_r: unknown facility/priority: %x", pri);
1261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		}
1271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		pri &= LOG_PRIMASK|LOG_FACMASK;
1281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	}
1291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	/* Check priority against setlogmask values. */
1311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if (!(LOG_MASK(LOG_PRI(pri)) & data->log_mask))
1321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		return;
1331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	saved_errno = errno;
1351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	/* Set default facility if none specified. */
1371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if ((pri & LOG_FACMASK) == 0)
1381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		pri |= data->log_fac;
1391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	/* If we have been called through syslog(), no need for reentrancy. */
1411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if (data == &sdata)
1421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		(void)time(&now);
1431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	p = tbuf;
1451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	tbuf_left = TBUF_LEN;
1461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define	DEC()	\
1481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	do {					\
1491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		if (prlen < 0)			\
1501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			prlen = 0;		\
1511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		if (prlen >= tbuf_left)		\
1521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			prlen = tbuf_left - 1;	\
1531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		p += prlen;			\
1541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		tbuf_left -= prlen;		\
1551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	} while (0)
1561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	prlen = snprintf(p, tbuf_left, "<%d>", pri);
1581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	DEC();
1591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	/*
1611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 * syslogd will expand time automagically for reentrant case, and
1621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 * for normal case, just do like before
1631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 */
1641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if (data == &sdata) {
1651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		prlen = strftime(p, tbuf_left, "%h %e %T ", localtime(&now));
1661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		DEC();
1671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	}
1681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if (data->log_stat & LOG_PERROR)
1701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		stdp = p;
1711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if (data->log_tag == NULL)
1721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		data->log_tag = __progname;
1731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if (data->log_tag != NULL) {
1741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		prlen = snprintf(p, tbuf_left, "%s", data->log_tag);
1751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		DEC();
1761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	}
1771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if (data->log_stat & LOG_PID) {
1781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		prlen = snprintf(p, tbuf_left, "[%ld]", (long)getpid());
1791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		DEC();
1801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	}
1811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if (data->log_tag != NULL) {
1821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		if (tbuf_left > 1) {
1831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			*p++ = ':';
1841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			tbuf_left--;
1851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		}
1861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		if (tbuf_left > 1) {
1871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			*p++ = ' ';
1881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			tbuf_left--;
1891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		}
1901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	}
1911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	/* strerror() is not reentrant */
1931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	for (t = fmt_cpy, fmt_left = FMT_LEN; (ch = *fmt); ++fmt) {
1951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		if (ch == '%' && fmt[1] == 'm') {
1961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			++fmt;
1971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			if (data == &sdata) {
1981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project				prlen = snprintf(t, fmt_left, "%s",
1991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project				    strerror(saved_errno));
2001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			} else {
2011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project				prlen = snprintf(t, fmt_left, "Error %d",
2021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project				    saved_errno);
2031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			}
2041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			if (prlen < 0)
2051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project				prlen = 0;
2061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			if (prlen >= fmt_left)
2071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project				prlen = fmt_left - 1;
2081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			t += prlen;
2091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			fmt_left -= prlen;
2101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		} else if (ch == '%' && fmt[1] == '%' && fmt_left > 2) {
2111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			*t++ = '%';
2121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			*t++ = '%';
2131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			fmt++;
2141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			fmt_left -= 2;
2151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		} else {
2161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			if (fmt_left > 1) {
2171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project				*t++ = ch;
2181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project				fmt_left--;
2191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			}
2201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		}
2211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	}
2221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	*t = '\0';
2231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	prlen = vsnprintf(p, tbuf_left, fmt_cpy, ap);
2251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	DEC();
2261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	cnt = p - tbuf;
2271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	/* Output to stderr if requested. */
2291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if (data->log_stat & LOG_PERROR) {
2301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		struct iovec iov[2];
2311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		iov[0].iov_base = stdp;
2331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		iov[0].iov_len = cnt - (stdp - tbuf);
2341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		iov[1].iov_base = "\n";
2351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		iov[1].iov_len = 1;
2361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		(void)writev(STDERR_FILENO, iov, 2);
2371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	}
2381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	/* Get connected, output the message to the local logger. */
2401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if (!data->opened)
2411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		openlog_r(data->log_tag, data->log_stat, 0, data);
2421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	connectlog_r(data);
2431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	/*
2451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 * If the send() failed, there are two likely scenarios:
2461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 *  1) syslogd was restarted
2471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 *  2) /dev/log is out of socket buffer space
2481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 * We attempt to reconnect to /dev/log to take care of
2491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 * case #1 and keep send()ing data to cover case #2
2501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 * to give syslogd a chance to empty its socket buffer.
2511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 */
2521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if ((error = send(data->log_file, tbuf, cnt, 0)) < 0) {
2531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		if (errno != ENOBUFS) {
2541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			disconnectlog_r(data);
2551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			connectlog_r(data);
2561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		}
2571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		do {
2581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			usleep(1);
2591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			if ((error = send(data->log_file, tbuf, cnt, 0)) >= 0)
2601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project				break;
2611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		} while (errno == ENOBUFS);
2621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	}
2631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	/*
2651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 * Output the message to the console; try not to block
2661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 * as a blocking console should not stop other processes.
2671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 * Make sure the error reported is the one from the syslogd failure.
2681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 */
2691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if (error == -1 && (data->log_stat & LOG_CONS) &&
2701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	    (fd = open(_PATH_CONSOLE, O_WRONLY|O_NONBLOCK, 0)) >= 0) {
2711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		struct iovec iov[2];
2721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		p = strchr(tbuf, '>') + 1;
2741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		iov[0].iov_base = p;
2751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		iov[0].iov_len = cnt - (p - tbuf);
2761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		iov[1].iov_base = "\r\n";
2771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		iov[1].iov_len = 2;
2781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		(void)writev(fd, iov, 2);
2791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		(void)close(fd);
2801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	}
2811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if (data != &sdata)
2831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		closelog_r(data);
2841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
2851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
2861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic void
2871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectdisconnectlog_r(struct syslog_data *data)
2881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
2891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	/*
2901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 * If the user closed the FD and opened another in the same slot,
2911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 * that's their problem.  They should close it before calling on
2921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 * system services.
2931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 */
2941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if (data->log_file != -1) {
2951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		close(data->log_file);
2961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		data->log_file = -1;
2971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	}
2981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	data->connected = 0;		/* retry connect */
2991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
3001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic void
3021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectconnectlog_r(struct syslog_data *data)
3031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
3041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    union {
3051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        struct sockaddr     syslogAddr;
3061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project        struct sockaddr_un  syslogAddrUn;
3071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    } u;
3081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define SyslogAddr   u.syslogAddrUn
3101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if (data->log_file == -1) {
3121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		if ((data->log_file = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1)
3131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			return;
3141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		(void)fcntl(data->log_file, F_SETFD, 1);
3151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	}
3161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if (data->log_file != -1 && !data->connected) {
3171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		memset(&SyslogAddr, '\0', sizeof(SyslogAddr));
3181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#if 0
3191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project                /* BIONIC: no sun_len field to fill on Linux */
3201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		SyslogAddr.sun_len = sizeof(SyslogAddr);
3211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#endif
3221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		SyslogAddr.sun_family = AF_UNIX;
3231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		strlcpy(SyslogAddr.sun_path, _PATH_LOG,
3241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		    sizeof(SyslogAddr.sun_path));
3251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		if (connect(data->log_file, &u.syslogAddr,
3261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		    sizeof(SyslogAddr)) == -1) {
3271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			(void)close(data->log_file);
3281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			data->log_file = -1;
3291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		} else
3301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			data->connected = 1;
3311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	}
3321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
3331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectvoid
3351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectopenlog_r(const char *ident, int logstat, int logfac, struct syslog_data *data)
3361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
3371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if (ident != NULL)
3381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		data->log_tag = ident;
3391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	data->log_stat = logstat;
3401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0)
3411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		data->log_fac = logfac;
3421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if (data->log_stat & LOG_NDELAY)	/* open immediately */
3441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		connectlog_r(data);
3451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	data->opened = 1;	/* ident and facility has been set */
3471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
3481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectvoid
3501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectcloselog_r(struct syslog_data *data)
3511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
3521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	(void)close(data->log_file);
3531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	data->log_file = -1;
3541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	data->connected = 0;
3551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	data->log_tag = NULL;
3561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
3571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* setlogmask -- set the log mask level */
3591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectint
3601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectsetlogmask_r(int pmask, struct syslog_data *data)
3611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
3621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	int omask;
3631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
3641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	omask = data->log_mask;
3651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if (pmask != 0)
3661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		data->log_mask = pmask;
3671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	return (omask);
3681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
369