Test programs not build on 'make all'.
[egate.git] / res+log / gw-log.c
1 /*
2  * Copyright (c) 1995, the EUROPAGATE consortium (see below).
3  *
4  * The EUROPAGATE consortium members are:
5  *
6  *    University College Dublin
7  *    Danmarks Teknologiske Videnscenter
8  *    An Chomhairle Leabharlanna
9  *    Consejo Superior de Investigaciones Cientificas
10  *
11  * Permission to use, copy, modify, distribute, and sell this software and
12  * its documentation, in whole or in part, for any purpose, is hereby granted,
13  * provided that:
14  *
15  * 1. This copyright and permission notice appear in all copies of the
16  * software and its documentation. Notices of copyright or attribution
17  * which appear at the beginning of any file must remain unchanged.
18  *
19  * 2. The names of EUROPAGATE or the project partners may not be used to
20  * endorse or promote products derived from this software without specific
21  * prior written permission.
22  *
23  * 3. Users of this software (implementors and gateway operators) agree to
24  * inform the EUROPAGATE consortium of their use of the software. This
25  * information will be used to evaluate the EUROPAGATE project and the
26  * software, and to plan further developments. The consortium may use
27  * the information in later publications.
28  * 
29  * 4. Users of this software agree to make their best efforts, when
30  * documenting their use of the software, to acknowledge the EUROPAGATE
31  * consortium, and the role played by the software in their work.
32  *
33  * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
34  * EXPRESS, IMPLIED, OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
35  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
36  * IN NO EVENT SHALL THE EUROPAGATE CONSORTIUM OR ITS MEMBERS BE LIABLE
37  * FOR ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF
38  * ANY KIND, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
39  * OR PROFITS, WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND
40  * ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
41  * USE OR PERFORMANCE OF THIS SOFTWARE.
42  *
43  */
44 /*
45  * Implementation of logging facilities.
46  *
47  * Europagate, 1994-1995.
48  *
49  * $Log: gw-log.c,v $
50  * Revision 1.11  1995/11/09 09:54:28  adam
51  * More readable logging format.
52  *
53  * Revision 1.10  1995/05/16  09:40:48  adam
54  * LICENSE.
55  *
56  * Revision 1.9  1995/04/19  12:12:06  adam
57  * Resource system uses only one log debug level.
58  *
59  * Revision 1.8  1995/04/17  09:36:16  adam
60  * Minor changes.
61  *
62  * Revision 1.7  1995/04/10  13:20:25  adam
63  * Use gettimeofday(2) instead of time(2) to get log time in milliseconds.
64  *
65  * Revision 1.6  1995/03/28  08:01:51  adam
66  * Bug fix: GW_LOG_ERRNO.
67  *
68  * Revision 1.5  1995/03/27  12:51:10  adam
69  * New log level in use: GW_LOG_ERRNO.
70  *
71  * Revision 1.4  1995/02/23  08:32:22  adam
72  * Changed header.
73  *
74  * Revision 1.2  1995/02/17  17:06:56  adam
75  * Remove everything before '/' in app_name. Use compact date format.
76  *
77  * Revision 1.1.1.1  1995/02/09  17:27:12  adam
78  * Initial version of email gateway under CVS control.
79  *
80  * Initial:       Dec  7, 94 (Adam Dickmeiss)
81  */
82
83 #include <stdio.h>
84 #include <stdlib.h>
85 #include <string.h>
86 #include <stdarg.h>
87 #include <fcntl.h>
88 #include <sys/time.h>
89 #include <unistd.h>
90 #include <time.h>
91 #include <errno.h>
92
93 #include <gw-log.h>
94
95 static char *app_name = NULL;
96 static unsigned level = GW_LOG_DEFAULT;
97 static int session = 0;
98
99 struct file_mask {
100     unsigned mask;           /* level mask for this file entry */
101     int fd;                  /* file descriptor for this file */
102     char *fname;             /* name of file ("" if stdout) */
103     struct file_mask *next;  /* next file in chain */
104 };
105
106 struct file_mask *file_mask_list = NULL;
107
108 char *gw_strdup (const char *s)
109 {
110     char *n = malloc (strlen(s)+1);
111     if (n)
112         strcpy (n, s);
113     return n;
114 }
115
116 void gw_log_init (const char *app_name_a)
117 {
118     struct file_mask *list, *list1;
119     const char *cp;
120
121     if ((cp = strrchr (app_name_a, '/')))
122         app_name = gw_strdup (cp+1);
123     else
124         app_name = gw_strdup (app_name_a);
125     level = GW_LOG_DEFAULT;
126     session = 0;
127
128     /* clean up all output file masks... */
129     for (list = file_mask_list; list; list = list1)
130     {
131         if (list->fd > 2)                  /* avoid closing stdout/stderr */
132             close (list->fd);              
133         free (list->fname);
134         list1 = list->next;
135         free (list);
136     }
137     file_mask_list = NULL;
138 }
139
140 void gw_log_level (unsigned level_a)
141 {
142     level = level_a;
143 }
144
145 void gw_log_session (int session_a)
146 {
147     session = session_a;
148 }
149
150 int gw_log_file (unsigned level_a, const char *fname_a)
151 {
152     struct file_mask **listp, *new_file_mask;
153     listp = &file_mask_list;
154
155     /* go through file mask list and close files already associated */
156     /* on new level */
157     while (*listp)
158     {
159         if (!((*listp)->mask &= ~level_a)) /* any levels left on this one? */
160         {
161             if ((*listp)->fd > 2)          /* close if not stdout/stderr */
162                 close ((*listp)->fd);      
163             free ((*listp)->fname);
164             *listp = (*listp)->next;
165         }
166         listp = &(*listp)->next;
167     }
168     if (!fname_a)                          /* stderr? */
169         return 0;                          /* stderr doesn't appear on list */
170     new_file_mask = malloc (sizeof(*new_file_mask));
171     if (!new_file_mask)
172         return -1;
173     new_file_mask->mask = level_a;
174     new_file_mask->next = file_mask_list;
175     file_mask_list = new_file_mask;
176     if (!(file_mask_list->fname = gw_strdup (fname_a)))
177         return -1;
178     if (*fname_a == '\0')                  /* stdout? */
179         new_file_mask->fd = 1;            
180     else                                   /* no, open as usual */
181     {
182         new_file_mask->fd = open (fname_a, O_WRONLY|O_CREAT|O_APPEND, 0666);
183         if (new_file_mask->fd == -1)
184             return -1;
185     }
186     return 0;
187 }
188
189 int gw_log (unsigned level_a, const char *event_type, const char *format, ...)
190 {
191     static char emit_str[4096];
192     struct file_mask *list;
193     struct timeval tv;
194     struct timezone tz;
195     va_list ap;
196     unsigned e_level = level_a & level;
197     int count;
198     int err = 0;
199     struct tm tms;
200     char *cp;
201
202     if (!e_level)                          /* any effective level(s)? */      
203         return 0;
204
205     va_start (ap, format);
206     gettimeofday (&tv, &tz);
207
208     memcpy (&tms, localtime (&tv.tv_sec), sizeof(tms));
209     sprintf (emit_str, "%s %d %02d%02d%02d %02d%02d%02d %03d %d %s ",
210              app_name, session,
211              tms.tm_year, 1+tms.tm_mon, tms.tm_mday,
212              tms.tm_hour, tms.tm_min, tms.tm_sec,
213              (int) (tv.tv_usec/1000),
214              e_level, event_type);
215     if ((cp = strchr (emit_str, '\n')))    /* remove \n from ctime-str */
216         *cp = ' ';
217     count = strlen (emit_str);
218     vsprintf (emit_str+count, format, ap);
219     if (level_a & GW_LOG_ERRNO)
220     {
221         strcat (emit_str, ": ");
222         strcat (emit_str, strerror (errno));
223     }
224     strcat (emit_str, "\n");
225     count = strlen (emit_str);
226
227     /* go through file mask list... */
228     for (list = file_mask_list; list; list = list->next)
229         if (list->mask & e_level)          /* output this one? */
230         {
231             e_level &= ~list->mask;        /* remove from effective level */
232             if (write (list->fd, emit_str, count) != count)
233                 err = 1;
234         }
235     if (e_level)                           /* bits left on effective level? */
236         write (2, emit_str, count);
237     va_end (ap);
238     return err;
239 }