1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2014 Kannel Group
5  * Copyright (c) 1998-2001 WapIT Ltd.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in
17  *    the documentation and/or other materials provided with the
18  *    distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  *    if any, must include the following acknowledgment:
22  *       "This product includes software developed by the
23  *        Kannel Group (http://www.kannel.org/)."
24  *    Alternately, this acknowledgment may appear in the software itself,
25  *    if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Kannel" and "Kannel Group" must not be used to
28  *    endorse or promote products derived from this software without
29  *    prior written permission. For written permission, please
30  *    contact org@kannel.org.
31  *
32  * 5. Products derived from this software may not be called "Kannel",
33  *    nor may "Kannel" appear in their name, without prior written
34  *    permission of the Kannel Group.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED.  IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
40  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
41  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
42  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Kannel Group.  For more information on
51  * the Kannel Group, please see <http://www.kannel.org/>.
52  *
53  * Portions of this software are based upon software originally written at
54  * WapIT Ltd., Helsinki, Finland for the Kannel project.
55  */
56 
57 /*
58  * accesslog.c - implement access logging functions
59  *
60  * see accesslog.h.
61  *
62  * Kalle Marjola 2000 for Project Kannel
63  */
64 
65 
66 #include <stdio.h>
67 #include <stdlib.h>
68 #include <errno.h>
69 #include <time.h>
70 #include <stdarg.h>
71 #include <string.h>
72 
73 #include "gwlib.h"
74 
75 static FILE *file = NULL;
76 static char filename[FILENAME_MAX + 1]; /* to allow re-open */
77 static int use_localtime;
78 static int markers = 1;     /* can be turned-off by 'access-log-clean = yes' */
79 
80 /*
81  * Reopen/rotate lock.
82  */
83 static List *writers = NULL;
84 
alog_reopen(void)85 void alog_reopen(void)
86 {
87     if (file == NULL)
88 	return;
89 
90     if (markers)
91         alog("Log ends");
92 
93     gwlist_lock(writers);
94     /* wait for writers to complete */
95     gwlist_consume(writers);
96 
97     fclose(file);
98     file = fopen(filename, "a");
99 
100     gwlist_unlock(writers);
101 
102     if (file == NULL) {
103         error(errno, "Couldn't re-open access logfile `%s'.", filename);
104     }
105     else if (markers) {
106         alog("Log begins");
107     }
108 }
109 
110 
alog_close(void)111 void alog_close(void)
112 {
113 
114     if (file != NULL) {
115         if (markers)
116             alog("Log ends");
117         gwlist_lock(writers);
118         /* wait for writers to complete */
119         gwlist_consume(writers);
120         fclose(file);
121         file = NULL;
122         gwlist_unlock(writers);
123         gwlist_destroy(writers, NULL);
124         writers = NULL;
125     }
126 }
127 
128 
alog_open(char * fname,int use_localtm,int use_markers)129 void alog_open(char *fname, int use_localtm, int use_markers)
130 {
131     FILE *f;
132 
133     use_localtime = use_localtm;
134     markers = use_markers;
135 
136     if (file != NULL) {
137         warning(0, "Opening an already opened access log");
138         alog_close();
139     }
140     if (strlen(fname) > FILENAME_MAX) {
141         error(0, "Access Log filename too long: `%s', cannot open.", fname);
142         return;
143     }
144 
145     if (writers == NULL)
146         writers = gwlist_create();
147 
148     f = fopen(fname, "a");
149     if (f == NULL) {
150         error(errno, "Couldn't open logfile `%s'.", fname);
151         return;
152     }
153     file = f;
154     strcpy(filename, fname);
155     info(0, "Started access logfile `%s'.", filename);
156     if (markers)
157         alog("Log begins");
158 }
159 
160 
alog_use_localtime(void)161 void alog_use_localtime(void)
162 {
163     use_localtime = 1;
164 }
165 
166 
alog_use_gmtime(void)167 void alog_use_gmtime(void)
168 {
169     use_localtime = 0;
170 }
171 
172 
173 #define FORMAT_SIZE (10*1024)
format(char * buf,const char * fmt)174 static void format(char *buf, const char *fmt)
175 {
176     time_t t;
177     struct tm tm;
178     char *p, prefix[1024];
179 
180     p = prefix;
181 
182     if (markers) {
183         time(&t);
184         if (use_localtime)
185             tm = gw_localtime(t);
186         else
187             tm = gw_gmtime(t);
188 
189         sprintf(p, "%04d-%02d-%02d %02d:%02d:%02d ",
190                 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
191                 tm.tm_hour, tm.tm_min, tm.tm_sec);
192     } else {
193         *p = '\0';
194     }
195 
196     if (strlen(prefix) + strlen(fmt) > FORMAT_SIZE / 2) {
197         sprintf(buf, "%s <OUTPUT message too long>\n", prefix);
198         return;
199     }
200     sprintf(buf, "%s%s\n", prefix, fmt);
201 }
202 
203 
204 /* XXX should we also log automatically into main log, too? */
205 
alog(const char * fmt,...)206 void alog(const char *fmt, ...)
207 {
208     char buf[FORMAT_SIZE + 1];
209     va_list args;
210 
211     if (file == NULL)
212         return;
213 
214     format(buf, fmt);
215     va_start(args, fmt);
216 
217     gwlist_lock(writers);
218     gwlist_add_producer(writers);
219     gwlist_unlock(writers);
220 
221     vfprintf(file, buf, args);
222     fflush(file);
223 
224     gwlist_remove_producer(writers);
225 
226     va_end(args);
227 }
228 
229