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
28 const char log_rcsid[] = "$FreeBSD$";
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));
51 static const char *zldate_and_time P((void));
52
53 /* Program name. Set by main function. */
54 const char *zProgram;
55
56 /* Log file name. */
57 static const char *zLogfile;
58
59 /* The function to call when a LOG_FATAL error occurs. */
60 static void (*pfLfatal) P((void));
61
62 /* Whether to go to a file. */
63 static boolean fLfile;
64
65 /* ID number. */
66 static int iLid;
67
68 /* The current user name. */
69 static char *zLuser;
70
71 /* The current system name. */
72 static char *zLsystem;
73
74 /* The current device name. */
75 char *zLdevice;
76
77 /* The open log file. */
78 static 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. */
84 static boolean fLlog_tried;
85
86 #if DEBUG > 1
87 /* Debugging file name. */
88 static const char *zLdebugfile;
89
90 /* The open debugging file. */
91 static FILE *eLdebug;
92
93 /* Whether we've tried to open the debugging file. */
94 static boolean fLdebug_tried;
95 #endif
96
97 /* Statistics file name. */
98 static const char *zLstatsfile;
99
100 /* The open statistics file. */
101 static FILE *eLstats;
102
103 /* Whether we've tried to open the statistics file. */
104 static 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. */
109 volatile 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. */
116 volatile sig_atomic_t afLog_signal[INDEXSIG_COUNT];
117
118 /* Flag that indicates SIGHUP is worth logging. */
119 boolean fLog_sighup = TRUE;
120
121 /* Signal names to use when logging signals. */
122 static 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. */
126 void (*pfLstart) P((void));
127
128 /* If not NULL, ulog calls this function after outputting everything.
129 This is used to support cu. */
130 void (*pfLend) P((void));
131
132 /* Set the function to call on a LOG_FATAL error. */
133
134 void
135 ulog_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
143 void
ulog_to_file(puuconf,ffile)144 ulog_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
170 void
ulog_id(i)171 ulog_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
180 void
ulog_user(zuser)181 ulog_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
191 void
ulog_system(zsystem)192 ulog_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
210 void
ulog_device(zdevice)211 ulog_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 *
zstpcpy(zto,zfrom)221 zstpcpy (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
240 void
ulog(enum tlog ttype,const char * zmsg,...)241 ulog (enum tlog ttype, const char *zmsg, ...)
242 #else
243 void
244 ulog (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
605 void
ulog_uuconf(ttype,puuconf,iuuconf)606 ulog_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
620 void
ulog_close()621 ulog_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 (void) fclose (eLlog);
629 eLlog = NULL;
630 fLlog_tried = FALSE;
631 }
632
633 #if DEBUG > 1
634 if (eLdebug != NULL)
635 {
636 (void) fclose (eLdebug);
637 eLdebug = NULL;
638 fLdebug_tried = FALSE;
639 }
640 #endif
641 }
642
643 /* Add an entry to the statistics file. We may eventually want to put
644 failed file transfers in here, but we currently do not. */
645
646 /*ARGSUSED*/
647 void
ustats(fsucceeded,zuser,zsystem,fsent,cbytes,csecs,cmicros,fcaller)648 ustats (fsucceeded, zuser, zsystem, fsent, cbytes, csecs, cmicros, fcaller)
649 boolean fsucceeded;
650 const char *zuser;
651 const char *zsystem;
652 boolean fsent;
653 long cbytes;
654 long csecs;
655 long cmicros;
656 boolean fcaller ATTRIBUTE_UNUSED;
657 {
658 long cbps;
659
660 /* The seconds and microseconds are now counted independently, so
661 they may be out of synch. */
662 if (cmicros < 0)
663 {
664 csecs -= ((- cmicros) / 1000000L) + 1;
665 cmicros = 1000000L - ((- cmicros) % 1000000L);
666 }
667 if (cmicros >= 1000000L)
668 {
669 csecs += cmicros / 10000000L;
670 cmicros = cmicros % 1000000L;
671 }
672
673 /* On a system which can determine microseconds we might very well
674 have both csecs == 0 and cmicros == 0. */
675 if (csecs == 0 && cmicros < 1000)
676 cbps = 0;
677 else
678 {
679 long cmillis, cdiv, crem;
680
681 /* Compute ((csecs * 1000) / cmillis) using integer division.
682 Where DIV is integer division, we know
683 a = (a DIV b) * b + a % b
684 so
685 a / b = (a DIV b) + (a % b) / b
686 We compute the latter with a as csecs and b as cmillis,
687 mixing the multiplication by 1000. */
688 cmillis = csecs * 1000 + cmicros / 1000;
689 cdiv = (cbytes / cmillis) * 1000;
690 crem = (cbytes % cmillis) * 1000;
691 cbps = cdiv + (crem / cmillis);
692 if (cmillis < 0 || cdiv < 0 || crem < 0 || cbps < 0)
693 {
694 /* We overflowed using milliseconds, so use seconds. */
695 cbps = cbytes / (csecs + ((cmicros > 500000L) ? 1 : 0));
696 }
697 }
698
699 if (eLstats == NULL)
700 {
701 if (fLstats_tried)
702 return;
703 fLstats_tried = TRUE;
704 eLstats = esysdep_fopen (zLstatsfile, TRUE, TRUE, TRUE);
705 if (eLstats == NULL)
706 return;
707 }
708
709 #if HAVE_TAYLOR_LOGGING
710 fprintf (eLstats,
711 "%s %s (%s) %s%s %ld bytes in %ld.%03ld seconds (%ld bytes/sec) on port %s\n",
712 zuser, zsystem, zldate_and_time (),
713 fsucceeded ? "" : "failed after ",
714 fsent ? "sent" : "received",
715 cbytes, csecs, cmicros / 1000, cbps,
716 zLdevice == NULL ? "unknown" : zLdevice);
717 #endif /* HAVE_TAYLOR_LOGGING */
718 #if HAVE_V2_LOGGING
719 fprintf (eLstats,
720 "%s %s (%s) (%ld) %s %s %ld bytes %ld seconds\n",
721 zuser, zsystem, zldate_and_time (),
722 (long) time ((time_t *) NULL),
723 fsent ? "sent" : "received",
724 fsucceeded ? "data" : "failed after",
725 cbytes, csecs + cmicros / 500000);
726 #endif /* HAVE_V2_LOGGING */
727 #if HAVE_HDB_LOGGING
728 {
729 static int iseq;
730
731 /* I don't know what the 'C' means. The sequence number should
732 probably correspond to the sequence number in the log file, but
733 that is currently always 0; using this fake sequence number
734 will still at least reveal which transfers are from different
735 calls. */
736 ++iseq;
737 fprintf (eLstats,
738 "%s!%s %c (%s) (C,%d,%d) [%s] %s %ld / %ld.%03ld secs, %ld%s%s\n",
739 zsystem, zuser, fcaller ? 'M' : 'S', zldate_and_time (),
740 iLid, iseq, zLdevice == NULL ? "unknown" : zLdevice,
741 fsent ? "->" : "<-",
742 cbytes, csecs, cmicros / 1000, cbps,
743 " bytes/sec",
744 fsucceeded ? "" : " [PARTIAL FILE]");
745 }
746 #endif /* HAVE_HDB_LOGGING */
747
748 (void) fflush (eLstats);
749
750 #if CLOSE_LOGFILES
751 ustats_close ();
752 #endif
753 }
754
755 /* Close the statistics file. */
756
757 void
ustats_close()758 ustats_close ()
759 {
760 if (eLstats != NULL)
761 {
762 if (fclose (eLstats) != 0)
763 ulog (LOG_ERROR, "fclose: %s", strerror (errno));
764 eLstats = NULL;
765 fLstats_tried = FALSE;
766 }
767 }
768
769 /* Return the date and time in a form used for a log entry. */
770
771 static const char *
zldate_and_time()772 zldate_and_time ()
773 {
774 long isecs, imicros;
775 struct tm s;
776 #if HAVE_TAYLOR_LOGGING
777 static char ab[sizeof "1991-12-31 12:00:00.00"];
778 #endif
779 #if HAVE_V2_LOGGING
780 static char ab[sizeof "12/31-12:00"];
781 #endif
782 #if HAVE_HDB_LOGGING
783 static char ab[sizeof "12/31-12:00:00"];
784 #endif
785
786 isecs = ixsysdep_time (&imicros);
787 usysdep_localtime (isecs, &s);
788
789 #if HAVE_TAYLOR_LOGGING
790 sprintf (ab, "%04d-%02d-%02d %02d:%02d:%02d.%02d",
791 s.tm_year + 1900, s.tm_mon + 1, s.tm_mday, s.tm_hour,
792 s.tm_min, s.tm_sec, (int) (imicros / 10000));
793 #endif
794 #if HAVE_V2_LOGGING
795 sprintf (ab, "%d/%d-%02d:%02d", s.tm_mon + 1, s.tm_mday,
796 s.tm_hour, s.tm_min);
797 #endif
798 #if HAVE_HDB_LOGGING
799 sprintf (ab, "%d/%d-%d:%02d:%02d", s.tm_mon + 1, s.tm_mday,
800 s.tm_hour, s.tm_min, s.tm_sec);
801 #endif
802
803 return ab;
804 }
805