1 /*
2 * (c) Copyright 1992, 1993 by Panagiotis Tsirigotis
3 * All rights reserved. The file named COPYRIGHT specifies the terms
4 * and conditions for redistribution.
5 */
6
7
8 #include "config.h"
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <stdarg.h>
12 #include <fcntl.h>
13 #include <time.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <unistd.h>
17 #include "config.h"
18 #ifndef NO_SYSLOG
19 #include <syslog.h>
20 #else
21 #define LOG_ALERT 0
22 #endif
23
24 #include "sio.h"
25 #include "str.h"
26 #include "xlog.h"
27 #include "filelog.h"
28
29 static int filelog_init(xlog_s *, va_list) ;
30 static void filelog_fini(xlog_s *) ;
31 static int filelog_control(xlog_s *, xlog_cmd_e, va_list) ;
32 static int filelog_write(xlog_s *, const char buf[], int, int, va_list) ;
33 static int filelog_parms(xlog_e, va_list) ;
34 static int limit_checks(const xlog_s *) ;
35
36 struct xlog_ops __xlog_filelog_ops =
37 {
38 filelog_init,
39 filelog_fini,
40 filelog_write,
41 filelog_control,
42 filelog_parms
43 } ;
44
45
filelog_init(xlog_s * xp,va_list ap)46 static int filelog_init( xlog_s *xp, va_list ap )
47 {
48 int fd ;
49 struct filelog_s *flp ;
50 char *filename;
51 int flags;
52
53 filename = va_arg(ap, char *);
54 flags = va_arg(ap, int);
55
56 flp = NEW( struct filelog_s ) ;
57 if ( flp == NULL )
58 return( XLOG_ENOMEM ) ;
59
60 if ( flags & O_CREAT )
61 fd = open( filename, flags, va_arg( ap, int ) ) ;
62 else
63 fd = open( filename, flags ) ;
64
65 if ( fd == -1 )
66 {
67 free( flp ) ;
68 return( XLOG_EOPEN ) ;
69 }
70
71 FILELOG_DISABLE_SIZE_CONTROL( flp ) ;
72 (void) Sbuftype( fd, SIO_LINEBUF ) ;
73 flp->fl_fd = fd ;
74 flp->fl_state = FL_OPEN ;
75 xp->xl_data = flp ;
76 return( XLOG_ENOERROR ) ;
77 }
78
79
filelog_fini(xlog_s * xp)80 static void filelog_fini( xlog_s *xp )
81 {
82 struct filelog_s *flp = FILELOG( xp ) ;
83
84 if ( flp->fl_state != FL_CLOSED )
85 {
86 (void) Sclose( flp->fl_fd ) ;
87 flp->fl_state = FL_CLOSED ;
88 }
89 free( flp ) ;
90 xp->xl_data = NULL ;
91 }
92
93
filelog_control(xlog_s * xp,xlog_cmd_e cmd,va_list ap)94 static int filelog_control( xlog_s *xp, xlog_cmd_e cmd, va_list ap )
95 {
96 struct stat st ;
97 struct filelog_s *flp = FILELOG( xp ) ;
98 int status = XLOG_ENOERROR ;
99
100 if ( flp->fl_state == FL_ERROR )
101 return( flp->fl_error ) ;
102
103 switch ( cmd )
104 {
105 case XLOG_GETFD:
106 if ( flp->fl_state == FL_OPEN )
107 *va_arg( ap, int * ) = flp->fl_fd ;
108 else
109 status = XLOG_ENOERROR ;
110 break ;
111
112 case XLOG_LIMITS:
113 flp->fl_soft_limit = va_arg( ap, unsigned ) ;
114 flp->fl_hard_limit = va_arg( ap, unsigned ) ;
115 flp->fl_issued_warning = FALSE ;
116 FILELOG_ENABLE_SIZE_CONTROL( flp ) ;
117 flp->fl_state = FL_OPEN ;
118 /* FALL THROUGH */
119
120 case XLOG_SIZECHECK:
121 if ( ! FILELOG_SIZE_CONTROL( flp ) )
122 break ;
123 if ( fstat( flp->fl_fd, &st ) == -1 )
124 {
125 FILELOG_DISABLE_SIZE_CONTROL( flp ) ;
126 flp->fl_state = FL_ERROR ;
127 flp->fl_error = status = XLOG_EFSTAT ;
128 }
129 else
130 {
131 flp->fl_size = st.st_size ;
132 if ( flp->fl_size > flp->fl_soft_limit )
133 status = limit_checks( xp ) ;
134 }
135 break ;
136 case XLOG_LINK:
137 case XLOG_CALLBACK:
138 case XLOG_GETFLAG:
139 case XLOG_SETFLAG:
140 case XLOG_LEVEL:
141 case XLOG_FACILITY:
142 case XLOG_PREEXEC:
143 case XLOG_POSTEXEC:
144 break;
145 }
146 return( status ) ;
147 }
148
149
limit_checks(const xlog_s * xp)150 static int limit_checks( const xlog_s *xp )
151 {
152 struct filelog_s *flp = FILELOG( xp ) ;
153 char buf[ 100 ] ;
154
155 if ( ! flp->fl_issued_warning )
156 {
157 if ( xp->xl_use != NULL )
158 xlog_write( (xlog_h) xp->xl_use, buf,
159 strx_nprint( buf, sizeof( buf ),
160 "soft limit exceeded on '%s'", xp->xl_id ),
161 XLOG_NOFLAGS, LOG_ALERT ) ;
162 flp->fl_issued_warning = TRUE ;
163 }
164
165 if ( flp->fl_size <= flp->fl_hard_limit )
166 return( XLOG_ENOERROR ) ;
167
168 if ( xp->xl_use != NULL )
169 xlog_write( (xlog_h) xp->xl_use, buf,
170 strx_nprint( buf, sizeof( buf ),
171 "hard limit exceeded on '%s'; log closed", xp->xl_id ),
172 XLOG_NOFLAGS, LOG_ALERT ) ;
173 flp->fl_state = FL_ERROR ;
174 return( XLOG_ESIZE ) ;
175 }
176
177
filelog_write(xlog_s * xp,const char buf[],int len,int flags,va_list ap)178 static int filelog_write( xlog_s *xp, const char buf[], int len, int flags,
179 va_list ap )
180 {
181 struct filelog_s *flp = FILELOG( xp ) ;
182 int action_flags = ( xp->xl_flags | flags ) ;
183 int msglen = 0 ;
184 int percent_m_pos = 0 ;
185 int cc ;
186 int status ;
187 time_t current_time ;
188 struct tm *tmp ;
189
190 if ( flp->fl_state != FL_OPEN )
191 return( flp->fl_error ) ;
192
193 (void) time( ¤t_time ) ;
194 tmp = localtime( ¤t_time ) ;
195 cc = Sprint( flp->fl_fd, "%02d/%d/%d@%02d:%02d:%02d",
196 tmp->tm_year%100, tmp->tm_mon+1, tmp->tm_mday,
197 tmp->tm_hour, tmp->tm_min, tmp->tm_sec ) ;
198 if ( cc == SIO_ERR )
199 return XLOG_EWRITE;
200
201 msglen += cc ;
202
203 if ( action_flags & XLOG_PRINT_ID )
204 {
205 cc = Sprint( flp->fl_fd, " %s", xp->xl_id ) ;
206 if ( cc == SIO_ERR ) {
207 flp->fl_size += msglen ;
208 return XLOG_EWRITE;
209 }
210 msglen += cc ;
211 }
212
213 if ( action_flags & XLOG_PRINT_PID )
214 {
215 cc = Sprint( flp->fl_fd, "[%d]", getpid() ) ;
216 if ( cc == SIO_ERR ) {
217 flp->fl_size += msglen ;
218 return XLOG_EWRITE;
219 }
220 msglen += cc ;
221 }
222
223 cc = Sprint( flp->fl_fd, ": " ) ;
224 if ( cc == SIO_ERR ) {
225 flp->fl_size += msglen ;
226 return XLOG_EWRITE;
227 }
228 msglen += cc ;
229
230 if ( ( action_flags & XLOG_NO_ERRNO ) ||
231 ( percent_m_pos = __xlog_add_errno( buf, len ) ) == -1 )
232 {
233 cc = Swrite( flp->fl_fd, buf, len ) ;
234 if ( cc == SIO_ERR ) {
235 flp->fl_size += msglen ;
236 return XLOG_EWRITE;
237 }
238 msglen += cc ;
239 }
240 else
241 {
242 char errno_buf[ 100 ] ;
243 unsigned size = sizeof( errno_buf ) ;
244 char *ep ;
245
246 /*
247 * The reason for the repetition of "msglen += cc ;" is that
248 * in the future we may want to check cc for SIO_ERR
249 */
250 ep = __xlog_explain_errno( errno_buf, &size ) ;
251 cc = Swrite( flp->fl_fd, buf, percent_m_pos ) ;
252 if ( cc == SIO_ERR ) {
253 flp->fl_size += msglen ;
254 return XLOG_EWRITE;
255 }
256 msglen += cc ;
257 cc = Swrite( flp->fl_fd, ep, size ) ;
258 if ( cc == SIO_ERR ) {
259 flp->fl_size += msglen ;
260 return XLOG_EWRITE;
261 }
262 msglen += cc ;
263 cc = Swrite( flp->fl_fd, buf+percent_m_pos+2,
264 len-percent_m_pos-2 ) ;
265 if ( cc == SIO_ERR ) {
266 flp->fl_size += msglen ;
267 return XLOG_EWRITE;
268 }
269 msglen += cc ;
270 }
271 /*
272 * Writing a newline will cause a buffer flush since we asked for
273 * line-buffered output
274 */
275 if ( Sputchar( flp->fl_fd, '\n' ) != SIO_ERR )
276 msglen++ ;
277
278 /*
279 * NOTE: we don't check if XLOG_NO_SIZECHECK is set in xp->xl_flags
280 * because size control is off by default and in order to
281 * be enabled XLOG_LIMITS must be used which overrides xp->xl_flags
282 */
283 if ( ! FILELOG_SIZE_CONTROL( flp ) || ( flags & XLOG_NO_SIZECHECK ) )
284 return( XLOG_ENOERROR ) ;
285
286 flp->fl_size += msglen ;
287 if ( flp->fl_size <= flp->fl_soft_limit ||
288 ( status = limit_checks( xp ) ) == XLOG_ENOERROR )
289 return( XLOG_ENOERROR ) ;
290
291 flp->fl_state = FL_SIZE ;
292 return( status ) ;
293 }
294
295
filelog_parms(xlog_e type,va_list ap)296 static int filelog_parms( xlog_e type, va_list ap)
297 {
298 return( XLOG_ENOERROR ) ;
299 }
300
301