/*****************************************************************************
POPular -- A POP3 server and proxy for large mail systems
$Id: xlog.c,v 1.21 2001/05/17 20:17:23 sqrt Exp $
http://www.remote.org/jochen/mail/popular/
******************************************************************************
Copyright (C) 1999-2001 Jochen Topf <jochen@remote.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*****************************************************************************/
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include "popular.h"
static char xhostname[256];
static char xprgname[256];
static char xid[256];
/* in the beginning the file descriptor for logging is 2 for stdout */
static int xfd = 2;
/*****************************************************************************
xlog_writeln()
Internal function
This function is used by the logging function, it writes a line to the
logfile. Tabs, newlines and carriage returns are printed as space, non-
printable characters are printed as a dot (.). A single newline is
included at the end.
*****************************************************************************/
void
xlog_writeln(char *string)
{
char buf[strlen(string)*4+2];
unsigned char *s, *t;
/* no logging if there is no fd to log to */
if (xfd == -1) return;
for (s=string, t=buf; *s; s++, t++) {
if (*s == '\n') { *t++ = '\\'; *t = 'n'; }
else if (*s == '\r') { *t++ = '\\'; *t = 'r'; }
else if (*s == '\t') { *t++ = '\\'; *t = 't'; }
else if (*s == '\"') { *t++ = '\\'; *t = '\"'; }
else if (*s == '\\') { *t++ = '\\'; *t = '\\'; }
else if (isprint(*s)) { *t = *s; }
else {
*t++ = '\\';
*t++ = 'x';
snprintf(t++, 3, "%02x", (unsigned int) *s);
}
}
*t++ = '\n';
*t = '\0';
(void) rel_write(xfd, buf, strlen(buf));
}
/*****************************************************************************
xlog_print_level()
*****************************************************************************/
const char *
xlog_print_level(xlog_level_t level)
{
switch (level) {
case xlog_dbg: return("DBG");
case xlog_inf: return("INF");
case xlog_err: return("ERR");
case xlog_adm: return("ADM");
case xlog_sos: return("SOS");
case xlog_bug: return("BUG");
}
return("BUG");
}
/*****************************************************************************
xlog_printf()
Write some information to the logfile and exit. Long strings will be
truncated. ('...' is printed at the end to signal truncation.) The following
characters are printed like escpaed: \r, \n, \t, \\, \". Other nonprintable
characters are printedas hexadecimal: \xXX.
Log format:
<date> <time> <hostname> <prgname> <pid> <idstring> <level> <code> <text>
Date and time use the ISO format (yyyymmdd and hhmmss), the hostname is
printed without domain. The level can be one of: DEBUG, INFO, ERR, ADMIN,
SOS, BUG. The code is a 4 digit unique hex number.
*****************************************************************************/
void
xlog_printf(xlog_level_t level, int code, const char *format, ...)
{
char buf[MAXBUF * 2];
va_list args;
time_t now = time(NULL);
struct tm *t = localtime(&now);
int r, rr;
r = snprintf(buf, sizeof(buf), "%04d%02d%02d %02d%02d%02d %s %s %d %s %s %04x ",
t->tm_year+1900, t->tm_mon+1, t->tm_mday,
t->tm_hour, t->tm_min, t->tm_sec,
xhostname, xprgname, getpid(), xid, xlog_print_level(level), code);
if (r < 0 || r >= sizeof(buf)) {
buf[sizeof(buf)-2] = '.';
buf[sizeof(buf)-3] = '.';
buf[sizeof(buf)-4] = '.';
goto done;
}
va_start(args, format);
rr = vsnprintf(buf+r, sizeof(buf)-r, format, args);
va_end(args);
if (rr < 0 || rr >= sizeof(buf)-r) {
buf[sizeof(buf)-2] = '.';
buf[sizeof(buf)-3] = '.';
buf[sizeof(buf)-4] = '.';
}
done:
xlog_writeln(buf);
}
/*****************************************************************************
xlog_set_id()
Set ID for logging
*****************************************************************************/
void
xlog_set_id(const char *id)
{
(void) strlcpy(xid, id, sizeof(xid));
}
/*****************************************************************************
xlog_init()
Save program and host name for logging.
*****************************************************************************/
void
xlog_init(const char *prgname)
{
char *p;
/* set ID to "-", it is set later with xlog_set_id() to the right value */
xid[0] = '-';
xid[1] = '\0';
(void) strlcpy(xprgname, prgname, sizeof(xprgname));
/* Get hostname for logging and drop domain */
(void) gethostname(xhostname, sizeof(xhostname));
xhostname[sizeof(xhostname)-1] = '\0';
p = strchr(xhostname, '.');
if (p) *p = '\0';
}
/*****************************************************************************
xlog_open()
Save program and host name for logging and open logfile
*****************************************************************************/
int
xlog_open(const char *prgname, const char *logfilename, mode_t mode)
{
xlog_init(prgname);
/* Open logfile. Return code is not checked. If logging doesn't work
everything else is still usable. The caller might want to check this. */
xfd = open(logfilename, O_WRONLY | O_APPEND | O_CREAT, mode);
return xfd;
}
/*****************************************************************************
xlog_close()
Close log file if it was open.
*****************************************************************************/
void
xlog_close()
{
if (xfd != -1) {
(void) close(xfd);
xfd = -1;
}
}
/*****************************************************************************
xlog_reopen()
Reopen the log file. If opening the new file failed, the old file will
remain open.
*****************************************************************************/
int
xlog_reopen(const char *logfilename, mode_t mode)
{
int nfd;
/* XLOG-DOC:INF:000a:log_reopen
* The logfile will be reopened now. This should be the last message
* of the parent process of the server to the log file. (See 000c for
* the message in the new log file) */
xlog_printf(xlog_inf, 0x000a, "log_reopen");
/* Open logfile. Return code is not checked. If logging doesn't work
everything else is still usable. The caller might want to check this. */
nfd = open(logfilename, O_WRONLY | O_APPEND | O_CREAT, mode);
if (nfd < 0) {
/* XLOG-DOC:SOS:000b:log_reopen_failed
* Reopening of the log file failed for some reason. The old file will
* be kept open. */
xlog_printf(xlog_sos, 0x000b, "log_reopen_failed file='%s' errno=%d errmsg='%s'", logfilename, errno, strerror(errno));
return -1;
}
xlog_close();
xfd = nfd;
/* XLOG-DOC:INF:000c:log_reopened
* This is the first message in the reopened log file.
* (See also: 000a). */
xlog_printf(xlog_inf, 0x000c, "log_reopened");
return xfd;
}
/** THE END *****************************************************************/
syntax highlighted by Code2HTML, v. 0.9.1