view dcclib/error_msg.c @ 0:c7f6b056b673

First import of vendor version
author Peter Gervai <grin@grin.hu>
date Tue, 10 Mar 2009 13:49:58 +0100
parents
children
line wrap: on
line source

/* Distributed Checksum Clearinghouse
 *
 * Copyright (c) 2008 by Rhyolite Software, LLC
 *
 * This agreement is not applicable to any entity which sells anti-spam
 * solutions to others or provides an anti-spam solution as part of a
 * security solution sold to other entities, or to a private network
 * which employs the DCC or uses data provided by operation of the DCC
 * but does not provide corresponding data to other users.
 *
 * Permission to use, copy, modify, and distribute this software without
 * changes for any purpose with or without fee is hereby granted, provided
 * that the above copyright notice and this permission notice appear in all
 * copies and any distributed versions or copies are either unchanged
 * or not called anything similar to "DCC" or "Distributed Checksum
 * Clearinghouse".
 *
 * Parties not eligible to receive a license under this agreement can
 * obtain a commercial license to use DCC by contacting Rhyolite Software
 * at sales@rhyolite.com.
 *
 * A commercial license would be for Distributed Checksum and Reputation
 * Clearinghouse software.  That software includes additional features.  This
 * free license for Distributed ChecksumClearinghouse Software does not in any
 * way grant permision to use Distributed Checksum and Reputation Clearinghouse
 * software
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND RHYOLITE SOFTWARE, LLC DISCLAIMS ALL
 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL RHYOLITE SOFTWARE, LLC
 * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 *
 * Rhyolite Software DCC 1.3.103-1.53 $Revision$
 */

#include "dcc_defs.h"
#include "dcc_paths.h"
#ifndef DCC_WIN32
#include <syslog.h>
#endif

extern void dcc_syslog_lock(void);
extern void dcc_syslog_unlock(void);

u_char trace_quiet;

u_char dcc_no_syslog;

int dcc_error_priority = LOG_ERR | LOG_MAIL;
int dcc_trace_priority = LOG_NOTICE | LOG_MAIL;


/* commonly used, but not thread safe */
int dcc_ex_code = EX_UNAVAILABLE;


DCC_PATH dcc_progname;
int dcc_progname_len;

#ifdef HAVE___PROGNAME
extern const char *__progname;
#endif


static void
clean_stdfd(int stdfd)
{
	struct stat sb;
	int fd;

	if (0 > fstat(stdfd, &sb) && errno == EBADF) {
		fd = open(_PATH_DEVNULL, 0, O_RDWR);
		if (fd < 0)		/* ignore errors we can't help */
			return;
		if (fd != stdfd) {
			dup2(fd, stdfd);
			close(fd);
		}
	}
}



/* prevent surprises from uses of stdio FDs by ensuring that the FDs are open */
void
clean_stdio(void)
{
	clean_stdfd(STDIN_FILENO);
	clean_stdfd(STDOUT_FILENO);
	clean_stdfd(STDERR_FILENO);
}



void
dcc_syslog_init(u_char use_syslog,
		const char *argv0 UATTRIB, const char *suffix)
{
	const char *p;

	/* Solaris defaults to "syslog" with a null identification string,
	 * but does not seem to have __progname set by crt0. */
#undef GOT_PROGNAME
#ifdef HAVE_GETPROGNAME
	p = getprogname();
#	define GOT_PROGNAME
#endif
#if defined(HAVE___PROGNAME) && !defined(GOT_PROGNAME)
	p = __progname;
#	define GOT_PROGNAME
#endif
#ifndef GOT_PROGNAME
	p = strrchr(argv0, '/');
#ifdef DCC_WIN32
	if (!p)
		p = strrchr(argv0, '\\');
#endif
	if (!p)
		p = argv0;
	else
		++p;
#ifdef DCC_WIN32
	/* strip ".exe" from Windows progam name */
	dcc_progname_len = strlen(p);
	if (dcc_progname_len > LITZ(".exe")
	    && !CLITCMP(&p[dcc_progname_len-LITZ(".exe")], ".exe")) {
		char *p1 = strdup(p);
		p1[dcc_progname_len-LITZ(".exe")] = '\0';
		p = p1;
	}
#endif /* DCC_WIN32 */
#endif /* !GOT_PROGNAME */
	snprintf(dcc_progname, sizeof(dcc_progname), "%s%s",
		 p, suffix ? suffix : "");
	dcc_progname_len = strlen(dcc_progname);

	/* ensure that stdout and stderr exist so that when we open
	 * database or other files, we don't get file descriptor 1 or 2
	 * and then later write error messages to them. */
	clean_stdio();

#ifdef DCC_WIN32
	dcc_no_syslog = 1;
#else
	/* Don't wait for the console if somehow we must use it,
	 * because that messes up dccm. */
#ifndef LOG_NOWAIT
#define LOG_NOWAIT 0
#endif
	openlog(dcc_progname, LOG_PID | LOG_NOWAIT, LOG_MAIL);
	if (!use_syslog)
		dcc_no_syslog = 1;
#endif /* DCC_WIN32 */
}



void
dcc_vfatal_msg(const char *p, va_list args)
{
	char logbuf[LOGBUF_SIZE];
	int i;

	/* write the message with the "fatal error" addition as
	 * a single message to syslog */
	i = vsnprintf(logbuf, sizeof(logbuf), p, args);
	if (i >= ISZ(logbuf))
		strcpy(&logbuf[ISZ(logbuf)-sizeof("...")], "...");

	fflush(stdout);			/* keep stderr and stdout straight */
	fprintf(stderr, "%s; fatal error\n", logbuf);
	fflush(stderr);

	if (dcc_no_syslog)
		return;

	dcc_syslog_lock();
	syslog(dcc_error_priority, "%s; fatal error", logbuf);
	closelog();
	dcc_syslog_unlock();
}



int
dcc_verror_msg(const char *p, va_list args)
{
	char logbuf[LOGBUF_SIZE];
	int i;

	i = vsnprintf(logbuf, sizeof(logbuf), p, args);
	if (i >= ISZ(logbuf)) {
		strcpy(&logbuf[ISZ(logbuf)-sizeof("...")], "...");
		i = ISZ(logbuf)-1;
	} else if (i == 0) {
		i = snprintf(logbuf, sizeof(logbuf), "(empty error message)");
	}

	fflush(stdout);			/* keep stderr and stdout straight */
	fwrite(logbuf, i, 1, stderr);
	if (logbuf[i-1] != '\n') {
		fwrite("\n", 1, 1, stderr);
		++i;
	}

	if (!dcc_no_syslog) {
		dcc_syslog_lock();
		syslog(dcc_error_priority, "%s", logbuf);
		dcc_syslog_unlock();
	}

	return i;
}



void PATTRIB(1,2)
dcc_error_msg(const char *p, ...)
{
	va_list args;

	va_start(args, p);
	dcc_verror_msg(p, args);
	va_end(args);
}



void
dcc_vtrace_msg(const char *p, va_list args)
{
	char logbuf[LOGBUF_SIZE];
	int i;

	/* Some systems including Linux with gcc 3.4.2 on AMD 64 processors
	 * do not allow two uses of a va_list but requires va_copy()
	 * Other systems do not have any notion of va_copy(). */
	i = vsnprintf(logbuf, sizeof(logbuf), p, args);
	if (i >= ISZ(logbuf))
		strcpy(&logbuf[ISZ(logbuf)-sizeof("...")], "...");

	fflush(stdout);			/* keep stderr and stdout straight */
	fprintf(stderr, "%s\n", logbuf);

	if (!dcc_no_syslog) {
		dcc_syslog_lock();
		syslog(dcc_trace_priority, "%s", logbuf);
		dcc_syslog_unlock();
	}
}



void PATTRIB(1,2)
dcc_trace_msg(const char *p, ...)
{
	va_list args;

	va_start(args, p);
	dcc_vtrace_msg(p, args);
	va_end(args);
}



/* send only to system log if being quiet */
void PATTRIB(1,2)
quiet_trace_msg(const char *p, ...)
{
	va_list args;

	va_start(args, p);
	if (trace_quiet) {
		vsyslog(dcc_trace_priority, p, args);
	} else {
		dcc_vtrace_msg(p, args);
	}
	va_end(args);
}



void
dcc_vpemsg(int ex_code, DCC_EMSG emsg, const char *msg, va_list args)
{
	if (!emsg) {
		dcc_verror_msg(msg, args);
	} else {
		dcc_ex_code = ex_code;
		vsnprintf(emsg, sizeof(DCC_EMSG), msg, args);
	}
}



void PATTRIB(3,4)
dcc_pemsg(int ex_code, DCC_EMSG emsg, const char *msg, ...)
{
	va_list args;

	va_start(args, msg);
	dcc_vpemsg(ex_code, emsg, msg, args);
	va_end(args);
}



const char *
fnm_lno(DCC_FNM_LNO_BUF *buf, const char *fnm, int lno)
{
	DCC_PATH tmp;

	if (!fnm || *fnm == '\0') {
		buf->b[0] = '\0';
	} else {
		fnm2abs(tmp, fnm, "");
		snprintf(buf->b, sizeof(buf->b), DCC_FNM_LNO_PAT, lno, tmp);
	}
	return buf->b;
}



int
dcc_vearly_log(EARLY_LOG *el, const char *p, va_list args)
{
#	define ELIPS_STR "...\n"
	int max_len, len;

	max_len = sizeof(el->buf) - el->len;
	if (max_len <= 0)
		return 0;

	len = vsnprintf(&el->buf[el->len], max_len, p, args);
	if (len < max_len) {
		el->len += len;
		return len;
	} else {
		memcpy(&el->buf[sizeof(el->buf)-LITZ(ELIPS_STR)],
		       ELIPS_STR, LITZ(ELIPS_STR));
		el->len = sizeof(el->buf);
		return max_len;
	}

#undef ELIPS_STR
}



const char *
optopt2str(int i)
{
	static char b[] = "-x";

	b[1] = i;
	return b;
}