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