]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/log.c
Fix clang-reported issues (<rdar://problem/15936066>)
[thirdparty/cups.git] / scheduler / log.c
CommitLineData
ef416fc2 1/*
f2d18633 2 * "$Id$"
ef416fc2 3 *
996acce8 4 * Log file routines for the CUPS scheduler.
ef416fc2 5 *
996acce8
MS
6 * Copyright 2007-2013 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
ef416fc2 8 *
996acce8
MS
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
ef416fc2 14 */
15
16/*
17 * Include necessary headers...
18 */
19
20#include "cupsd.h"
21#include <stdarg.h>
b423cd4c 22#include <syslog.h>
ef416fc2 23
24
75bd9771
MS
25/*
26 * Local globals...
27 */
28
28a463e0
MS
29static _cups_mutex_t log_mutex = _CUPS_MUTEX_INITIALIZER;
30 /* Mutex for logging */
75bd9771
MS
31static int log_linesize = 0; /* Size of line for output file */
32static char *log_line = NULL; /* Line for output file */
33
cb7f98ee
MS
34#ifdef HAVE_VSYSLOG
35static const int syslevels[] = /* SYSLOG levels... */
36 {
37 0,
38 LOG_EMERG,
39 LOG_ALERT,
40 LOG_CRIT,
41 LOG_ERR,
42 LOG_WARNING,
43 LOG_NOTICE,
44 LOG_INFO,
45 LOG_DEBUG,
46 LOG_DEBUG
47 };
48#endif /* HAVE_VSYSLOG */
49
75bd9771 50
ef416fc2 51/*
52 * Local functions...
53 */
54
005dd1eb 55static int format_log_line(const char *message, va_list ap);
ef416fc2 56
57
22c9029b
MS
58/*
59 * 'cupsdCheckLogFile()' - Open/rotate a log file if it needs it.
60 */
61
62int /* O - 1 if log file open */
63cupsdCheckLogFile(cups_file_t **lf, /* IO - Log file */
64 const char *logname) /* I - Log filename */
65{
66 char backname[1024], /* Backup log filename */
67 filename[1024], /* Formatted log filename */
68 *ptr; /* Pointer into filename */
69 const char *logptr; /* Pointer into log filename */
70
71
72 /*
73 * See if we have a log file to check...
74 */
75
76 if (!lf || !logname || !logname[0])
77 return (1);
78
79 /*
80 * Format the filename as needed...
81 */
82
83 if (!*lf ||
84 (strncmp(logname, "/dev/", 5) && cupsFileTell(*lf) > MaxLogSize &&
85 MaxLogSize > 0))
86 {
87 /*
88 * Handle format strings...
89 */
90
91 filename[sizeof(filename) - 1] = '\0';
92
93 if (logname[0] != '/')
94 {
95 strlcpy(filename, ServerRoot, sizeof(filename));
96 strlcat(filename, "/", sizeof(filename));
97 }
98 else
99 filename[0] = '\0';
100
101 for (logptr = logname, ptr = filename + strlen(filename);
102 *logptr && ptr < (filename + sizeof(filename) - 1);
103 logptr ++)
104 if (*logptr == '%')
105 {
106 /*
107 * Format spec...
108 */
109
110 logptr ++;
111 if (*logptr == 's')
112 {
113 /*
114 * Insert the server name...
115 */
116
117 strlcpy(ptr, ServerName, sizeof(filename) - (ptr - filename));
118 ptr += strlen(ptr);
119 }
120 else
121 {
122 /*
123 * Otherwise just insert the character...
124 */
125
126 *ptr++ = *logptr;
127 }
128 }
129 else
130 *ptr++ = *logptr;
131
132 *ptr = '\0';
133 }
134
135 /*
136 * See if the log file is open...
137 */
138
139 if (!*lf)
140 {
141 /*
142 * Nope, open the log file...
143 */
144
145 if ((*lf = cupsFileOpen(filename, "a")) == NULL)
146 {
147 /*
148 * If the file is in CUPS_LOGDIR then try to create a missing directory...
149 */
150
151 if (!strncmp(filename, CUPS_LOGDIR, strlen(CUPS_LOGDIR)))
152 {
153 /*
154 * Try updating the permissions of the containing log directory, using
155 * the log file permissions as a basis...
156 */
157
158 int log_dir_perm = 0300 | LogFilePerm;
159 /* LogFilePerm + owner write/search */
160 if (log_dir_perm & 0040)
161 log_dir_perm |= 0010; /* Add group search */
162 if (log_dir_perm & 0004)
163 log_dir_perm |= 0001; /* Add other search */
164
165 cupsdCheckPermissions(CUPS_LOGDIR, NULL, log_dir_perm, RunUser, Group,
166 1, -1);
167
168 *lf = cupsFileOpen(filename, "a");
169 }
170
171 if (*lf == NULL)
172 {
173 syslog(LOG_ERR, "Unable to open log file \"%s\" - %s", filename,
174 strerror(errno));
175
176 if (FatalErrors & CUPSD_FATAL_LOG)
177 cupsdEndProcess(getpid(), 0);
178
179 return (0);
180 }
181 }
182
183 if (strncmp(filename, "/dev/", 5))
184 {
185 /*
186 * Change ownership and permissions of non-device logs...
187 */
188
189 fchown(cupsFileNumber(*lf), RunUser, Group);
190 fchmod(cupsFileNumber(*lf), LogFilePerm);
191 }
192 }
193
194 /*
195 * Do we need to rotate the log?
196 */
197
198 if (strncmp(logname, "/dev/", 5) && cupsFileTell(*lf) > MaxLogSize &&
199 MaxLogSize > 0)
200 {
201 /*
202 * Rotate log file...
203 */
204
205 cupsFileClose(*lf);
206
5a9febac 207 strlcpy(backname, filename, sizeof(backname));
22c9029b
MS
208 strlcat(backname, ".O", sizeof(backname));
209
210 unlink(backname);
211 rename(filename, backname);
212
213 if ((*lf = cupsFileOpen(filename, "a")) == NULL)
214 {
215 syslog(LOG_ERR, "Unable to open log file \"%s\" - %s", filename,
216 strerror(errno));
217
218 if (FatalErrors & CUPSD_FATAL_LOG)
219 cupsdEndProcess(getpid(), 0);
220
221 return (0);
222 }
223
224 /*
225 * Change ownership and permissions of non-device logs...
226 */
227
228 fchown(cupsFileNumber(*lf), RunUser, Group);
229 fchmod(cupsFileNumber(*lf), LogFilePerm);
230 }
231
232 return (1);
233}
234
235
ef416fc2 236/*
237 * 'cupsdGetDateTime()' - Returns a pointer to a date/time string.
238 */
239
240char * /* O - Date/time string */
dfd5680b
MS
241cupsdGetDateTime(struct timeval *t, /* I - Time value or NULL for current */
242 cupsd_time_t format) /* I - Format to use */
ef416fc2 243{
dfd5680b
MS
244 struct timeval curtime; /* Current time value */
245 struct tm *date; /* Date/time value */
246 static struct timeval last_time = { 0, 0 };
247 /* Last time we formatted */
248 static char s[1024]; /* Date/time string */
ef416fc2 249 static const char * const months[12] =/* Months */
250 {
251 "Jan",
252 "Feb",
253 "Mar",
254 "Apr",
255 "May",
256 "Jun",
257 "Jul",
258 "Aug",
259 "Sep",
260 "Oct",
261 "Nov",
262 "Dec"
263 };
264
265
839a51c8
MS
266 /*
267 * Make sure we have a valid time...
268 */
269
270 if (!t)
dfd5680b
MS
271 {
272 gettimeofday(&curtime, NULL);
273 t = &curtime;
274 }
839a51c8 275
dfd5680b
MS
276 if (t->tv_sec != last_time.tv_sec ||
277 (LogTimeFormat == CUPSD_TIME_USECS && t->tv_usec != last_time.tv_usec))
ef416fc2 278 {
dfd5680b 279 last_time = *t;
ef416fc2 280
281 /*
282 * Get the date and time from the UNIX time value, and then format it
283 * into a string. Note that we *can't* use the strftime() function since
284 * it is localized and will seriously confuse automatic programs if the
285 * month names are in the wrong language!
286 *
287 * Also, we use the "timezone" variable that contains the current timezone
288 * offset from GMT in seconds so that we are reporting local time in the
289 * log files. If you want GMT, set the TZ environment variable accordingly
290 * before starting the scheduler.
291 *
292 * (*BSD and Darwin store the timezone offset in the tm structure)
293 */
294
dfd5680b 295 date = localtime(&(t->tv_sec));
ef416fc2 296
dfd5680b
MS
297 if (format == CUPSD_TIME_STANDARD)
298 snprintf(s, sizeof(s), "[%02d/%s/%04d:%02d:%02d:%02d %+03ld%02ld]",
299 date->tm_mday, months[date->tm_mon], 1900 + date->tm_year,
300 date->tm_hour, date->tm_min, date->tm_sec,
301#ifdef HAVE_TM_GMTOFF
302 date->tm_gmtoff / 3600, (date->tm_gmtoff / 60) % 60);
303#else
304 timezone / 3600, (timezone / 60) % 60);
305#endif /* HAVE_TM_GMTOFF */
306 else
307 snprintf(s, sizeof(s), "[%02d/%s/%04d:%02d:%02d:%02d.%06d %+03ld%02ld]",
308 date->tm_mday, months[date->tm_mon], 1900 + date->tm_year,
bf3816c7 309 date->tm_hour, date->tm_min, date->tm_sec, (int)t->tv_usec,
ef416fc2 310#ifdef HAVE_TM_GMTOFF
dfd5680b 311 date->tm_gmtoff / 3600, (date->tm_gmtoff / 60) % 60);
ef416fc2 312#else
dfd5680b 313 timezone / 3600, (timezone / 60) % 60);
ef416fc2 314#endif /* HAVE_TM_GMTOFF */
315 }
316
317 return (s);
318}
319
320
22c9029b
MS
321/*
322 * 'cupsdLogFCMessage()' - Log a file checking message.
323 */
324
325void
326cupsdLogFCMessage(
327 void *context, /* I - Printer (if any) */
328 _cups_fc_result_t result, /* I - Check result */
329 const char *message) /* I - Message to log */
330{
331 cupsd_printer_t *p = (cupsd_printer_t *)context;
332 /* Printer */
333 cupsd_loglevel_t level; /* Log level */
334
335
336 if (result == _CUPS_FILE_CHECK_OK)
337 level = CUPSD_LOG_DEBUG2;
338 else
339 level = CUPSD_LOG_ERROR;
340
341 if (p)
342 {
343 cupsdLogMessage(level, "%s: %s", p->name, message);
344
345 if (result == _CUPS_FILE_CHECK_MISSING ||
346 result == _CUPS_FILE_CHECK_WRONG_TYPE)
347 {
348 strlcpy(p->state_message, message, sizeof(p->state_message));
349
350 if (cupsdSetPrinterReasons(p, "+cups-missing-filter-warning"))
351 cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, p, NULL, "%s", message);
352 }
88f9aafc
MS
353 else if (result == _CUPS_FILE_CHECK_PERMISSIONS ||
354 result == _CUPS_FILE_CHECK_RELATIVE_PATH)
22c9029b
MS
355 {
356 strlcpy(p->state_message, message, sizeof(p->state_message));
357
358 if (cupsdSetPrinterReasons(p, "+cups-insecure-filter-warning"))
359 cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE, p, NULL, "%s", message);
360 }
361 }
362 else
363 cupsdLogMessage(level, "%s", message);
364}
365
366
f7deaa1a 367#ifdef HAVE_GSSAPI
368/*
369 * 'cupsdLogGSSMessage()' - Log a GSSAPI error...
370 */
371
372int /* O - 1 on success, 0 on error */
373cupsdLogGSSMessage(
374 int level, /* I - Log level */
375 int major_status, /* I - Major GSSAPI status */
376 int minor_status, /* I - Minor GSSAPI status */
377 const char *message, /* I - printf-style message string */
378 ...) /* I - Additional args as needed */
379{
380 OM_uint32 err_major_status, /* Major status code for display */
381 err_minor_status; /* Minor status code for display */
382 OM_uint32 msg_ctx; /* Message context */
383 gss_buffer_desc major_status_string = GSS_C_EMPTY_BUFFER,
384 /* Major status message */
385 minor_status_string = GSS_C_EMPTY_BUFFER;
386 /* Minor status message */
387 int ret; /* Return value */
dcb445bc 388 char buffer[8192]; /* Buffer for vsnprintf */
f7deaa1a 389
390
dcb445bc
MS
391 if (strchr(message, '%'))
392 {
393 /*
394 * Format the message string...
395 */
396
397 va_list ap; /* Pointer to arguments */
398
399 va_start(ap, message);
400 vsnprintf(buffer, sizeof(buffer), message, ap);
401 va_end(ap);
402
403 message = buffer;
404 }
405
f7deaa1a 406 msg_ctx = 0;
407 err_major_status = gss_display_status(&err_minor_status,
408 major_status,
409 GSS_C_GSS_CODE,
410 GSS_C_NO_OID,
411 &msg_ctx,
412 &major_status_string);
413
414 if (!GSS_ERROR(err_major_status))
1f0275e3
MS
415 gss_display_status(&err_minor_status, minor_status, GSS_C_MECH_CODE,
416 GSS_C_NULL_OID, &msg_ctx, &minor_status_string);
f7deaa1a 417
418 ret = cupsdLogMessage(level, "%s: %s, %s", message,
419 (char *)major_status_string.value,
420 (char *)minor_status_string.value);
421 gss_release_buffer(&err_minor_status, &major_status_string);
422 gss_release_buffer(&err_minor_status, &minor_status_string);
423
424 return (ret);
425}
426#endif /* HAVE_GSSAPI */
427
428
996acce8
MS
429/*
430 * 'cupsdLogClient()' - Log a client message.
431 */
432
433int /* O - 1 on success, 0 on error */
434cupsdLogClient(cupsd_client_t *con, /* I - Client connection */
435 int level, /* I - Log level */
436 const char *message, /* I - Printf-style message string */
437 ...) /* I - Additional arguments as needed */
438{
439 va_list ap, ap2; /* Argument pointers */
440 char clientmsg[1024];/* Format string for client message */
441 int status; /* Formatting status */
442
443
444 /*
445 * See if we want to log this message...
446 */
447
448 if (TestConfigFile || !ErrorLog)
449 return (1);
450
451 if (level > LogLevel)
452 return (1);
453
454 /*
455 * Format and write the log message...
456 */
457
458 if (con)
459 snprintf(clientmsg, sizeof(clientmsg), "[Client %d] %s", con->number,
460 message);
461 else
462 strlcpy(clientmsg, message, sizeof(clientmsg));
463
464 va_start(ap, message);
465
466 do
467 {
468 va_copy(ap2, ap);
469 status = format_log_line(clientmsg, ap2);
470 va_end(ap2);
471 }
472 while (status == 0);
473
474 va_end(ap);
475
476 if (status > 0)
477 return (cupsdWriteErrorLog(level, log_line));
478 else
479 return (cupsdWriteErrorLog(CUPSD_LOG_ERROR,
480 "Unable to allocate memory for log line."));
481}
482
483
ef416fc2 484/*
75bd9771 485 * 'cupsdLogJob()' - Log a job message.
ef416fc2 486 */
487
488int /* O - 1 on success, 0 on error */
75bd9771
MS
489cupsdLogJob(cupsd_job_t *job, /* I - Job */
490 int level, /* I - Log level */
491 const char *message, /* I - Printf-style message string */
492 ...) /* I - Additional arguments as needed */
ef416fc2 493{
dcb445bc 494 va_list ap, ap2; /* Argument pointers */
005dd1eb
MS
495 char jobmsg[1024]; /* Format string for job message */
496 int status; /* Formatting status */
ef416fc2 497
498
499 /*
500 * See if we want to log this message...
501 */
502
94da7e34
MS
503 if (TestConfigFile || !ErrorLog)
504 return (1);
505
178cb736
MS
506 if ((level > LogLevel ||
507 (level == CUPSD_LOG_INFO && LogLevel < CUPSD_LOG_DEBUG)) &&
508 LogDebugHistory <= 0)
2e4ff8af 509 return (1);
2e4ff8af 510
ef416fc2 511 /*
75bd9771 512 * Format and write the log message...
ef416fc2 513 */
514
dcb445bc
MS
515 if (job)
516 snprintf(jobmsg, sizeof(jobmsg), "[Job %d] %s", job->id, message);
517 else
518 strlcpy(jobmsg, message, sizeof(jobmsg));
519
520 va_start(ap, message);
ef416fc2 521
005dd1eb
MS
522 do
523 {
dcb445bc
MS
524 va_copy(ap2, ap);
525 status = format_log_line(jobmsg, ap2);
526 va_end(ap2);
005dd1eb
MS
527 }
528 while (status == 0);
771bd8cb 529
dcb445bc
MS
530 va_end(ap);
531
005dd1eb 532 if (status > 0)
178cb736 533 {
dcb445bc
MS
534 if (job &&
535 (level > LogLevel ||
178cb736
MS
536 (level == CUPSD_LOG_INFO && LogLevel < CUPSD_LOG_DEBUG)) &&
537 LogDebugHistory > 0)
538 {
539 /*
540 * Add message to the job history...
541 */
542
543 cupsd_joblog_t *temp; /* Copy of log message */
ff2b08f9
MS
544 size_t log_len = strlen(log_line);
545 /* Length of log message */
178cb736 546
ff2b08f9 547 if ((temp = malloc(sizeof(cupsd_joblog_t) + log_len)) != NULL)
178cb736
MS
548 {
549 temp->time = time(NULL);
ff2b08f9 550 memcpy(temp->message, log_line, log_len + 1);
178cb736
MS
551 }
552
553 if (!job->history)
554 job->history = cupsArrayNew(NULL, NULL);
555
556 if (job->history && temp)
557 {
558 cupsArrayAdd(job->history, temp);
559
560 if (cupsArrayCount(job->history) > LogDebugHistory)
561 {
562 /*
563 * Remove excess messages...
564 */
565
566 temp = cupsArrayFirst(job->history);
567 cupsArrayRemove(job->history, temp);
568 free(temp);
569 }
570 }
571 else if (temp)
572 free(temp);
573
574 return (1);
575 }
576 else if (level <= LogLevel &&
577 (level != CUPSD_LOG_INFO || LogLevel >= CUPSD_LOG_DEBUG))
578 return (cupsdWriteErrorLog(level, log_line));
579 else
580 return (1);
581 }
75bd9771
MS
582 else
583 return (cupsdWriteErrorLog(CUPSD_LOG_ERROR,
996acce8 584 "Unable to allocate memory for log line."));
75bd9771 585}
ef416fc2 586
ef416fc2 587
75bd9771
MS
588/*
589 * 'cupsdLogMessage()' - Log a message to the error log file.
590 */
ef416fc2 591
75bd9771
MS
592int /* O - 1 on success, 0 on error */
593cupsdLogMessage(int level, /* I - Log level */
594 const char *message, /* I - printf-style message string */
595 ...) /* I - Additional args as needed */
596{
dcb445bc 597 va_list ap, ap2; /* Argument pointers */
005dd1eb 598 int status; /* Formatting status */
ef416fc2 599
ef416fc2 600
601 /*
75bd9771 602 * See if we want to log this message...
ef416fc2 603 */
604
85dda01c 605 if ((TestConfigFile || !ErrorLog) && level <= CUPSD_LOG_WARN)
ef416fc2 606 {
a4845881 607 va_start(ap, message);
cb7f98ee
MS
608#ifdef HAVE_VSYSLOG
609 vsyslog(LOG_LPR | syslevels[level], message, ap);
610#else
a4845881
MS
611 vfprintf(stderr, message, ap);
612 putc('\n', stderr);
cb7f98ee 613#endif /* HAVE_VSYSLOG */
a4845881 614 va_end(ap);
ef416fc2 615
75bd9771 616 return (1);
ef416fc2 617 }
618
75bd9771
MS
619 if (level > LogLevel || !ErrorLog)
620 return (1);
ef416fc2 621
622 /*
75bd9771 623 * Format and write the log message...
ef416fc2 624 */
625
dcb445bc
MS
626 va_start(ap, message);
627
005dd1eb
MS
628 do
629 {
dcb445bc
MS
630 va_copy(ap2, ap);
631 status = format_log_line(message, ap2);
632 va_end(ap2);
005dd1eb
MS
633 }
634 while (status == 0);
ef416fc2 635
dcb445bc
MS
636 va_end(ap);
637
005dd1eb
MS
638 if (status > 0)
639 return (cupsdWriteErrorLog(level, log_line));
75bd9771
MS
640 else
641 return (cupsdWriteErrorLog(CUPSD_LOG_ERROR,
642 "Unable to allocate memory for log line!"));
ef416fc2 643}
644
645
646/*
647 * 'cupsdLogPage()' - Log a page to the page log file.
648 */
649
650int /* O - 1 on success, 0 on error */
651cupsdLogPage(cupsd_job_t *job, /* I - Job being printed */
652 const char *page) /* I - Page being printed */
653{
01ce6322
MS
654 int i; /* Looping var */
655 char buffer[2048], /* Buffer for page log */
656 *bufptr, /* Pointer into buffer */
657 name[256]; /* Attribute name */
658 const char *format, /* Pointer into PageLogFormat */
659 *nameend; /* End of attribute name */
660 ipp_attribute_t *attr; /* Current attribute */
771bd8cb
MS
661 char number[256]; /* Page number */
662 int copies; /* Number of copies */
ef416fc2 663
664
01ce6322
MS
665 /*
666 * Format the line going into the page log...
667 */
668
669 if (!PageLogFormat)
670 return (1);
671
5a9febac 672 strlcpy(number, "1", sizeof(number));
771bd8cb
MS
673 copies = 1;
674 sscanf(page, "%255s%d", number, &copies);
01ce6322
MS
675
676 for (format = PageLogFormat, bufptr = buffer; *format; format ++)
677 {
678 if (*format == '%')
679 {
680 format ++;
681
682 switch (*format)
683 {
684 case '%' : /* Literal % */
685 if (bufptr < (buffer + sizeof(buffer) - 1))
686 *bufptr++ = '%';
687 break;
688
689 case 'p' : /* Printer name */
690 strlcpy(bufptr, job->printer->name,
691 sizeof(buffer) - (bufptr - buffer));
692 bufptr += strlen(bufptr);
693 break;
694
695 case 'j' : /* Job ID */
696 snprintf(bufptr, sizeof(buffer) - (bufptr - buffer), "%d", job->id);
697 bufptr += strlen(bufptr);
698 break;
699
700 case 'u' : /* Username */
701 strlcpy(bufptr, job->username ? job->username : "-",
702 sizeof(buffer) - (bufptr - buffer));
703 bufptr += strlen(bufptr);
704 break;
705
706 case 'T' : /* Date and time */
dfd5680b 707 strlcpy(bufptr, cupsdGetDateTime(NULL, LogTimeFormat),
01ce6322
MS
708 sizeof(buffer) - (bufptr - buffer));
709 bufptr += strlen(bufptr);
710 break;
711
712 case 'P' : /* Page number */
771bd8cb 713 strlcpy(bufptr, number, sizeof(buffer) - (bufptr - buffer));
01ce6322
MS
714 bufptr += strlen(bufptr);
715 break;
716
717 case 'C' : /* Number of copies */
771bd8cb 718 snprintf(bufptr, sizeof(buffer) - (bufptr - buffer), "%d", copies);
01ce6322
MS
719 bufptr += strlen(bufptr);
720 break;
721
722 case '{' : /* {attribute} */
723 if ((nameend = strchr(format, '}')) != NULL &&
724 (nameend - format - 2) < (sizeof(name) - 1))
725 {
726 /*
727 * Pull the name from inside the brackets...
728 */
729
75bd9771
MS
730 memcpy(name, format + 1, nameend - format - 1);
731 name[nameend - format - 1] = '\0';
732
733 format = nameend;
01ce6322
MS
734
735 if ((attr = ippFindAttribute(job->attrs, name,
736 IPP_TAG_ZERO)) != NULL)
737 {
738 /*
739 * Add the attribute value...
740 */
741
01ce6322
MS
742 for (i = 0;
743 i < attr->num_values &&
744 bufptr < (buffer + sizeof(buffer) - 1);
745 i ++)
746 {
747 if (i)
748 *bufptr++ = ',';
749
750 switch (attr->value_tag)
751 {
752 case IPP_TAG_INTEGER :
753 case IPP_TAG_ENUM :
754 snprintf(bufptr, sizeof(buffer) - (bufptr - buffer),
755 "%d", attr->values[i].integer);
756 bufptr += strlen(bufptr);
757 break;
758
759 case IPP_TAG_BOOLEAN :
760 snprintf(bufptr, sizeof(buffer) - (bufptr - buffer),
761 "%d", attr->values[i].boolean);
762 bufptr += strlen(bufptr);
763 break;
764
765 case IPP_TAG_TEXTLANG :
766 case IPP_TAG_NAMELANG :
767 case IPP_TAG_TEXT :
768 case IPP_TAG_NAME :
769 case IPP_TAG_KEYWORD :
770 case IPP_TAG_URI :
771 case IPP_TAG_URISCHEME :
772 case IPP_TAG_CHARSET :
773 case IPP_TAG_LANGUAGE :
774 case IPP_TAG_MIMETYPE :
775 strlcpy(bufptr, attr->values[i].string.text,
776 sizeof(buffer) - (bufptr - buffer));
777 bufptr += strlen(bufptr);
778 break;
779
780 default :
781 strlcpy(bufptr, "???",
782 sizeof(buffer) - (bufptr - buffer));
783 bufptr += strlen(bufptr);
784 break;
785 }
786 }
787 }
788 else if (bufptr < (buffer + sizeof(buffer) - 1))
789 *bufptr++ = '-';
790 break;
791 }
792
793 default :
794 if (bufptr < (buffer + sizeof(buffer) - 2))
795 {
796 *bufptr++ = '%';
797 *bufptr++ = *format;
798 }
799 break;
800 }
801 }
802 else if (bufptr < (buffer + sizeof(buffer) - 1))
803 *bufptr++ = *format;
804 }
ef416fc2 805
01ce6322 806 *bufptr = '\0';
771bd8cb 807
ef416fc2 808#ifdef HAVE_VSYSLOG
809 /*
810 * See if we are logging pages via syslog...
811 */
812
813 if (!strcmp(PageLog, "syslog"))
814 {
01ce6322 815 syslog(LOG_INFO, "%s", buffer);
ef416fc2 816
817 return (1);
818 }
819#endif /* HAVE_VSYSLOG */
820
821 /*
822 * Not using syslog; check the log file...
823 */
824
22c9029b 825 if (!cupsdCheckLogFile(&PageFile, PageLog))
ef416fc2 826 return (0);
827
828 /*
829 * Print a page log entry of the form:
830 *
ac884b6a 831 * printer user job-id [DD/MON/YYYY:HH:MM:SS +TTTT] page num-copies \
ef416fc2 832 * billing hostname
833 */
834
01ce6322 835 cupsFilePrintf(PageFile, "%s\n", buffer);
ef416fc2 836 cupsFileFlush(PageFile);
837
838 return (1);
839}
840
841
842/*
843 * 'cupsdLogRequest()' - Log an HTTP request in Common Log Format.
844 */
845
846int /* O - 1 on success, 0 on error */
847cupsdLogRequest(cupsd_client_t *con, /* I - Request to log */
848 http_status_t code) /* I - Response code */
849{
839a51c8 850 char temp[2048]; /* Temporary string for URI */
ef416fc2 851 static const char * const states[] = /* HTTP client states... */
852 {
853 "WAITING",
854 "OPTIONS",
855 "GET",
856 "GET",
857 "HEAD",
858 "POST",
859 "POST",
860 "POST",
861 "PUT",
862 "PUT",
863 "DELETE",
864 "TRACE",
865 "CLOSE",
866 "STATUS"
867 };
868
869
1f0275e3
MS
870 /*
871 * Filter requests as needed...
872 */
873
874 if (AccessLogLevel < CUPSD_ACCESSLOG_ALL)
875 {
876 /*
ba55dc12 877 * Eliminate simple GET, POST, and PUT requests...
1f0275e3
MS
878 */
879
880 if ((con->operation == HTTP_GET &&
881 strncmp(con->uri, "/admin/conf", 11) &&
882 strncmp(con->uri, "/admin/log", 10)) ||
883 (con->operation == HTTP_POST && !con->request &&
884 strncmp(con->uri, "/admin", 6)) ||
ba55dc12
MS
885 (con->operation != HTTP_GET && con->operation != HTTP_POST &&
886 con->operation != HTTP_PUT))
1f0275e3
MS
887 return (1);
888
889 if (con->request && con->response &&
e07d4801
MS
890 (con->response->request.status.status_code < IPP_REDIRECTION_OTHER_SITE ||
891 con->response->request.status.status_code == IPP_NOT_FOUND))
1f0275e3
MS
892 {
893 /*
894 * Check successful requests...
895 */
896
897 ipp_op_t op = con->request->request.op.operation_id;
898 static cupsd_accesslog_t standard_ops[] =
899 {
900 CUPSD_ACCESSLOG_ALL, /* reserved */
901 CUPSD_ACCESSLOG_ALL, /* reserved */
902 CUPSD_ACCESSLOG_ACTIONS,/* Print-Job */
903 CUPSD_ACCESSLOG_ACTIONS,/* Print-URI */
904 CUPSD_ACCESSLOG_ACTIONS,/* Validate-Job */
905 CUPSD_ACCESSLOG_ACTIONS,/* Create-Job */
906 CUPSD_ACCESSLOG_ACTIONS,/* Send-Document */
907 CUPSD_ACCESSLOG_ACTIONS,/* Send-URI */
908 CUPSD_ACCESSLOG_ACTIONS,/* Cancel-Job */
909 CUPSD_ACCESSLOG_ALL, /* Get-Job-Attributes */
910 CUPSD_ACCESSLOG_ALL, /* Get-Jobs */
911 CUPSD_ACCESSLOG_ALL, /* Get-Printer-Attributes */
912 CUPSD_ACCESSLOG_ACTIONS,/* Hold-Job */
913 CUPSD_ACCESSLOG_ACTIONS,/* Release-Job */
914 CUPSD_ACCESSLOG_ACTIONS,/* Restart-Job */
915 CUPSD_ACCESSLOG_ALL, /* reserved */
916 CUPSD_ACCESSLOG_CONFIG, /* Pause-Printer */
917 CUPSD_ACCESSLOG_CONFIG, /* Resume-Printer */
918 CUPSD_ACCESSLOG_CONFIG, /* Purge-Jobs */
919 CUPSD_ACCESSLOG_CONFIG, /* Set-Printer-Attributes */
920 CUPSD_ACCESSLOG_ACTIONS,/* Set-Job-Attributes */
921 CUPSD_ACCESSLOG_CONFIG, /* Get-Printer-Supported-Values */
922 CUPSD_ACCESSLOG_ACTIONS,/* Create-Printer-Subscription */
923 CUPSD_ACCESSLOG_ACTIONS,/* Create-Job-Subscription */
924 CUPSD_ACCESSLOG_ALL, /* Get-Subscription-Attributes */
925 CUPSD_ACCESSLOG_ALL, /* Get-Subscriptions */
926 CUPSD_ACCESSLOG_ACTIONS,/* Renew-Subscription */
927 CUPSD_ACCESSLOG_ACTIONS,/* Cancel-Subscription */
928 CUPSD_ACCESSLOG_ALL, /* Get-Notifications */
929 CUPSD_ACCESSLOG_ACTIONS,/* Send-Notifications */
930 CUPSD_ACCESSLOG_ALL, /* reserved */
931 CUPSD_ACCESSLOG_ALL, /* reserved */
932 CUPSD_ACCESSLOG_ALL, /* reserved */
933 CUPSD_ACCESSLOG_ALL, /* Get-Print-Support-Files */
934 CUPSD_ACCESSLOG_CONFIG, /* Enable-Printer */
935 CUPSD_ACCESSLOG_CONFIG, /* Disable-Printer */
936 CUPSD_ACCESSLOG_CONFIG, /* Pause-Printer-After-Current-Job */
937 CUPSD_ACCESSLOG_ACTIONS,/* Hold-New-Jobs */
938 CUPSD_ACCESSLOG_ACTIONS,/* Release-Held-New-Jobs */
939 CUPSD_ACCESSLOG_CONFIG, /* Deactivate-Printer */
940 CUPSD_ACCESSLOG_CONFIG, /* Activate-Printer */
941 CUPSD_ACCESSLOG_CONFIG, /* Restart-Printer */
942 CUPSD_ACCESSLOG_CONFIG, /* Shutdown-Printer */
943 CUPSD_ACCESSLOG_CONFIG, /* Startup-Printer */
944 CUPSD_ACCESSLOG_ACTIONS,/* Reprocess-Job */
945 CUPSD_ACCESSLOG_ACTIONS,/* Cancel-Current-Job */
946 CUPSD_ACCESSLOG_ACTIONS,/* Suspend-Current-Job */
947 CUPSD_ACCESSLOG_ACTIONS,/* Resume-Job */
948 CUPSD_ACCESSLOG_ACTIONS,/* Promote-Job */
949 CUPSD_ACCESSLOG_ACTIONS /* Schedule-Job-After */
950 };
951 static cupsd_accesslog_t cups_ops[] =
952 {
953 CUPSD_ACCESSLOG_ALL, /* CUPS-Get-Default */
954 CUPSD_ACCESSLOG_ALL, /* CUPS-Get-Printers */
955 CUPSD_ACCESSLOG_CONFIG, /* CUPS-Add-Modify-Printer */
956 CUPSD_ACCESSLOG_CONFIG, /* CUPS-Delete-Printer */
957 CUPSD_ACCESSLOG_ALL, /* CUPS-Get-Classes */
958 CUPSD_ACCESSLOG_CONFIG, /* CUPS-Add-Modify-Class */
959 CUPSD_ACCESSLOG_CONFIG, /* CUPS-Delete-Class */
960 CUPSD_ACCESSLOG_CONFIG, /* CUPS-Accept-Jobs */
961 CUPSD_ACCESSLOG_CONFIG, /* CUPS-Reject-Jobs */
962 CUPSD_ACCESSLOG_CONFIG, /* CUPS-Set-Default */
963 CUPSD_ACCESSLOG_CONFIG, /* CUPS-Get-Devices */
964 CUPSD_ACCESSLOG_CONFIG, /* CUPS-Get-PPDs */
965 CUPSD_ACCESSLOG_ACTIONS,/* CUPS-Move-Job */
966 CUPSD_ACCESSLOG_ACTIONS,/* CUPS-Authenticate-Job */
967 CUPSD_ACCESSLOG_ALL /* CUPS-Get-PPD */
968 };
771bd8cb 969
1f0275e3
MS
970
971 if ((op <= IPP_SCHEDULE_JOB_AFTER && standard_ops[op] > AccessLogLevel) ||
972 (op >= CUPS_GET_DEFAULT && op <= CUPS_GET_PPD &&
973 cups_ops[op - CUPS_GET_DEFAULT] > AccessLogLevel))
974 return (1);
975 }
976 }
977
ef416fc2 978#ifdef HAVE_VSYSLOG
979 /*
980 * See if we are logging accesses via syslog...
981 */
982
983 if (!strcmp(AccessLog, "syslog"))
984 {
2abf387c 985 syslog(LOG_INFO,
986 "REQUEST %s - %s \"%s %s HTTP/%d.%d\" %d " CUPS_LLFMT " %s %s\n",
996acce8 987 con->http->hostname, con->username[0] != '\0' ? con->username : "-",
839a51c8 988 states[con->operation], _httpEncodeURI(temp, con->uri, sizeof(temp)),
996acce8 989 con->http->version / 100, con->http->version % 100,
2abf387c 990 code, CUPS_LLCAST con->bytes,
991 con->request ?
992 ippOpString(con->request->request.op.operation_id) : "-",
993 con->response ?
994 ippErrorString(con->response->request.status.status_code) : "-");
ef416fc2 995
996 return (1);
997 }
998#endif /* HAVE_VSYSLOG */
999
1000 /*
1001 * Not using syslog; check the log file...
1002 */
1003
22c9029b 1004 if (!cupsdCheckLogFile(&AccessFile, AccessLog))
ef416fc2 1005 return (0);
1006
1007 /*
1008 * Write a log of the request in "common log format"...
1009 */
1010
1011 cupsFilePrintf(AccessFile,
1012 "%s - %s %s \"%s %s HTTP/%d.%d\" %d " CUPS_LLFMT " %s %s\n",
996acce8 1013 con->http->hostname,
c8fef167 1014 con->username[0] != '\0' ? con->username : "-",
dfd5680b
MS
1015 cupsdGetDateTime(&(con->start), LogTimeFormat),
1016 states[con->operation],
839a51c8 1017 _httpEncodeURI(temp, con->uri, sizeof(temp)),
996acce8 1018 con->http->version / 100, con->http->version % 100,
ef416fc2 1019 code, CUPS_LLCAST con->bytes,
1020 con->request ?
1021 ippOpString(con->request->request.op.operation_id) : "-",
1022 con->response ?
1023 ippErrorString(con->response->request.status.status_code) :
1024 "-");
1025
1026 cupsFileFlush(AccessFile);
1027
1028 return (1);
1029}
1030
1031
75bd9771
MS
1032/*
1033 * 'cupsdWriteErrorLog()' - Write a line to the ErrorLog.
1034 */
1035
1036int /* O - 1 on success, 0 on failure */
1037cupsdWriteErrorLog(int level, /* I - Log level */
1038 const char *message) /* I - Message string */
1039{
28a463e0 1040 int ret = 1; /* Return value */
75bd9771
MS
1041 static const char levels[] = /* Log levels... */
1042 {
1043 ' ',
1044 'X',
1045 'A',
1046 'C',
1047 'E',
1048 'W',
1049 'N',
1050 'I',
1051 'D',
1052 'd'
1053 };
75bd9771
MS
1054
1055
1056#ifdef HAVE_VSYSLOG
1057 /*
1058 * See if we are logging errors via syslog...
1059 */
1060
1061 if (!strcmp(ErrorLog, "syslog"))
1062 {
1063 syslog(syslevels[level], "%s", message);
1064 return (1);
1065 }
1066#endif /* HAVE_VSYSLOG */
1067
1068 /*
1069 * Not using syslog; check the log file...
1070 */
1071
28a463e0
MS
1072 _cupsMutexLock(&log_mutex);
1073
22c9029b 1074 if (!cupsdCheckLogFile(&ErrorFile, ErrorLog))
28a463e0
MS
1075 {
1076 ret = 0;
1077 }
1078 else
1079 {
1080 /*
1081 * Write the log message...
1082 */
75bd9771 1083
28a463e0
MS
1084 cupsFilePrintf(ErrorFile, "%c %s %s\n", levels[level],
1085 cupsdGetDateTime(NULL, LogTimeFormat), message);
1086 cupsFileFlush(ErrorFile);
1087 }
75bd9771 1088
28a463e0 1089 _cupsMutexUnlock(&log_mutex);
75bd9771 1090
28a463e0 1091 return (ret);
75bd9771
MS
1092}
1093
1094
ef416fc2 1095/*
75bd9771
MS
1096 * 'format_log_line()' - Format a line for a log file.
1097 *
1098 * This function resizes a global string buffer as needed. Each call returns
1099 * a pointer to this buffer, so the contents are only good until the next call
1100 * to format_log_line()...
1101 */
1102
005dd1eb 1103static int /* O - -1 for fatal, 0 for retry, 1 for success */
75bd9771
MS
1104format_log_line(const char *message, /* I - Printf-style format string */
1105 va_list ap) /* I - Argument list */
1106{
005dd1eb 1107 int len; /* Length of formatted line */
75bd9771
MS
1108
1109
1110 /*
1111 * Allocate the line buffer as needed...
1112 */
1113
1114 if (!log_linesize)
1115 {
1116 log_linesize = 8192;
1117 log_line = malloc(log_linesize);
1118
1119 if (!log_line)
005dd1eb 1120 return (-1);
75bd9771
MS
1121 }
1122
1123 /*
1124 * Format the log message...
1125 */
1126
1127 len = vsnprintf(log_line, log_linesize, message, ap);
1128
1129 /*
1130 * Resize the buffer as needed...
1131 */
1132
ed6e7faf 1133 if (len >= log_linesize && log_linesize < 65536)
75bd9771
MS
1134 {
1135 char *temp; /* Temporary string pointer */
1136
1137
1138 len ++;
1139
1140 if (len < 8192)
1141 len = 8192;
1142 else if (len > 65536)
1143 len = 65536;
1144
1145 temp = realloc(log_line, len);
1146
1147 if (temp)
1148 {
1149 log_line = temp;
1150 log_linesize = len;
75bd9771 1151
005dd1eb
MS
1152 return (0);
1153 }
75bd9771
MS
1154 }
1155
005dd1eb 1156 return (1);
75bd9771
MS
1157}
1158
1159
1160/*
f2d18633 1161 * End of "$Id$".
ef416fc2 1162 */