home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / gnu / fax-3.2.1 / lib / libutil / logmsg.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-07-31  |  8.8 KB  |  505 lines

  1. /*
  2.   This file is part of the NetFax system.
  3.  
  4.   (c) Copyright 1989 by David M. Siegel and Sundar Narasimhan.
  5.       All rights reserved.
  6.  
  7.     This program is free software; you can redistribute it and/or modify
  8.     it under the terms of the GNU General Public License as published by
  9.     the Free Software Foundation.
  10.  
  11.     This program is distributed in the hope that it will be useful, 
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of 
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.     GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License
  17.     along with this program; if not, write to the Free Software
  18.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19. */
  20.  
  21. #include <stdio.h>
  22. #include <time.h>
  23. #include <syslog.h>
  24. #include <errno.h>
  25. #include <varargs.h>
  26. #include <strings.h>
  27.  
  28. #include "alloc.h"
  29. #include "bool.h"
  30. #include "list.h"
  31. #include "hash.h"
  32. #include "logmsg.h"
  33.  
  34. extern char *sys_errlist[];
  35. extern int sys_nerr;
  36.  
  37. static LIST *logs = NULL;
  38.  
  39. struct logrecord {
  40.     long last;
  41.     long ok;
  42.     int count;
  43.     int shutdown;
  44. };
  45.  
  46. #define HTSIZE           1024
  47. #define LIMIT_RESTART_WAIT (60*10)
  48.  
  49. static HTTABLE *limit_ht;
  50. static int limit_rate;
  51.  
  52. #define LIMIT_OK    0
  53. #define LIMIT_SHUTDOWN    1
  54. #define LIMIT_OFF    2
  55.  
  56. static int
  57. limit_check(file, line)
  58. char *file;
  59. int line;
  60. {
  61.     char key[BUFSIZ];
  62.     struct logrecord *r;
  63.     long curtime = time(0);
  64.  
  65.     if (limit_ht == NULL) {
  66.     if ((limit_ht = htinit(HTSIZE, 0)) == NULL) {
  67.         fprintf(stderr, "can't init logmsg hashtable\n");
  68.         return (LIMIT_OK);
  69.     }
  70.     }
  71.  
  72.     if (file == NULL)
  73.       return (LIMIT_OK);
  74.  
  75.     sprintf(key, "%s%d", file, line);
  76.     
  77.     if ((r = (struct logrecord *)htgetdata(key, limit_ht)) == NULL) {
  78.     if ((r = salloc(1, struct logrecord)) == NULL) {
  79.         fprintf(stderr, "can't allocate logrecord struct\n");
  80.         return (LIMIT_OK);
  81.     }
  82.     htadd(key, limit_ht, (char *)r);
  83.     }
  84.  
  85.     r->count++;
  86.  
  87.     if (r->shutdown) {
  88.     if (r->last == curtime)
  89.       return (LIMIT_OFF);
  90.     else {
  91.         r->last = curtime;
  92.         if (r->count/(curtime - r->ok) > limit_rate) {
  93.         r->ok = curtime;
  94.         r->count = 1;
  95.         return (LIMIT_OFF);
  96.         } else {
  97.         if ((curtime - r->ok) >= (long)LIMIT_RESTART_WAIT) {
  98.             r->shutdown = FALSE;
  99.             r->count = 1;
  100.             return (LIMIT_OK);
  101.         } else {
  102.             r->count = 1;
  103.             return (LIMIT_OFF);
  104.         }
  105.         }
  106.     }
  107.     }
  108.  
  109.     if (r->last == curtime) {
  110.     if (r->count > limit_rate) {
  111.         r->shutdown = TRUE;
  112.         r->ok = curtime;
  113.         return (LIMIT_SHUTDOWN);
  114.     }
  115.     } else {
  116.     r->last = curtime;
  117.     r->count = 1;
  118.     }
  119.  
  120.     return (LIMIT_OK);
  121. }
  122.  
  123. /*
  124.   We break this routine out from below to avoid performing
  125.   this scan if we're not using the format string.  That is,
  126.   the loglevel is to low to force the printout.
  127. */
  128. static void
  129. fix_format(format_in, format_out, len, errno_save, file, line)
  130. char *format_in;
  131. char *format_out;
  132. int len;
  133. int errno_save;
  134. char *file;
  135. int line;
  136. {
  137.     char *f = format_in;
  138.     char *b = format_out;
  139.     char *b_end = &format_out[len];
  140.     char c;
  141.  
  142.     while ((c = *f++) != '\0' && c != '\n' && b < b_end) {
  143.     if (c != '%') {
  144.         *b++ = c;
  145.         continue;
  146.     }
  147.     c = *f++;
  148.     switch (c) {
  149.       case 'm':
  150.         if ((unsigned)errno_save > sys_nerr)
  151.           sprintf(b, "error %d", errno_save);
  152.         else
  153.           strcpy(b, sys_errlist[errno_save]);
  154.         b += strlen(b);
  155.         break;
  156.       case 'F':
  157.         sprintf(b, "%s", file);
  158.         b += strlen(b);
  159.         break;
  160.       case 'L':
  161.         sprintf(b, "%d", line);
  162.         b += strlen(b);
  163.         break;
  164.       default:
  165.         *b++ = '%';
  166.         *b++ = c;
  167.         break;
  168.     }
  169.     }
  170.  
  171.     *b++ = '\n';
  172.     *b = '\0';
  173. }
  174.  
  175. /*VARARGS*/
  176. int
  177. logmsg(va_alist)
  178. va_dcl
  179. {
  180.     va_list ap;
  181.     int level;
  182.     char *format;
  183.     NODE *node = NULL;
  184.     LOG *log;
  185.     char buf[BUFSIZ];
  186.     char formatbuf[BUFSIZ];
  187.     char *file;
  188.     int line;
  189.     int mask;
  190.     int limit_stat;
  191.     int do_fix = TRUE;
  192.     int errno_save;
  193.  
  194.     errno_save = errno;
  195.  
  196.     va_start(ap);
  197.  
  198.     level = va_arg(ap, int);
  199.     file = va_arg(ap, char *);
  200.     line = va_arg(ap, int);
  201.     mask = va_arg(ap, int);
  202.     format = va_arg(ap, char *);
  203.  
  204.     if ((file != NULL) && (limit_rate > 0))
  205.       limit_stat = limit_check(file, line);
  206.     else
  207.       limit_stat = LIMIT_OK;
  208.  
  209.     if (limit_stat == LIMIT_OFF)
  210.       return (0);
  211.  
  212.  
  213.     if (logs == NULL) {
  214.     if (do_fix) {
  215.         fix_format(format, formatbuf, sizeof(formatbuf),
  216.                errno_save, file, line);
  217.         do_fix = FALSE;
  218.     }
  219.     vfprintf(stderr, formatbuf, ap);
  220.     return (0);
  221.     }
  222.  
  223.     if (level < 0)
  224.       level = 0;
  225.     if (level > MAX_LOG_LEVEL)
  226.       level = MAX_LOG_LEVEL;
  227.  
  228.     while ((log = (LOG *)list_next(logs, &node)) != NULL) {
  229.     if ((mask == 0) || mask & log->mask[level]) {
  230.         if (log->style & L_STYLE_TIME) {
  231.         struct tm *tm;
  232.         long t = time(0);
  233.         tm = localtime(&t);
  234.         sprintf(buf, "%d/%d/%d %02d:%02d:%02d",
  235.             tm->tm_mon+1, tm->tm_mday, tm->tm_year,
  236.             tm->tm_hour, tm->tm_min, tm->tm_sec);
  237.         } else
  238.           buf[0] = '\0';
  239.  
  240.         if ((log->style & L_STYLE_LINE) && (file != NULL)) {
  241.         char *ptr = rindex(file, '.');
  242.         if (ptr != NULL)
  243.           *ptr = '\0';
  244.         if (strlen(buf) > 0)
  245.           strcat(buf, " ");
  246.         sprintf(&buf[strlen(buf)], "(%s:%d): ", file, line);
  247.         } else {
  248.         if (strlen(buf) > 0)
  249.           strcat(buf, ": ");
  250.         }
  251.  
  252.         if (limit_stat == LIMIT_SHUTDOWN)
  253.           strcat(buf, "EXCESSIVE MESSAGES: ");
  254.  
  255.         if (do_fix) {
  256.         fix_format(format, formatbuf, sizeof(formatbuf),
  257.                errno_save, file, line);
  258.         do_fix = FALSE;
  259.         }
  260.         vsprintf(&buf[strlen(buf)], formatbuf, ap);
  261.  
  262.         if (log->type != L_TYPE_SYSLOG)
  263.           fprintf(log->fp, "%s", buf);
  264.         else
  265.           syslog(level, "%s", buf);
  266.     }
  267.     }
  268.  
  269.     va_end(ap);
  270.  
  271.     return (0);
  272. }
  273.  
  274. int
  275. notice(va_alist)
  276. va_dcl
  277. {
  278.     va_list ap;
  279.     char *format;
  280.     char buf[BUFSIZ];
  281.  
  282.     va_start(ap);
  283.     format = va_arg(ap, char *);
  284.     va_end(ap);
  285.  
  286.     vsprintf(buf, format, ap);
  287.  
  288.     logmsg(LOG_INFO, NULL, 0, 0, "%s", buf);
  289.  
  290.     return (0);
  291. }
  292.  
  293. int
  294. log_set_limit(rate)
  295. int rate;
  296. {
  297.     limit_rate = rate;
  298.  
  299.     return (0);
  300. }
  301.  
  302. static int
  303. reset_limits(r)
  304. struct logrecord *r;
  305. {
  306.     r->shutdown = FALSE;
  307.  
  308.     return (0);
  309. }
  310.  
  311. int
  312. log_reset_limits()
  313. {
  314.     if (limit_ht != NULL)
  315.       htmap(limit_ht, reset_limits, 0);
  316.     
  317.     return (0);
  318. }
  319.  
  320. int
  321. log_set_mask(log, level, mask)
  322. LOG *log;
  323. int level;
  324. int mask;
  325. {
  326.     int i;
  327.  
  328.     if (level < 0)
  329.       level = 0;
  330.  
  331.     if (level > MAX_LOG_LEVEL)
  332.       level = MAX_LOG_LEVEL;
  333.  
  334.     for (i = 0; i <= level; i++)
  335.      log->mask[i] |= mask;
  336.  
  337.     for (i = level+1; i <= MAX_LOG_LEVEL; i++)
  338.       log->mask[i] &= ~mask;
  339.     
  340.     return (0);
  341. }
  342.  
  343. int
  344. log_set_level(log, level)
  345. LOG *log;
  346. int level;
  347. {
  348.     return (log_set_mask(log, level, -1));
  349. }
  350.  
  351. static LOG *
  352. add_log(level, mask, type, style)
  353. int level;
  354. int mask;
  355. int type;
  356. int style;
  357. {
  358.     LOG *log;
  359.  
  360.     if (logs == NULL)
  361.       if ((logs = list_make(NULL, NULL)) == NULL)
  362.     return (NULL);
  363.  
  364.     if ((log = salloc(1, LOG)) == NULL)
  365.       return (NULL);
  366.  
  367.     log->type = type;
  368.     log->style = style;
  369.  
  370.     log_set_mask(log, level, mask);
  371.  
  372.     list_add(logs, (char *)log);
  373.  
  374.     return (log);
  375. }
  376.  
  377. LOG *
  378. log_open_syslog(ident, logopt, facility, level, mask, style)
  379. char *ident;
  380. int logopt;
  381. int facility;
  382. int level;
  383. int mask;
  384. int style;
  385. {
  386.     LOG *log;
  387.  
  388.     if ((log = add_log(level, mask, L_TYPE_SYSLOG, style)) == NULL)
  389.       return (NULL);
  390.  
  391.     openlog(ident, logopt, facility);
  392.  
  393.     return (log);
  394. }
  395.  
  396. LOG *
  397. log_open_fp(fp, level, mask, style)
  398. FILE *fp;
  399. int level;
  400. int mask;
  401. int style;
  402. {
  403.     LOG *log;
  404.  
  405.     if ((log = add_log(level, mask, L_TYPE_FP, style)) == NULL)
  406.       return (NULL);
  407.     
  408.     log->fp = fp;
  409.  
  410.     return (log);
  411. }
  412.  
  413. LOG *
  414. log_open_file(filename, level, mask, style)
  415. char *filename;
  416. int level;
  417. int mask;
  418. int style;
  419. {
  420.     FILE *fp;
  421.     LOG *log;
  422.  
  423.     if ((fp = fopen(filename, "a")) == NULL)
  424.       return (NULL);
  425.  
  426.     if ((log = add_log(level, mask, L_TYPE_FILE, style)) == NULL)
  427.       return (NULL);
  428.  
  429.     log->fp = fp;
  430.  
  431.     return (log);
  432. }
  433.  
  434. int
  435. log_close(log)
  436. LOG *log;
  437. {
  438.     if (log->type == L_TYPE_FILE)
  439.       fclose(log->fp);
  440.     
  441.     list_delete(logs, (char *)log);
  442.  
  443.     return (0);
  444. }
  445.  
  446. int
  447. log_parse_mask(mask_str, alist, size, maskp)
  448. char *mask_str;
  449. LOGMASK_ALIST *alist;
  450. int size;
  451. int *maskp;
  452. {
  453.     char name[BUFSIZ];
  454.     char *namep = name;
  455.     char *ptr = mask_str;
  456.     int i;
  457.  
  458.     *maskp = 0;
  459.  
  460.     for (;;) {
  461.     /*
  462.       Mask lists have symbolic mask names separated by commas.
  463.     */
  464.     if ((*ptr == ',') || (*ptr == '\0')) {
  465.         /*
  466.           Process the last entry we found by searching the mask
  467.           alist for a match, and oring in the bit pattern.
  468.         */
  469.         *namep = '\0';
  470.         for (i=0; i<size; i++) {
  471.         if (strcmp(name, alist[i].name) == 0) {
  472.             *maskp |= alist[i].bit;
  473.             goto ok;
  474.         }
  475.         }
  476.         return (-1);
  477.       ok:
  478.         namep = name;
  479.     } else
  480.       *(namep++) = *ptr;
  481.     
  482.     if (*ptr == '\0')
  483.       return (0);
  484.     
  485.     ptr++;
  486.     }
  487. }
  488.  
  489. #ifdef DEBUG
  490. log_test_open()
  491. {
  492.     log_open_fp(stderr, LOG_DEBUG, L_MASK_ALL, L_STYLE_ALL);
  493. }
  494.  
  495. log_test()
  496. {
  497.     logmsg(L_EMERG, 1, "test message");
  498. }
  499.  
  500. log_test_other()
  501. {
  502.     logmsg(L_EMERG, 1, "test other message");
  503. }
  504. #endif DEBUG
  505.