1/* log.c
2   Routines to add entries to the log files.
3
4   Copyright (C) 1991, 1992, 1993, 1994, 1995, 2002 Ian Lance Taylor
5
6   This file is part of the Taylor UUCP package.
7
8   This program is free software; you can redistribute it and/or
9   modify it under the terms of the GNU General Public License as
10   published by the Free Software Foundation; either version 2 of the
11   License, or (at your option) any later version.
12
13   This program is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16   General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program; if not, write to the Free Software
20   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
21
22   The author of the program may be contacted at ian@airs.com.
23   */
24
25#include "uucp.h"
26
27#if USE_RCS_ID
28const char log_rcsid[] = "$Id: log.c,v 1.65 2002/03/05 19:10:41 ian Rel $";
29#endif
30
31#include <ctype.h>
32#include <errno.h>
33
34#if HAVE_STDARG_H
35#include <stdarg.h>
36#endif
37
38#if TM_IN_SYS_TIME
39#include <sys/time.h>
40#else
41#include <time.h>
42#endif
43
44#include "uudefs.h"
45#include "uuconf.h"
46#include "system.h"
47
48/* Local functions.  */
49
50__inline__ static char *zstpcpy P((char *zto, const char *zfrom));
51static const char *zldate_and_time P((void));
52
53/* Program name.  Set by main function.  */
54const char *zProgram;
55
56/* Log file name.  */
57static const char *zLogfile;
58
59/* The function to call when a LOG_FATAL error occurs.  */
60static void (*pfLfatal) P((void));
61
62/* Whether to go to a file.  */
63static boolean fLfile;
64
65/* ID number.  */
66static int iLid;
67
68/* The current user name.  */
69static char *zLuser;
70
71/* The current system name.  */
72static char *zLsystem;
73
74/* The current device name.  */
75char *zLdevice;
76
77/* The open log file.  */
78static FILE *eLlog;
79
80/* Whether we have tried to open the log file.  We need this because
81   we don't want to keep trying to open the log file if we failed the
82   first time.  It can't be static because under HAVE_HDB_LOGGING we
83   may have to write to various different log files.  */
84static boolean fLlog_tried;
85
86#if DEBUG > 1
87/* Debugging file name.  */
88static const char *zLdebugfile;
89
90/* The open debugging file.  */
91static FILE *eLdebug;
92
93/* Whether we've tried to open the debugging file.  */
94static boolean fLdebug_tried;
95#endif
96
97/* Statistics file name.  */
98static const char *zLstatsfile;
99
100/* The open statistics file.  */
101static FILE *eLstats;
102
103/* Whether we've tried to open the statistics file.  */
104static boolean fLstats_tried;
105
106/* The array of signals.  The elements are only set to TRUE by the
107   default signal handler.  They are only set to FALSE if we don't
108   care whether we got the signal or not.  */
109volatile sig_atomic_t afSignal[INDEXSIG_COUNT];
110
111/* The array of signals to log.  The elements are only set to TRUE by
112   the default signal handler.  They are set to FALSE when the signal
113   is logged in ulog.  This means that if a signal comes in at just
114   the right time we won't log it (or, rather, we'll log it once
115   instead of twice), but that is not a catatrophe.  */
116volatile sig_atomic_t afLog_signal[INDEXSIG_COUNT];
117
118/* Flag that indicates SIGHUP is worth logging.  */
119boolean fLog_sighup = TRUE;
120
121/* Signal names to use when logging signals.  */
122static const char * const azSignal_names[INDEXSIG_COUNT] = INDEXSIG_NAMES;
123
124/* If not NULL, ulog calls this function before outputting anything.
125   This is used to support cu.  */
126void (*pfLstart) P((void));
127
128/* If not NULL, ulog calls this function after outputting everything.
129   This is used to support cu.  */
130void (*pfLend) P((void));
131
132/* Set the function to call on a LOG_FATAL error.  */
133
134void
135ulog_fatal_fn (pfn)
136     void (*pfn) P((void));
137{
138  pfLfatal = pfn;
139}
140
141/* Decide whether to send log message to the file or not.  */
142
143void
144ulog_to_file (puuconf, ffile)
145     pointer puuconf;
146     boolean ffile;
147{
148  int iuuconf;
149
150  iuuconf = uuconf_logfile (puuconf, &zLogfile);
151  if (iuuconf != UUCONF_SUCCESS)
152    ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
153
154#if DEBUG > 1
155  iuuconf = uuconf_debugfile (puuconf, &zLdebugfile);
156  if (iuuconf != UUCONF_SUCCESS)
157    ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
158#endif
159
160  iuuconf = uuconf_statsfile (puuconf, &zLstatsfile);
161  if (iuuconf != UUCONF_SUCCESS)
162    ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
163
164  fLfile = ffile;
165}
166
167/* Set the ID number.  This will be called by the usysdep_initialize
168   if there is something sensible to set it to.  */
169
170void
171ulog_id (i)
172     int i;
173{
174  iLid = i;
175}
176
177/* Set the user we are making log entries for.  The arguments will be
178   copied into memory.  */
179
180void
181ulog_user (zuser)
182     const char *zuser;
183{
184  ubuffree (zLuser);
185  zLuser = zbufcpy (zuser);
186}
187
188/* Set the system name we are making log entries for.  The name is copied
189   into memory.  */
190
191void
192ulog_system (zsystem)
193  const char *zsystem;
194{
195  if (zsystem == NULL
196      || zLsystem == NULL
197      || strcmp (zsystem, zLsystem) != 0)
198    {
199      ubuffree (zLsystem);
200      zLsystem = zbufcpy (zsystem);
201#if HAVE_HDB_LOGGING
202      /* Under HDB logging we now must write to a different log file.  */
203      ulog_close ();
204#endif /* HAVE_HDB_LOGGING */
205    }
206}
207
208/* Set the device name.  This is copied into memory.  */
209
210void
211ulog_device (zdevice)
212     const char *zdevice;
213{
214  ubuffree (zLdevice);
215  zLdevice = zbufcpy (zdevice);
216}
217
218/* A helper function for ulog.  */
219
220__inline__ static char *
221zstpcpy (zto, zfrom)
222     char *zto;
223     const char *zfrom;
224{
225  while ((*zto++ = *zfrom++) != '\0')
226    ;
227  return zto - 1;
228}
229
230/* Make a log entry.  We make a token concession to non ANSI_C systems,
231   but it clearly won't always work.  */
232
233#if ! HAVE_PROTOTYPES || ! HAVE_STDARG_H
234#undef HAVE_VFPRINTF
235#define HAVE_VFPRINTF 0
236#endif
237
238/*VARARGS2*/
239#if HAVE_VFPRINTF
240void
241ulog (enum tlog ttype, const char *zmsg, ...)
242#else
243void
244ulog (ttype, zmsg, a, b, c, d, f, g, h, i, j)
245     enum tlog ttype;
246     const char *zmsg;
247#endif
248{
249#if HAVE_VFPRINTF
250  va_list parg;
251#endif
252  FILE *e, *edebug;
253  boolean fstart, fend;
254  const char *zhdr;
255  char *zprefix;
256  register char *zset;
257  char *zformat;
258  char *zfrom;
259
260  /* Log any received signal.  We do it this way to avoid calling ulog
261     from the signal handler.  A few routines call ulog to get this
262     message out with zmsg == NULL.  */
263  {
264    static boolean fdoing_sigs;
265
266    if (! fdoing_sigs)
267      {
268	int isig;
269
270	fdoing_sigs = TRUE;
271	for (isig = 0; isig < INDEXSIG_COUNT; isig++)
272	  {
273	    if (afLog_signal[isig])
274	      {
275		afLog_signal[isig] = FALSE;
276
277		/* Apparently SunOS sends SIGINT rather than SIGHUP
278		   when hanging up, so we don't log either signal if
279		   fLog_sighup is FALSE.  */
280		if ((isig != INDEXSIG_SIGHUP && isig != INDEXSIG_SIGINT)
281		    || fLog_sighup)
282		  ulog (LOG_ERROR, "Got %s signal", azSignal_names[isig]);
283	      }
284	  }
285	fdoing_sigs = FALSE;
286      }
287  }
288
289#if DEBUG > 1
290  /* If we've had a debugging file open in the past, then we want to
291     write all log file entries to the debugging file even if it's
292     currently closed.  */
293  if (fLfile
294      && eLdebug == NULL
295      && ! fLdebug_tried
296      && iDebug != 0)
297    {
298      fLdebug_tried = TRUE;
299      eLdebug = esysdep_fopen (zLdebugfile, FALSE, TRUE, TRUE);
300    }
301#endif /* DEBUG > 1 */
302
303  if (! fLfile)
304    e = stderr;
305#if DEBUG > 1
306  else if ((int) ttype >= (int) LOG_DEBUG)
307    {
308      e = eLdebug;
309
310      /* If we can't open the debugging file, don't output any
311	 debugging messages.  */
312      if (e == NULL)
313	return;
314    }
315#endif /* DEBUG > 1 */
316  else
317    {
318      if (eLlog == NULL && ! fLlog_tried)
319	{
320	  const char *zprint = NULL;
321
322	  fLlog_tried = TRUE;
323#if ! HAVE_HDB_LOGGING
324	  eLlog = esysdep_fopen (zLogfile, TRUE, TRUE, TRUE);
325	  zprint = zLogfile;
326#else /* HAVE_HDB_LOGGING */
327	  {
328	    const char *zcheck;
329	    int cfmt;
330	    char *zfile;
331
332	    /* Only run sprintf if there are no more than two
333               unadorned %s.  If we see any other formatting
334               character, just use zLogfile as is.  This is to protect
335               the UUCP administrator against foolishness.  Note that
336               this has been reported as a security vulnerability, but
337               it is not.  */
338	    cfmt = 0;
339	    for (zcheck = zLogfile; *zcheck != '\0'; ++zcheck)
340	      {
341		if (*zcheck == '%')
342		  {
343		    if (zcheck[1] == 's')
344		      ++cfmt;
345		    else
346		      {
347			cfmt = 3;
348			break;
349		      }
350		  }
351	      }
352
353	    if (cfmt > 2)
354	      zfile = zbufcpy (zLogfile);
355	    else
356	      {
357		const char *zsys;
358		char *zbase;
359		char *zlower;
360
361		/* We want to write to .Log/program/system, e.g.
362		   .Log/uucico/uunet.  The system name may not be set.  */
363		if (zLsystem == NULL)
364		  zsys = "ANY";
365		else
366		  zsys = zLsystem;
367
368		zbase = zsysdep_base_name (zProgram);
369		if (zbase == NULL)
370		  zbase = zbufcpy (zProgram);
371
372		/* On some systems the native uusched will invoke
373		   uucico with an upper case argv[0].  We work around
374		   that by forcing the filename to lower case here.  */
375		for (zlower = zbase; *zlower != '\0'; zlower++)
376		  if (isupper (*zlower))
377		    *zlower = tolower (*zlower);
378
379		zfile = zbufalc (strlen (zLogfile)
380				 + strlen (zbase)
381				 + strlen (zsys)
382				 + 1);
383		sprintf (zfile, zLogfile, zbase, zsys);
384		ubuffree (zbase);
385	      }
386
387	    eLlog = esysdep_fopen (zfile, TRUE, TRUE, TRUE);
388	    if (eLlog != NULL)
389	      ubuffree (zfile);
390	    else
391	      zprint = zfile;
392	  }
393#endif /* HAVE_HDB_LOGGING */
394
395	  if (eLlog == NULL)
396	    {
397	      /* We can't open the log file.  We report the problem to
398		 stderr.  This is not ideal, since if this is uucico
399		 running on an inbound call stderr is actually
400		 connected to a remote system, but is better than
401		 doing nothing.  */
402	      fprintf (stderr, "%s: %s: can not open log file: %s\n",
403		       zProgram, zprint, strerror (errno));
404	      if (pfLfatal != NULL)
405		(*pfLfatal) ();
406	      usysdep_exit (FALSE);
407	    }
408	}
409
410      e = eLlog;
411
412      /* eLlog might be NULL here because we might try to open the log
413	 file recursively via esysdep_fopen.  */
414      if (e == NULL)
415	return;
416    }
417
418  if (zmsg == NULL)
419    return;
420
421  if (pfLstart != NULL)
422    (*pfLstart) ();
423
424  edebug = NULL;
425#if DEBUG > 1
426  if ((int) ttype < (int) LOG_DEBUG)
427    edebug = eLdebug;
428#endif
429
430  fstart = TRUE;
431  fend = TRUE;
432
433  switch (ttype)
434    {
435    case LOG_NORMAL:
436      zhdr = "";
437      break;
438    case LOG_ERROR:
439      zhdr = "ERROR: ";
440      break;
441    case LOG_FATAL:
442      zhdr = "FATAL: ";
443      break;
444#if DEBUG > 1
445    case LOG_DEBUG:
446      zhdr = "DEBUG: ";
447      break;
448    case LOG_DEBUG_START:
449      zhdr = "DEBUG: ";
450      fend = FALSE;
451      break;
452    case LOG_DEBUG_CONTINUE:
453      zhdr = NULL;
454      fstart = FALSE;
455      fend = FALSE;
456      break;
457    case LOG_DEBUG_END:
458      zhdr = NULL;
459      fstart = FALSE;
460      break;
461#endif
462    default:
463      zhdr = "???: ";
464      break;
465    }
466
467  if (! fstart)
468    zprefix = zbufcpy ("");
469  else
470    {
471      if (! fLfile)
472	{
473	  zprefix = zbufalc (strlen (zProgram) + 3);
474	  sprintf (zprefix, "%s: ", zProgram);
475	}
476      else
477	{
478	  zprefix = zbufalc (strlen (zProgram)
479			     + (zLsystem == NULL ? 1 : strlen (zLsystem))
480			     + (zLuser == NULL ? 4 : strlen (zLuser))
481			     + sizeof "1991-12-31 12:00:00.00"
482			     + strlen (zhdr)
483			     + 100);
484	  zset = zprefix;
485#if HAVE_TAYLOR_LOGGING
486	  {
487	    char *zbase;
488
489	    zbase = zsysdep_base_name (zProgram);
490	    if (zbase == NULL)
491	      zbase = zbufcpy (zProgram);
492	    zset = zstpcpy (zset, zbase);
493	    *zset++ = ' ';
494	    ubuffree (zbase);
495	  }
496#else /* ! HAVE_TAYLOR_LOGGING */
497	  zset = zstpcpy (zset, zLuser == NULL ? "uucp" : zLuser);
498	  *zset++ = ' ';
499#endif /* HAVE_TAYLOR_LOGGING */
500
501	  zset = zstpcpy (zset, zLsystem == NULL ? "-" : zLsystem);
502	  *zset++ = ' ';
503
504#if HAVE_TAYLOR_LOGGING
505	  zset = zstpcpy (zset, zLuser == NULL ? "-" : zLuser);
506	  *zset++ = ' ';
507#endif /* HAVE_TAYLOR_LOGGING */
508
509	  *zset++ = '(';
510	  zset = zstpcpy (zset, zldate_and_time ());
511
512	  if (iLid != 0)
513	    {
514#if ! HAVE_HDB_LOGGING
515#if HAVE_TAYLOR_LOGGING
516	      sprintf (zset, " %d", iLid);
517#else /* ! HAVE_TAYLOR_LOGGING */
518	      sprintf (zset, "-%d", iLid);
519#endif /* ! HAVE_TAYLOR_LOGGING */
520#else /* HAVE_HDB_LOGGING */
521	      /* I assume that the second number here is meant to be
522		 some sort of file sequence number, and that it should
523		 correspond to the sequence number in the statistics
524		 file.  I don't have any really convenient way to do
525		 this, so I won't unless somebody thinks it's very
526		 important.  */
527	      sprintf (zset, ",%d,%d", iLid, 0);
528#endif /* HAVE_HDB_LOGGING */
529
530	      zset += strlen (zset);
531	    }
532
533#if QNX_LOG_NODE_ID
534	  sprintf (zset, " %ld", (long) getnid ());
535	  zset += strlen (zset);
536#endif
537
538	  *zset++ = ')';
539	  *zset++ = ' ';
540
541	  strcpy (zset, zhdr);
542	}
543    }
544
545  zformat = zbufalc (2 * strlen (zprefix) + strlen (zmsg) + 2);
546
547  zset = zformat;
548  zfrom = zprefix;
549  while (*zfrom != '\0')
550    {
551      if (*zfrom == '%')
552	*zset++ = '%';
553      *zset++ = *zfrom++;
554    }
555
556  ubuffree (zprefix);
557
558  zset = zstpcpy (zset, zmsg);
559
560  if (fend)
561    {
562      *zset++ = '\n';
563      *zset = '\0';
564    }
565
566#if HAVE_VFPRINTF
567  va_start (parg, zmsg);
568  vfprintf (e, zformat, parg);
569  va_end (parg);
570  if (edebug != NULL)
571    {
572      va_start (parg, zmsg);
573      vfprintf (edebug, zformat, parg);
574      va_end (parg);
575    }
576#else /* ! HAVE_VFPRINTF */
577  fprintf (e, zformat, a, b, c, d, f, g, h, i, j);
578  if (edebug != NULL)
579    fprintf (edebug, zformat, a, b, c, d, f, g, h, i, j);
580#endif /* ! HAVE_VFPRINTF */
581
582  ubuffree (zformat);
583
584  (void) fflush (e);
585  if (edebug != NULL)
586    (void) fflush (edebug);
587
588  if (pfLend != NULL)
589    (*pfLend) ();
590
591  if (ttype == LOG_FATAL)
592    {
593      if (pfLfatal != NULL)
594	(*pfLfatal) ();
595      usysdep_exit (FALSE);
596    }
597
598#if CLOSE_LOGFILES
599  ulog_close ();
600#endif
601}
602
603/* Log a uuconf error.  */
604
605void
606ulog_uuconf (ttype, puuconf, iuuconf)
607     enum tlog ttype;
608     pointer puuconf;
609     int iuuconf;
610{
611  char ab[512];
612
613  (void) uuconf_error_string (puuconf, iuuconf, ab, sizeof ab);
614  ulog (ttype, "%s", ab);
615}
616
617/* Close the log file.  There's nothing useful we can do with errors,
618   so we don't check for them.  */
619
620void
621ulog_close ()
622{
623  /* Make sure we logged any signal we received.  */
624  ulog (LOG_ERROR, (const char *) NULL);
625
626  if (eLlog != NULL)
627    {
628      fchmod(fileno(eLlog), 0666);
629      (void) fclose (eLlog);
630      eLlog = NULL;
631      fLlog_tried = FALSE;
632    }
633
634#if DEBUG > 1
635  if (eLdebug != NULL)
636    {
637      fchmod(fileno(eLdebug), 0666);
638      (void) fclose (eLdebug);
639      eLdebug = NULL;
640      fLdebug_tried = FALSE;
641    }
642#endif
643}
644
645/* Add an entry to the statistics file.  We may eventually want to put
646   failed file transfers in here, but we currently do not.  */
647
648/*ARGSUSED*/
649void
650ustats (fsucceeded, zuser, zsystem, fsent, cbytes, csecs, cmicros, fcaller)
651     boolean fsucceeded;
652     const char *zuser;
653     const char *zsystem;
654     boolean fsent;
655     long cbytes;
656     long csecs;
657     long cmicros;
658     boolean fcaller ATTRIBUTE_UNUSED;
659{
660  long cbps;
661
662  /* The seconds and microseconds are now counted independently, so
663     they may be out of synch.  */
664  if (cmicros < 0)
665    {
666      csecs -= ((- cmicros) / 1000000L) + 1;
667      cmicros = 1000000L - ((- cmicros) % 1000000L);
668    }
669  if (cmicros >= 1000000L)
670    {
671      csecs += cmicros / 10000000L;
672      cmicros = cmicros % 1000000L;
673    }
674
675  /* On a system which can determine microseconds we might very well
676     have both csecs == 0 and cmicros == 0.  */
677  if (csecs == 0 && cmicros < 1000)
678    cbps = 0;
679  else
680    {
681      long cmillis, cdiv, crem;
682
683      /* Compute ((csecs * 1000) / cmillis) using integer division.
684	 Where DIV is integer division, we know
685	     a = (a DIV b) * b + a % b
686	 so
687	     a / b = (a DIV b) + (a % b) / b
688	 We compute the latter with a as csecs and b as cmillis,
689	 mixing the multiplication by 1000.  */
690      cmillis = csecs * 1000 + cmicros / 1000;
691      cdiv = (cbytes / cmillis) * 1000;
692      crem = (cbytes % cmillis) * 1000;
693      cbps = cdiv + (crem / cmillis);
694      if (cmillis < 0 || cdiv < 0 || crem < 0 || cbps < 0)
695	{
696	  /* We overflowed using milliseconds, so use seconds.  */
697	  cbps = cbytes / (csecs + ((cmicros > 500000L) ? 1 : 0));
698	}
699    }
700
701  if (eLstats == NULL)
702    {
703      if (fLstats_tried)
704	return;
705      fLstats_tried = TRUE;
706      eLstats = esysdep_fopen (zLstatsfile, TRUE, TRUE, TRUE);
707      if (eLstats == NULL)
708	return;
709    }
710
711#if HAVE_TAYLOR_LOGGING
712  fprintf (eLstats,
713	   "%s %s (%s) %s%s %ld bytes in %ld.%03ld seconds (%ld bytes/sec) on port %s\n",
714	   zuser, zsystem, zldate_and_time (),
715	   fsucceeded ? "" : "failed after ",
716	   fsent ? "sent" : "received",
717	   cbytes, csecs, cmicros / 1000, cbps,
718	   zLdevice == NULL ? "unknown" : zLdevice);
719#endif /* HAVE_TAYLOR_LOGGING */
720#if HAVE_V2_LOGGING
721  fprintf (eLstats,
722	   "%s %s (%s) (%ld) %s %s %ld bytes %ld seconds\n",
723	   zuser, zsystem, zldate_and_time (),
724	   (long) time ((time_t *) NULL),
725	   fsent ? "sent" : "received",
726	   fsucceeded ? "data" : "failed after",
727	   cbytes, csecs + cmicros / 500000);
728#endif /* HAVE_V2_LOGGING */
729#if HAVE_HDB_LOGGING
730  {
731    static int iseq;
732
733    /* I don't know what the 'C' means.  The sequence number should
734       probably correspond to the sequence number in the log file, but
735       that is currently always 0; using this fake sequence number
736       will still at least reveal which transfers are from different
737       calls.  */
738    ++iseq;
739    fprintf (eLstats,
740	     "%s!%s %c (%s) (C,%d,%d) [%s] %s %ld / %ld.%03ld secs, %ld%s%s\n",
741	     zsystem, zuser, fcaller ? 'M' : 'S', zldate_and_time (),
742	     iLid, iseq, zLdevice == NULL ? "unknown" : zLdevice,
743	     fsent ? "->" : "<-",
744	     cbytes, csecs, cmicros / 1000, cbps,
745	     " bytes/sec",
746	     fsucceeded ? "" : " [PARTIAL FILE]");
747  }
748#endif /* HAVE_HDB_LOGGING */
749
750  (void) fflush (eLstats);
751
752#if CLOSE_LOGFILES
753  ustats_close ();
754#endif
755}
756
757/* Close the statistics file.  */
758
759void
760ustats_close ()
761{
762  if (eLstats != NULL)
763    {
764      if (fclose (eLstats) != 0)
765	ulog (LOG_ERROR, "fclose: %s", strerror (errno));
766      eLstats = NULL;
767      fLstats_tried = FALSE;
768    }
769}
770
771/* Return the date and time in a form used for a log entry.  */
772
773static const char *
774zldate_and_time ()
775{
776  long isecs, imicros;
777  struct tm s;
778#if HAVE_TAYLOR_LOGGING
779  static char ab[sizeof "1991-12-31 12:00:00.00"];
780#endif
781#if HAVE_V2_LOGGING
782  static char ab[sizeof "12/31-12:00"];
783#endif
784#if HAVE_HDB_LOGGING
785  static char ab[sizeof "12/31-12:00:00"];
786#endif
787
788  isecs = ixsysdep_time (&imicros);
789  usysdep_localtime (isecs, &s);
790
791#if HAVE_TAYLOR_LOGGING
792  sprintf (ab, "%04d-%02d-%02d %02d:%02d:%02d.%02d",
793	   s.tm_year + 1900, s.tm_mon + 1, s.tm_mday, s.tm_hour,
794	   s.tm_min, s.tm_sec, (int) (imicros / 10000));
795#endif
796#if HAVE_V2_LOGGING
797  sprintf (ab, "%d/%d-%02d:%02d", s.tm_mon + 1, s.tm_mday,
798	   s.tm_hour, s.tm_min);
799#endif
800#if HAVE_HDB_LOGGING
801  sprintf (ab, "%d/%d-%d:%02d:%02d", s.tm_mon + 1, s.tm_mday,
802	   s.tm_hour, s.tm_min, s.tm_sec);
803#endif
804
805  return ab;
806}
807