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