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