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( &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 
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