#include "uucp.h"
#if USE_RCS_ID
const char log_rcsid[] = "$Id: log.c,v 1.65 2002/03/05 19:10:41 ian Rel $";
#endif
#include <ctype.h>
#include <errno.h>
#if HAVE_STDARG_H
#include <stdarg.h>
#endif
#if TM_IN_SYS_TIME
#include <sys/time.h>
#else
#include <time.h>
#endif
#include "uudefs.h"
#include "uuconf.h"
#include "system.h"
__inline__ static char *zstpcpy P((char *zto, const char *zfrom));
static const char *zldate_and_time P((void));
const char *zProgram;
static const char *zLogfile;
static void (*pfLfatal) P((void));
static boolean fLfile;
static int iLid;
static char *zLuser;
static char *zLsystem;
char *zLdevice;
static FILE *eLlog;
static boolean fLlog_tried;
#if DEBUG > 1
static const char *zLdebugfile;
static FILE *eLdebug;
static boolean fLdebug_tried;
#endif
static const char *zLstatsfile;
static FILE *eLstats;
static boolean fLstats_tried;
volatile sig_atomic_t afSignal[INDEXSIG_COUNT];
volatile sig_atomic_t afLog_signal[INDEXSIG_COUNT];
boolean fLog_sighup = TRUE;
static const char * const azSignal_names[INDEXSIG_COUNT] = INDEXSIG_NAMES;
void (*pfLstart) P((void));
void (*pfLend) P((void));
void
ulog_fatal_fn (pfn)
void (*pfn) P((void));
{
pfLfatal = pfn;
}
void
ulog_to_file (puuconf, ffile)
pointer puuconf;
boolean ffile;
{
int iuuconf;
iuuconf = uuconf_logfile (puuconf, &zLogfile);
if (iuuconf != UUCONF_SUCCESS)
ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
#if DEBUG > 1
iuuconf = uuconf_debugfile (puuconf, &zLdebugfile);
if (iuuconf != UUCONF_SUCCESS)
ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
#endif
iuuconf = uuconf_statsfile (puuconf, &zLstatsfile);
if (iuuconf != UUCONF_SUCCESS)
ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
fLfile = ffile;
}
void
ulog_id (i)
int i;
{
iLid = i;
}
void
ulog_user (zuser)
const char *zuser;
{
ubuffree (zLuser);
zLuser = zbufcpy (zuser);
}
void
ulog_system (zsystem)
const char *zsystem;
{
if (zsystem == NULL
|| zLsystem == NULL
|| strcmp (zsystem, zLsystem) != 0)
{
ubuffree (zLsystem);
zLsystem = zbufcpy (zsystem);
#if HAVE_HDB_LOGGING
ulog_close ();
#endif
}
}
void
ulog_device (zdevice)
const char *zdevice;
{
ubuffree (zLdevice);
zLdevice = zbufcpy (zdevice);
}
__inline__ static char *
zstpcpy (zto, zfrom)
char *zto;
const char *zfrom;
{
while ((*zto++ = *zfrom++) != '\0')
;
return zto - 1;
}
#if ! HAVE_PROTOTYPES || ! HAVE_STDARG_H
#undef HAVE_VFPRINTF
#define HAVE_VFPRINTF 0
#endif
#if HAVE_VFPRINTF
void
ulog (enum tlog ttype, const char *zmsg, ...)
#else
void
ulog (ttype, zmsg, a, b, c, d, f, g, h, i, j)
enum tlog ttype;
const char *zmsg;
#endif
{
#if HAVE_VFPRINTF
va_list parg;
#endif
FILE *e, *edebug;
boolean fstart, fend;
const char *zhdr;
char *zprefix;
register char *zset;
char *zformat;
char *zfrom;
{
static boolean fdoing_sigs;
if (! fdoing_sigs)
{
int isig;
fdoing_sigs = TRUE;
for (isig = 0; isig < INDEXSIG_COUNT; isig++)
{
if (afLog_signal[isig])
{
afLog_signal[isig] = FALSE;
if ((isig != INDEXSIG_SIGHUP && isig != INDEXSIG_SIGINT)
|| fLog_sighup)
ulog (LOG_ERROR, "Got %s signal", azSignal_names[isig]);
}
}
fdoing_sigs = FALSE;
}
}
#if DEBUG > 1
if (fLfile
&& eLdebug == NULL
&& ! fLdebug_tried
&& iDebug != 0)
{
fLdebug_tried = TRUE;
eLdebug = esysdep_fopen (zLdebugfile, FALSE, TRUE, TRUE);
}
#endif
if (! fLfile)
e = stderr;
#if DEBUG > 1
else if ((int) ttype >= (int) LOG_DEBUG)
{
e = eLdebug;
if (e == NULL)
return;
}
#endif
else
{
if (eLlog == NULL && ! fLlog_tried)
{
const char *zprint = NULL;
fLlog_tried = TRUE;
#if ! HAVE_HDB_LOGGING
eLlog = esysdep_fopen (zLogfile, TRUE, TRUE, TRUE);
zprint = zLogfile;
#else
{
const char *zcheck;
int cfmt;
char *zfile;
cfmt = 0;
for (zcheck = zLogfile; *zcheck != '\0'; ++zcheck)
{
if (*zcheck == '%')
{
if (zcheck[1] == 's')
++cfmt;
else
{
cfmt = 3;
break;
}
}
}
if (cfmt > 2)
zfile = zbufcpy (zLogfile);
else
{
const char *zsys;
char *zbase;
char *zlower;
if (zLsystem == NULL)
zsys = "ANY";
else
zsys = zLsystem;
zbase = zsysdep_base_name (zProgram);
if (zbase == NULL)
zbase = zbufcpy (zProgram);
for (zlower = zbase; *zlower != '\0'; zlower++)
if (isupper (*zlower))
*zlower = tolower (*zlower);
zfile = zbufalc (strlen (zLogfile)
+ strlen (zbase)
+ strlen (zsys)
+ 1);
sprintf (zfile, zLogfile, zbase, zsys);
ubuffree (zbase);
}
eLlog = esysdep_fopen (zfile, TRUE, TRUE, TRUE);
if (eLlog != NULL)
ubuffree (zfile);
else
zprint = zfile;
}
#endif
if (eLlog == NULL)
{
fprintf (stderr, "%s: %s: can not open log file: %s\n",
zProgram, zprint, strerror (errno));
if (pfLfatal != NULL)
(*pfLfatal) ();
usysdep_exit (FALSE);
}
}
e = eLlog;
if (e == NULL)
return;
}
if (zmsg == NULL)
return;
if (pfLstart != NULL)
(*pfLstart) ();
edebug = NULL;
#if DEBUG > 1
if ((int) ttype < (int) LOG_DEBUG)
edebug = eLdebug;
#endif
fstart = TRUE;
fend = TRUE;
switch (ttype)
{
case LOG_NORMAL:
zhdr = "";
break;
case LOG_ERROR:
zhdr = "ERROR: ";
break;
case LOG_FATAL:
zhdr = "FATAL: ";
break;
#if DEBUG > 1
case LOG_DEBUG:
zhdr = "DEBUG: ";
break;
case LOG_DEBUG_START:
zhdr = "DEBUG: ";
fend = FALSE;
break;
case LOG_DEBUG_CONTINUE:
zhdr = NULL;
fstart = FALSE;
fend = FALSE;
break;
case LOG_DEBUG_END:
zhdr = NULL;
fstart = FALSE;
break;
#endif
default:
zhdr = "???: ";
break;
}
if (! fstart)
zprefix = zbufcpy ("");
else
{
if (! fLfile)
{
zprefix = zbufalc (strlen (zProgram) + 3);
sprintf (zprefix, "%s: ", zProgram);
}
else
{
zprefix = zbufalc (strlen (zProgram)
+ (zLsystem == NULL ? 1 : strlen (zLsystem))
+ (zLuser == NULL ? 4 : strlen (zLuser))
+ sizeof "1991-12-31 12:00:00.00"
+ strlen (zhdr)
+ 100);
zset = zprefix;
#if HAVE_TAYLOR_LOGGING
{
char *zbase;
zbase = zsysdep_base_name (zProgram);
if (zbase == NULL)
zbase = zbufcpy (zProgram);
zset = zstpcpy (zset, zbase);
*zset++ = ' ';
ubuffree (zbase);
}
#else
zset = zstpcpy (zset, zLuser == NULL ? "uucp" : zLuser);
*zset++ = ' ';
#endif
zset = zstpcpy (zset, zLsystem == NULL ? "-" : zLsystem);
*zset++ = ' ';
#if HAVE_TAYLOR_LOGGING
zset = zstpcpy (zset, zLuser == NULL ? "-" : zLuser);
*zset++ = ' ';
#endif
*zset++ = '(';
zset = zstpcpy (zset, zldate_and_time ());
if (iLid != 0)
{
#if ! HAVE_HDB_LOGGING
#if HAVE_TAYLOR_LOGGING
sprintf (zset, " %d", iLid);
#else
sprintf (zset, "-%d", iLid);
#endif
#else
sprintf (zset, ",%d,%d", iLid, 0);
#endif
zset += strlen (zset);
}
#if QNX_LOG_NODE_ID
sprintf (zset, " %ld", (long) getnid ());
zset += strlen (zset);
#endif
*zset++ = ')';
*zset++ = ' ';
strcpy (zset, zhdr);
}
}
zformat = zbufalc (2 * strlen (zprefix) + strlen (zmsg) + 2);
zset = zformat;
zfrom = zprefix;
while (*zfrom != '\0')
{
if (*zfrom == '%')
*zset++ = '%';
*zset++ = *zfrom++;
}
ubuffree (zprefix);
zset = zstpcpy (zset, zmsg);
if (fend)
{
*zset++ = '\n';
*zset = '\0';
}
#if HAVE_VFPRINTF
va_start (parg, zmsg);
vfprintf (e, zformat, parg);
va_end (parg);
if (edebug != NULL)
{
va_start (parg, zmsg);
vfprintf (edebug, zformat, parg);
va_end (parg);
}
#else
fprintf (e, zformat, a, b, c, d, f, g, h, i, j);
if (edebug != NULL)
fprintf (edebug, zformat, a, b, c, d, f, g, h, i, j);
#endif
ubuffree (zformat);
(void) fflush (e);
if (edebug != NULL)
(void) fflush (edebug);
if (pfLend != NULL)
(*pfLend) ();
if (ttype == LOG_FATAL)
{
if (pfLfatal != NULL)
(*pfLfatal) ();
usysdep_exit (FALSE);
}
#if CLOSE_LOGFILES
ulog_close ();
#endif
}
void
ulog_uuconf (ttype, puuconf, iuuconf)
enum tlog ttype;
pointer puuconf;
int iuuconf;
{
char ab[512];
(void) uuconf_error_string (puuconf, iuuconf, ab, sizeof ab);
ulog (ttype, "%s", ab);
}
void
ulog_close ()
{
ulog (LOG_ERROR, (const char *) NULL);
if (eLlog != NULL)
{
fchmod(fileno(eLlog), 0666);
(void) fclose (eLlog);
eLlog = NULL;
fLlog_tried = FALSE;
}
#if DEBUG > 1
if (eLdebug != NULL)
{
fchmod(fileno(eLdebug), 0666);
(void) fclose (eLdebug);
eLdebug = NULL;
fLdebug_tried = FALSE;
}
#endif
}
void
ustats (fsucceeded, zuser, zsystem, fsent, cbytes, csecs, cmicros, fcaller)
boolean fsucceeded;
const char *zuser;
const char *zsystem;
boolean fsent;
long cbytes;
long csecs;
long cmicros;
boolean fcaller ATTRIBUTE_UNUSED;
{
long cbps;
if (cmicros < 0)
{
csecs -= ((- cmicros) / 1000000L) + 1;
cmicros = 1000000L - ((- cmicros) % 1000000L);
}
if (cmicros >= 1000000L)
{
csecs += cmicros / 10000000L;
cmicros = cmicros % 1000000L;
}
if (csecs == 0 && cmicros < 1000)
cbps = 0;
else
{
long cmillis, cdiv, crem;
cmillis = csecs * 1000 + cmicros / 1000;
cdiv = (cbytes / cmillis) * 1000;
crem = (cbytes % cmillis) * 1000;
cbps = cdiv + (crem / cmillis);
if (cmillis < 0 || cdiv < 0 || crem < 0 || cbps < 0)
{
cbps = cbytes / (csecs + ((cmicros > 500000L) ? 1 : 0));
}
}
if (eLstats == NULL)
{
if (fLstats_tried)
return;
fLstats_tried = TRUE;
eLstats = esysdep_fopen (zLstatsfile, TRUE, TRUE, TRUE);
if (eLstats == NULL)
return;
}
#if HAVE_TAYLOR_LOGGING
fprintf (eLstats,
"%s %s (%s) %s%s %ld bytes in %ld.%03ld seconds (%ld bytes/sec) on port %s\n",
zuser, zsystem, zldate_and_time (),
fsucceeded ? "" : "failed after ",
fsent ? "sent" : "received",
cbytes, csecs, cmicros / 1000, cbps,
zLdevice == NULL ? "unknown" : zLdevice);
#endif
#if HAVE_V2_LOGGING
fprintf (eLstats,
"%s %s (%s) (%ld) %s %s %ld bytes %ld seconds\n",
zuser, zsystem, zldate_and_time (),
(long) time ((time_t *) NULL),
fsent ? "sent" : "received",
fsucceeded ? "data" : "failed after",
cbytes, csecs + cmicros / 500000);
#endif
#if HAVE_HDB_LOGGING
{
static int iseq;
++iseq;
fprintf (eLstats,
"%s!%s %c (%s) (C,%d,%d) [%s] %s %ld / %ld.%03ld secs, %ld%s%s\n",
zsystem, zuser, fcaller ? 'M' : 'S', zldate_and_time (),
iLid, iseq, zLdevice == NULL ? "unknown" : zLdevice,
fsent ? "->" : "<-",
cbytes, csecs, cmicros / 1000, cbps,
" bytes/sec",
fsucceeded ? "" : " [PARTIAL FILE]");
}
#endif
(void) fflush (eLstats);
#if CLOSE_LOGFILES
ustats_close ();
#endif
}
void
ustats_close ()
{
if (eLstats != NULL)
{
if (fclose (eLstats) != 0)
ulog (LOG_ERROR, "fclose: %s", strerror (errno));
eLstats = NULL;
fLstats_tried = FALSE;
}
}
static const char *
zldate_and_time ()
{
long isecs, imicros;
struct tm s;
#if HAVE_TAYLOR_LOGGING
static char ab[sizeof "1991-12-31 12:00:00.00"];
#endif
#if HAVE_V2_LOGGING
static char ab[sizeof "12/31-12:00"];
#endif
#if HAVE_HDB_LOGGING
static char ab[sizeof "12/31-12:00:00"];
#endif
isecs = ixsysdep_time (&imicros);
usysdep_localtime (isecs, &s);
#if HAVE_TAYLOR_LOGGING
sprintf (ab, "%04d-%02d-%02d %02d:%02d:%02d.%02d",
s.tm_year + 1900, s.tm_mon + 1, s.tm_mday, s.tm_hour,
s.tm_min, s.tm_sec, (int) (imicros / 10000));
#endif
#if HAVE_V2_LOGGING
sprintf (ab, "%d/%d-%02d:%02d", s.tm_mon + 1, s.tm_mday,
s.tm_hour, s.tm_min);
#endif
#if HAVE_HDB_LOGGING
sprintf (ab, "%d/%d-%d:%02d:%02d", s.tm_mon + 1, s.tm_mday,
s.tm_hour, s.tm_min, s.tm_sec);
#endif
return ab;
}