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