Initial version of email gateway under CVS control.
[egate.git] / res+log / gw-log.c
1 /*
2    gw-log.c: Implementation of logging facilities.
3
4    Europagate, 1994-1995.
5
6    $Log: gw-log.c,v $
7    Revision 1.1.1.1  1995/02/09 17:27:12  adam
8    Initial version of email gateway under CVS control.
9
10
11    Initial:       Dec  7, 94 (Adam Dickmeiss)
12    Last update:   Dec 13, 94 (Adam Dickmeiss)
13
14  */
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <stdarg.h>
20 #include <fcntl.h>
21 #include <unistd.h>
22 #include <time.h>
23
24 #include <gw-log.h>
25
26 static char *app_name = NULL;
27 static unsigned level = GW_LOG_DEFAULT;
28 static int session = 0;
29
30 struct file_mask {
31     unsigned mask;           /* level mask for this file entry */
32     int fd;                  /* file descriptor for this file */
33     char *fname;             /* name of file ("" if stdout) */
34     struct file_mask *next;  /* next file in chain */
35 };
36
37 struct file_mask *file_mask_list = NULL;
38
39 char *gw_strdup (const char *s)
40 {
41     char *n = malloc (strlen(s)+1);
42     if (n)
43         strcpy (n, s);
44     return n;
45 }
46
47 void gw_log_init (const char *app_name_a)
48 {
49     struct file_mask *list, *list1;
50
51     app_name = gw_strdup (app_name_a);
52     level = GW_LOG_DEFAULT;
53     session = 0;
54
55     /* clean up all output file masks... */
56     for (list = file_mask_list; list; list = list1)
57     {
58         if (list->fd > 2)                  /* avoid closing stdout/stderr */
59             close (list->fd);              
60         free (list->fname);
61         list1 = list->next;
62         free (list);
63     }
64     file_mask_list = NULL;
65 }
66
67 void gw_log_level (unsigned level_a)
68 {
69     level = level_a;
70 }
71
72 void gw_log_session (int session_a)
73 {
74     session = session_a;
75 }
76
77 int gw_log_file (unsigned level_a, const char *fname_a)
78 {
79     struct file_mask **listp, *new_file_mask;
80     listp = &file_mask_list;
81
82     /* go through file mask list and close files already associated */
83     /* on new level */
84     while (*listp)
85     {
86         if (!((*listp)->mask &= ~level_a)) /* any levels left on this one? */
87         {
88             if ((*listp)->fd > 2)          /* close if not stdout/stderr */
89                 close ((*listp)->fd);      
90             free ((*listp)->fname);
91             *listp = (*listp)->next;
92         }
93         listp = &(*listp)->next;
94     }
95     if (!fname_a)                          /* stderr? */
96         return 0;                          /* stderr doesn't appear on list */
97     new_file_mask = malloc (sizeof(*new_file_mask));
98     if (!new_file_mask)
99         return -1;
100     new_file_mask->mask = level_a;
101     new_file_mask->next = file_mask_list;
102     file_mask_list = new_file_mask;
103     if (!(file_mask_list->fname = gw_strdup (fname_a)))
104         return -1;
105     if (*fname_a == '\0')                  /* stdout? */
106         new_file_mask->fd = 1;            
107     else                                   /* no, open as usual */
108     {
109         new_file_mask->fd = open (fname_a, O_WRONLY|O_CREAT|O_APPEND, 0666);
110         if (new_file_mask->fd == -1)
111             return -1;
112     }
113     return 0;
114 }
115
116 int gw_log (unsigned level_a, const char *event_type, const char *format, ...)
117 {
118     static char emit_str[2048];
119     struct file_mask *list;
120     va_list ap;
121     unsigned e_level = level_a & level;
122     int count;
123     int err = 0;
124     time_t time_now;
125     char *cp;
126
127     if (!e_level)                          /* any effective level(s)? */      
128         return 0;
129
130     va_start (ap, format);
131     time (&time_now);
132     sprintf (emit_str, "%s %d %s %d %s ", app_name, session,
133              ctime (&time_now), e_level, event_type);
134     if ((cp = strchr (emit_str, '\n')))    /* remove \n from ctime-str */
135         *cp = ' ';
136     count = strlen (emit_str);
137     vsprintf (emit_str+count, format, ap);
138     strcat (emit_str, "\n");
139     count = strlen (emit_str);
140
141     /* go through file mask list... */
142     for (list = file_mask_list; list; list = list->next)
143         if (list->mask & e_level)          /* output this one? */
144         {
145             e_level &= ~list->mask;        /* remove from effective level */
146             if (write (list->fd, emit_str, count) != count)
147                 err = 1;
148         }
149     if (e_level)                           /* bits left on effective level? */
150         write (2, emit_str, count);
151     va_end (ap);
152     return err;
153 }