]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/log.c
Load cups into easysw/current.
[thirdparty/cups.git] / scheduler / log.c
CommitLineData
ef416fc2 1/*
2abf387c 2 * "$Id: log.c 6027 2006-10-11 21:04:58Z mike $"
ef416fc2 3 *
4 * Log file routines for the Common UNIX Printing System (CUPS).
5 *
a74454a7 6 * Copyright 1997-2006 by Easy Software Products, all rights reserved.
ef416fc2 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 USA
19 *
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * Contents:
25 *
a74454a7 26 * cupsdGetDateTime() - Returns a pointer to a date/time string.
27 * cupsdLogMessage() - Log a message to the error log file.
28 * cupsdLogPage() - Log a page to the page log file.
29 * cupsdLogRequest() - Log an HTTP request in Common Log Format.
30 * check_log_file() - Open/rotate a log file if it needs it.
ef416fc2 31 */
32
33/*
34 * Include necessary headers...
35 */
36
37#include "cupsd.h"
38#include <stdarg.h>
b423cd4c 39#include <syslog.h>
ef416fc2 40
41
42/*
43 * Local functions...
44 */
45
46static int check_log_file(cups_file_t **, const char *);
47
48
49/*
50 * 'cupsdGetDateTime()' - Returns a pointer to a date/time string.
51 */
52
53char * /* O - Date/time string */
54cupsdGetDateTime(time_t t) /* I - Time value */
55{
56 struct tm *date; /* Date/time value */
57 static time_t last_time = -1; /* Last time value */
58 static char s[1024]; /* Date/time string */
59 static const char * const months[12] =/* Months */
60 {
61 "Jan",
62 "Feb",
63 "Mar",
64 "Apr",
65 "May",
66 "Jun",
67 "Jul",
68 "Aug",
69 "Sep",
70 "Oct",
71 "Nov",
72 "Dec"
73 };
74
75
76 if (t != last_time)
77 {
78 last_time = t;
79
80 /*
81 * Get the date and time from the UNIX time value, and then format it
82 * into a string. Note that we *can't* use the strftime() function since
83 * it is localized and will seriously confuse automatic programs if the
84 * month names are in the wrong language!
85 *
86 * Also, we use the "timezone" variable that contains the current timezone
87 * offset from GMT in seconds so that we are reporting local time in the
88 * log files. If you want GMT, set the TZ environment variable accordingly
89 * before starting the scheduler.
90 *
91 * (*BSD and Darwin store the timezone offset in the tm structure)
92 */
93
94 date = localtime(&t);
95
96 snprintf(s, sizeof(s), "[%02d/%s/%04d:%02d:%02d:%02d %+03ld%02ld]",
97 date->tm_mday, months[date->tm_mon], 1900 + date->tm_year,
98 date->tm_hour, date->tm_min, date->tm_sec,
99#ifdef HAVE_TM_GMTOFF
100 date->tm_gmtoff / 3600, (date->tm_gmtoff / 60) % 60);
101#else
102 timezone / 3600, (timezone / 60) % 60);
103#endif /* HAVE_TM_GMTOFF */
104 }
105
106 return (s);
107}
108
109
110/*
111 * 'cupsdLogMessage()' - Log a message to the error log file.
112 */
113
114int /* O - 1 on success, 0 on error */
115cupsdLogMessage(int level, /* I - Log level */
116 const char *message, /* I - printf-style message string */
117 ...) /* I - Additional args as needed */
118{
119 int len; /* Length of message */
120 va_list ap; /* Argument pointer */
121 static const char levels[] = /* Log levels... */
122 {
123 ' ',
124 'X',
125 'A',
126 'C',
127 'E',
128 'W',
129 'N',
130 'I',
131 'D',
132 'd'
133 };
134#ifdef HAVE_VSYSLOG
135 static const int syslevels[] = /* SYSLOG levels... */
136 {
137 0,
138 LOG_EMERG,
139 LOG_ALERT,
140 LOG_CRIT,
141 LOG_ERR,
142 LOG_WARNING,
143 LOG_NOTICE,
144 LOG_INFO,
145 LOG_DEBUG,
146 LOG_DEBUG
147 };
148#endif /* HAVE_VSYSLOG */
149 static int linesize = 0; /* Size of line for output file */
150 static char *line = NULL; /* Line for output file */
151
152
153 /*
154 * See if we want to log this message...
155 */
156
157 if (level > LogLevel || !ErrorLog)
158 return (1);
159
160#ifdef HAVE_VSYSLOG
161 /*
162 * See if we are logging errors via syslog...
163 */
164
165 if (!strcmp(ErrorLog, "syslog"))
166 {
167 va_start(ap, message);
168 vsyslog(syslevels[level], message, ap);
169 va_end(ap);
170
171 return (1);
172 }
173#endif /* HAVE_VSYSLOG */
174
175 /*
176 * Not using syslog; check the log file...
177 */
178
179 if (!check_log_file(&ErrorFile, ErrorLog))
180 return (0);
181
182 /*
183 * Print the log level and date/time...
184 */
185
186 cupsFilePrintf(ErrorFile, "%c %s ", levels[level], cupsdGetDateTime(time(NULL)));
187
188 /*
189 * Allocate the line buffer as needed...
190 */
191
192 if (!linesize)
193 {
194 linesize = 8192;
195 line = malloc(linesize);
196
197 if (!line)
198 {
199 cupsFilePrintf(ErrorFile,
200 "ERROR: Unable to allocate memory for line - %s\n",
201 strerror(errno));
202 cupsFileFlush(ErrorFile);
203
204 return (0);
205 }
206 }
207
208 /*
209 * Format the log message...
210 */
211
212 va_start(ap, message);
213 len = vsnprintf(line, linesize, message, ap);
214 va_end(ap);
215
216 /*
217 * Resize the buffer as needed...
218 */
219
220 if (len >= linesize)
221 {
222 len ++;
223
224 if (len < 8192)
225 len = 8192;
226 else if (len > 65536)
227 len = 65536;
228
229 line = realloc(line, len);
230
231 if (line)
232 linesize = len;
233 else
234 {
235 cupsFilePrintf(ErrorFile,
236 "ERROR: Unable to allocate memory for line - %s\n",
237 strerror(errno));
238 cupsFileFlush(ErrorFile);
239
240 return (0);
241 }
242
243 va_start(ap, message);
244 len = vsnprintf(line, linesize, message, ap);
245 va_end(ap);
246 }
247
248 if (len >= linesize)
249 len = linesize - 1;
250
251 /*
252 * Then the log message...
253 */
254
255 cupsFilePuts(ErrorFile, line);
256
257 /*
258 * Then a newline...
259 */
260
261 if (len > 0 && line[len - 1] != '\n')
262 cupsFilePutChar(ErrorFile, '\n');
263
264 /*
265 * Flush the line to the file and return...
266 */
267
268 cupsFileFlush(ErrorFile);
269
270 return (1);
271}
272
273
274/*
275 * 'cupsdLogPage()' - Log a page to the page log file.
276 */
277
278int /* O - 1 on success, 0 on error */
279cupsdLogPage(cupsd_job_t *job, /* I - Job being printed */
280 const char *page) /* I - Page being printed */
281{
282 ipp_attribute_t *billing, /* job-billing attribute */
283 *hostname; /* job-originating-host-name attribute */
284
285
286 billing = ippFindAttribute(job->attrs, "job-billing", IPP_TAG_ZERO);
287 hostname = ippFindAttribute(job->attrs, "job-originating-host-name",
288 IPP_TAG_ZERO);
289
290#ifdef HAVE_VSYSLOG
291 /*
292 * See if we are logging pages via syslog...
293 */
294
295 if (!strcmp(PageLog, "syslog"))
296 {
297 syslog(LOG_INFO, "PAGE %s %s %d %s %s %s", job->printer->name,
298 job->username ? job->username : "-",
299 job->id, page, billing ? billing->values[0].string.text : "-",
300 hostname->values[0].string.text);
301
302 return (1);
303 }
304#endif /* HAVE_VSYSLOG */
305
306 /*
307 * Not using syslog; check the log file...
308 */
309
310 if (!check_log_file(&PageFile, PageLog))
311 return (0);
312
313 /*
314 * Print a page log entry of the form:
315 *
316 * printer job-id user [DD/MON/YYYY:HH:MM:SS +TTTT] page num-copies \
317 * billing hostname
318 */
319
320 cupsFilePrintf(PageFile, "%s %s %d %s %s %s %s\n", job->printer->name,
321 job->username ? job->username : "-",
322 job->id, cupsdGetDateTime(time(NULL)), page,
323 billing ? billing->values[0].string.text : "-",
324 hostname->values[0].string.text);
325 cupsFileFlush(PageFile);
326
327 return (1);
328}
329
330
331/*
332 * 'cupsdLogRequest()' - Log an HTTP request in Common Log Format.
333 */
334
335int /* O - 1 on success, 0 on error */
336cupsdLogRequest(cupsd_client_t *con, /* I - Request to log */
337 http_status_t code) /* I - Response code */
338{
339 static const char * const states[] = /* HTTP client states... */
340 {
341 "WAITING",
342 "OPTIONS",
343 "GET",
344 "GET",
345 "HEAD",
346 "POST",
347 "POST",
348 "POST",
349 "PUT",
350 "PUT",
351 "DELETE",
352 "TRACE",
353 "CLOSE",
354 "STATUS"
355 };
356
357
358#ifdef HAVE_VSYSLOG
359 /*
360 * See if we are logging accesses via syslog...
361 */
362
363 if (!strcmp(AccessLog, "syslog"))
364 {
2abf387c 365 syslog(LOG_INFO,
366 "REQUEST %s - %s \"%s %s HTTP/%d.%d\" %d " CUPS_LLFMT " %s %s\n",
ef416fc2 367 con->http.hostname, con->username[0] != '\0' ? con->username : "-",
368 states[con->operation], con->uri,
369 con->http.version / 100, con->http.version % 100,
2abf387c 370 code, CUPS_LLCAST con->bytes,
371 con->request ?
372 ippOpString(con->request->request.op.operation_id) : "-",
373 con->response ?
374 ippErrorString(con->response->request.status.status_code) : "-");
ef416fc2 375
376 return (1);
377 }
378#endif /* HAVE_VSYSLOG */
379
380 /*
381 * Not using syslog; check the log file...
382 */
383
384 if (!check_log_file(&AccessFile, AccessLog))
385 return (0);
386
387 /*
388 * Write a log of the request in "common log format"...
389 */
390
391 cupsFilePrintf(AccessFile,
392 "%s - %s %s \"%s %s HTTP/%d.%d\" %d " CUPS_LLFMT " %s %s\n",
393 con->http.hostname, con->username[0] != '\0' ? con->username : "-",
394 cupsdGetDateTime(con->start), states[con->operation], con->uri,
395 con->http.version / 100, con->http.version % 100,
396 code, CUPS_LLCAST con->bytes,
397 con->request ?
398 ippOpString(con->request->request.op.operation_id) : "-",
399 con->response ?
400 ippErrorString(con->response->request.status.status_code) :
401 "-");
402
403 cupsFileFlush(AccessFile);
404
405 return (1);
406}
407
408
409/*
410 * 'check_log_file()' - Open/rotate a log file if it needs it.
411 */
412
413static int /* O - 1 if log file open */
414check_log_file(cups_file_t **lf, /* IO - Log file */
415 const char *logname) /* I - Log filename */
416{
417 char backname[1024], /* Backup log filename */
418 filename[1024], /* Formatted log filename */
419 *ptr; /* Pointer into filename */
420
421
422 /*
423 * See if we have a log file to check...
424 */
425
426 if (!lf || !logname || !logname[0])
427 return (1);
428
429 /*
430 * Format the filename as needed...
431 */
432
a74454a7 433 if (!*lf ||
434 (strncmp(logname, "/dev/", 5) && cupsFileTell(*lf) > MaxLogSize &&
435 MaxLogSize > 0))
ef416fc2 436 {
437 /*
438 * Handle format strings...
439 */
440
441 filename[sizeof(filename) - 1] = '\0';
442
443 if (logname[0] != '/')
444 {
445 strlcpy(filename, ServerRoot, sizeof(filename));
446 strlcat(filename, "/", sizeof(filename));
447 }
448 else
449 filename[0] = '\0';
450
451 for (ptr = filename + strlen(filename);
452 *logname && ptr < (filename + sizeof(filename) - 1);
453 logname ++)
454 if (*logname == '%')
455 {
456 /*
457 * Format spec...
458 */
459
460 logname ++;
461 if (*logname == 's')
462 {
463 /*
464 * Insert the server name...
465 */
466
467 strlcpy(ptr, ServerName, sizeof(filename) - (ptr - filename));
468 ptr += strlen(ptr);
469 }
470 else
471 {
472 /*
473 * Otherwise just insert the character...
474 */
475
476 *ptr++ = *logname;
477 }
478 }
479 else
480 *ptr++ = *logname;
481
482 *ptr = '\0';
483 }
484
485 /*
486 * See if the log file is open...
487 */
488
489 if (!*lf)
490 {
491 /*
492 * Nope, open the log file...
493 */
494
495 if ((*lf = cupsFileOpen(filename, "a")) == NULL)
496 {
497 syslog(LOG_ERR, "Unable to open log file \"%s\" - %s", filename,
498 strerror(errno));
499
500 return (0);
501 }
502
503 if (strncmp(filename, "/dev/", 5))
504 {
505 /*
506 * Change ownership and permissions of non-device logs...
507 */
508
509 fchown(cupsFileNumber(*lf), RunUser, Group);
510 fchmod(cupsFileNumber(*lf), LogFilePerm);
511 }
512 }
513
514 /*
515 * Do we need to rotate the log?
516 */
517
a74454a7 518 if (strncmp(logname, "/dev/", 5) && cupsFileTell(*lf) > MaxLogSize &&
519 MaxLogSize > 0)
ef416fc2 520 {
521 /*
522 * Rotate log file...
523 */
524
525 cupsFileClose(*lf);
526
527 strcpy(backname, filename);
528 strlcat(backname, ".O", sizeof(backname));
529
530 unlink(backname);
531 rename(filename, backname);
532
533 if ((*lf = cupsFileOpen(filename, "a")) == NULL)
534 {
535 syslog(LOG_ERR, "Unable to open log file \"%s\" - %s", filename,
536 strerror(errno));
537
538 return (0);
539 }
540
a74454a7 541 /*
542 * Change ownership and permissions of non-device logs...
543 */
ef416fc2 544
a74454a7 545 fchown(cupsFileNumber(*lf), RunUser, Group);
546 fchmod(cupsFileNumber(*lf), LogFilePerm);
ef416fc2 547 }
548
549 return (1);
550}
551
552
553/*
2abf387c 554 * End of "$Id: log.c 6027 2006-10-11 21:04:58Z mike $".
ef416fc2 555 */