Import upstream 2.3.14
[packages/xinetd.git] / libs / src / xlog / filelog.c
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
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
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
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
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
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( &current_time ) ;
194         tmp = localtime( &current_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
296 static int filelog_parms( xlog_e type, va_list ap)
297 {
298         return( XLOG_ENOERROR ) ;
299 }
300