]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/log.c
Import cups.org releases
[thirdparty/cups.git] / scheduler / log.c
1 /*
2 * "$Id$"
3 *
4 * Log file routines for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2002 by Easy Software Products, all rights reserved.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636-3111 USA
19 *
20 * Voice: (301) 373-9603
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * Contents:
25 *
26 * GetDateTime() - Returns a pointer to a date/time string.
27 * LogMessage() - Log a message to the error log file.
28 * LogPage() - Log a page to the page log file.
29 * LogRequest() - Log an HTTP request in Common Log Format.
30 * check_log_file() - Open/rotate a log file if it needs it.
31 */
32
33 /*
34 * Include necessary headers...
35 */
36
37 #include "cupsd.h"
38 #include <stdarg.h>
39
40 #ifdef HAVE_VSYSLOG
41 # include <syslog.h>
42 #endif /* HAVE_VSYSLOG */
43
44
45 /*
46 * Local functions...
47 */
48
49 static int check_log_file(FILE **, const char *);
50
51
52 /*
53 * 'GetDateTime()' - Returns a pointer to a date/time string.
54 */
55
56 char * /* O - Date/time string */
57 GetDateTime(time_t t) /* I - Time value */
58 {
59 struct tm *date; /* Date/time value */
60 static char s[1024]; /* Date/time string */
61 static const char *months[12] =/* Months */
62 {
63 "Jan",
64 "Feb",
65 "Mar",
66 "Apr",
67 "May",
68 "Jun",
69 "Jul",
70 "Aug",
71 "Sep",
72 "Oct",
73 "Nov",
74 "Dec"
75 };
76
77
78 /*
79 * Get the date and time from the UNIX time value, and then format it
80 * into a string. Note that we *can't* use the strftime() function since
81 * it is localized and will seriously confuse automatic programs if the
82 * month names are in the wrong language!
83 *
84 * Also, we use the "timezone" variable that contains the current timezone
85 * offset from GMT in seconds so that we are reporting local time in the
86 * log files. If you want GMT, set the TZ environment variable accordingly
87 * before starting the scheduler.
88 *
89 * (*BSD and Darwin store the timezone offset in the tm structure)
90 */
91
92 date = localtime(&t);
93
94 snprintf(s, sizeof(s), "[%02d/%s/%04d:%02d:%02d:%02d %+03ld%02ld]",
95 date->tm_mday, months[date->tm_mon], 1900 + date->tm_year,
96 date->tm_hour, date->tm_min, date->tm_sec,
97 #ifdef HAVE_TM_GMTOFF
98 date->tm_gmtoff / 3600, (date->tm_gmtoff / 60) % 60);
99 #else
100 timezone / 3600, (timezone / 60) % 60);
101 #endif /* HAVE_TM_GMTOFF */
102
103 return (s);
104 }
105
106
107 /*
108 * 'LogMessage()' - Log a message to the error log file.
109 */
110
111 int /* O - 1 on success, 0 on error */
112 LogMessage(int level, /* I - Log level */
113 const char *message, /* I - printf-style message string */
114 ...) /* I - Additional args as needed */
115 {
116 int len; /* Length of message */
117 char line[1024]; /* Line for output file */
118 va_list ap; /* Argument pointer */
119 static char levels[] = /* Log levels... */
120 {
121 ' ',
122 'X',
123 'A',
124 'C',
125 'E',
126 'W',
127 'N',
128 'I',
129 'D',
130 'd'
131 };
132 #ifdef HAVE_VSYSLOG
133 static int syslevels[] = /* SYSLOG levels... */
134 {
135 0,
136 LOG_EMERG,
137 LOG_ALERT,
138 LOG_CRIT,
139 LOG_ERR,
140 LOG_WARNING,
141 LOG_NOTICE,
142 LOG_INFO,
143 LOG_DEBUG,
144 LOG_DEBUG
145 };
146 #endif /* HAVE_VSYSLOG */
147
148
149 /*
150 * See if we want to log this message...
151 */
152
153 if (level > LogLevel)
154 return (1);
155
156 #ifdef HAVE_VSYSLOG
157 /*
158 * See if we are logging errors via syslog...
159 */
160
161 if (strcmp(ErrorLog, "syslog") == 0)
162 {
163 va_start(ap, message);
164 vsyslog(syslevels[level], message, ap);
165 va_end(ap);
166
167 return (1);
168 }
169 #endif /* HAVE_VSYSLOG */
170
171 /*
172 * Not using syslog; check the log file...
173 */
174
175 if (!check_log_file(&ErrorFile, ErrorLog))
176 return (0);
177
178 /*
179 * Print the log level and date/time...
180 */
181
182 fprintf(ErrorFile, "%c %s ", levels[level], GetDateTime(time(NULL)));
183
184 /*
185 * Then the log message...
186 */
187
188 va_start(ap, message);
189 len = vsnprintf(line, sizeof(line), message, ap);
190 va_end(ap);
191
192 /*
193 * Then a newline...
194 */
195
196 fputs(line, ErrorFile);
197 if (len > 0 && line[len - 1] != '\n')
198 putc('\n', ErrorFile);
199
200 fflush(ErrorFile);
201
202 return (1);
203 }
204
205
206 /*
207 * 'LogPage()' - Log a page to the page log file.
208 */
209
210 int /* O - 1 on success, 0 on error */
211 LogPage(job_t *job, /* I - Job being printed */
212 const char *page) /* I - Page being printed */
213 {
214 ipp_attribute_t *billing; /* job-billing attribute */
215
216
217
218 billing = ippFindAttribute(job->attrs, "job-billing", IPP_TAG_ZERO);
219
220 #ifdef HAVE_VSYSLOG
221 /*
222 * See if we are logging pages via syslog...
223 */
224
225 if (strcmp(PageLog, "syslog") == 0)
226 {
227 syslog(LOG_INFO, "PAGE %s %s %d %s %s", job->printer->name, job->username,
228 job->id, page, billing ? billing->values[0].string.text : "");
229
230 return (1);
231 }
232 #endif /* HAVE_VSYSLOG */
233
234 /*
235 * Not using syslog; check the log file...
236 */
237
238 if (!check_log_file(&PageFile, PageLog))
239 return (0);
240
241 /*
242 * Print a page log entry of the form:
243 *
244 * printer job-id user [DD/MON/YYYY:HH:MM:SS +TTTT] page num-copies billing
245 */
246
247 fprintf(PageFile, "%s %s %d %s %s %s\n", job->printer->name, job->username,
248 job->id, GetDateTime(time(NULL)), page,
249 billing ? billing->values[0].string.text : "");
250 fflush(PageFile);
251
252 return (1);
253 }
254
255
256 /*
257 * 'LogRequest()' - Log an HTTP request in Common Log Format.
258 */
259
260 int /* O - 1 on success, 0 on error */
261 LogRequest(client_t *con, /* I - Request to log */
262 http_status_t code) /* I - Response code */
263 {
264 static const char *states[] = /* HTTP client states... */
265 {
266 "WAITING",
267 "OPTIONS",
268 "GET",
269 "GET",
270 "HEAD",
271 "POST",
272 "POST",
273 "POST",
274 "PUT",
275 "PUT",
276 "DELETE",
277 "TRACE",
278 "CLOSE",
279 "STATUS"
280 };
281
282
283 #ifdef HAVE_VSYSLOG
284 /*
285 * See if we are logging accesses via syslog...
286 */
287
288 if (strcmp(AccessLog, "syslog") == 0)
289 {
290 syslog(LOG_INFO, "REQUEST %s - %s \"%s %s HTTP/%d.%d\" %d %d\n",
291 con->http.hostname, con->username[0] != '\0' ? con->username : "-",
292 states[con->operation], con->uri,
293 con->http.version / 100, con->http.version % 100,
294 code, con->bytes);
295
296 return (1);
297 }
298 #endif /* HAVE_VSYSLOG */
299
300 /*
301 * Not using syslog; check the log file...
302 */
303
304 if (!check_log_file(&AccessFile, AccessLog))
305 return (0);
306
307 /*
308 * Write a log of the request in "common log format"...
309 */
310
311 fprintf(AccessFile, "%s - %s %s \"%s %s HTTP/%d.%d\" %d %d\n",
312 con->http.hostname, con->username[0] != '\0' ? con->username : "-",
313 GetDateTime(con->start), states[con->operation], con->uri,
314 con->http.version / 100, con->http.version % 100,
315 code, con->bytes);
316 fflush(AccessFile);
317
318 return (1);
319 }
320
321
322 /*
323 * 'check_log_file()' - Open/rotate a log file if it needs it.
324 */
325
326 static int /* O - 1 if log file open */
327 check_log_file(FILE **log, /* IO - Log file */
328 const char *logname) /* I - Log filename */
329 {
330 char backname[1024], /* Backup log filename */
331 filename[1024], /* Formatted log filename */
332 *ptr; /* Pointer into filename */
333
334
335 /*
336 * See if we have a log file to check...
337 */
338
339 if (log == NULL || logname == NULL || !logname[0])
340 return (1);
341
342 /*
343 * Format the filename as needed...
344 */
345
346 if (*log == NULL ||
347 (ftell(*log) > MaxLogSize && MaxLogSize > 0))
348 {
349 /*
350 * Handle format strings...
351 */
352
353 filename[sizeof(filename) - 1] = '\0';
354
355 if (logname[0] != '/')
356 {
357 strlcpy(filename, ServerRoot, sizeof(filename));
358 strlcat(filename, "/", sizeof(filename));
359 }
360 else
361 filename[0] = '\0';
362
363 for (ptr = filename + strlen(filename);
364 *logname && ptr < (filename + sizeof(filename) - 1);
365 logname ++)
366 if (*logname == '%')
367 {
368 /*
369 * Format spec...
370 */
371
372 logname ++;
373 if (*logname == 's')
374 {
375 /*
376 * Insert the server name...
377 */
378
379 strlcpy(ptr, ServerName, sizeof(filename) - (ptr - filename));
380 ptr += strlen(ptr);
381 }
382 else
383 {
384 /*
385 * Otherwise just insert the character...
386 */
387
388 *ptr++ = *logname;
389 }
390 }
391 else
392 *ptr++ = *logname;
393
394 *ptr = '\0';
395 }
396
397 /*
398 * See if the log file is open...
399 */
400
401 if (*log == NULL)
402 {
403 /*
404 * Nope, open the log file...
405 */
406
407 if ((*log = fopen(filename, "a")) == NULL)
408 return (0);
409
410 fchown(fileno(*log), User, Group);
411 fchmod(fileno(*log), LogFilePerm);
412 }
413
414 /*
415 * Do we need to rotate the log?
416 */
417
418 if (ftell(*log) > MaxLogSize && MaxLogSize > 0)
419 {
420 /*
421 * Rotate log file...
422 */
423
424 fclose(*log);
425
426 strcpy(backname, filename);
427 strlcat(backname, ".O", sizeof(backname));
428
429 unlink(backname);
430 rename(filename, backname);
431
432 if ((*log = fopen(filename, "a")) == NULL)
433 return (0);
434
435 fchown(fileno(*log), User, Group);
436 fchmod(fileno(*log), LogFilePerm);
437 }
438
439 return (1);
440 }
441
442
443 /*
444 * End of "$Id$".
445 */