4 * Log file routines for the CUPS scheduler.
6 * Copyright 2007-2015 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
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/".
17 * Include necessary headers...
24 #elif defined(HAVE_SYSTEMD_SD_JOURNAL_H)
25 # define SD_JOURNAL_SUPPRESS_LOCATION
26 # include <systemd/sd-journal.h>
27 #endif /* HAVE_ASL_H */
32 * Constants for log keys from PWG 5110.3 (PWG Common Log Format)...
35 #define PWG_DeviceUUID "DUU"
37 #define PWG_LogNaturalLanguage "NL"
38 #define PWG_Status "S"
39 #define PWG_ServiceURI "URI"
40 #define PWG_UserHost "UH"
41 #define PWG_UserName "UN"
42 #define PWG_UserURI "UU"
43 #define PWG_ServiceIsAcceptingJobs "IAJ"
44 #define PWG_ServiceState "ST"
45 #define PWG_ServiceStateReasons "SR"
46 #define PWG_ServiceUUID "SUU"
47 #define PWG_JobID "JID"
48 #define PWG_JobUUID "JUU"
49 #define PWG_JobImagesCompleted "JIM"
50 #define PWG_JobImpressionsCompleted "JIC"
51 #define PWG_JobDestinationURI "JD"
52 #define PWG_JobState "JS"
53 #define PWG_JobStateReasons "JR"
54 #define PWG_JobAccountingID "JA"
55 #define PWG_JobAcountingUserName "JAUN"
56 #define PWG_JobAccountingUserURI "JAUU"
63 static _cups_mutex_t log_mutex
= _CUPS_MUTEX_INITIALIZER
;
64 /* Mutex for logging */
65 static size_t log_linesize
= 0; /* Size of line for output file */
66 static char *log_line
= NULL
; /* Line for output file */
69 static const int log_levels
[] = /* ASL levels... */
82 #elif defined(HAVE_VSYSLOG) || defined(HAVE_SYSTEMD_SD_JOURNAL_H)
83 static const int log_levels
[] = /* SYSLOG levels... */
96 #endif /* HAVE_ASL_H */
103 static int format_log_line(const char *message
, va_list ap
);
107 * 'cupsdCheckLogFile()' - Open/rotate a log file if it needs it.
110 int /* O - 1 if log file open */
111 cupsdCheckLogFile(cups_file_t
**lf
, /* IO - Log file */
112 const char *logname
) /* I - Log filename */
114 char backname
[1024], /* Backup log filename */
115 filename
[1024], /* Formatted log filename */
116 *ptr
; /* Pointer into filename */
117 const char *logptr
; /* Pointer into log filename */
121 * See if we have a log file to check...
124 if (!lf
|| !logname
|| !logname
[0])
128 * Handle logging to stderr...
131 if (!strcmp(logname
, "stderr"))
138 * Format the filename as needed...
142 (strncmp(logname
, "/dev/", 5) && cupsFileTell(*lf
) > MaxLogSize
&&
146 * Handle format strings...
149 filename
[sizeof(filename
) - 1] = '\0';
151 if (logname
[0] != '/')
153 strlcpy(filename
, ServerRoot
, sizeof(filename
));
154 strlcat(filename
, "/", sizeof(filename
));
159 for (logptr
= logname
, ptr
= filename
+ strlen(filename
);
160 *logptr
&& ptr
< (filename
+ sizeof(filename
) - 1);
172 * Insert the server name...
175 strlcpy(ptr
, ServerName
, sizeof(filename
) - (size_t)(ptr
- filename
));
181 * Otherwise just insert the character...
194 * See if the log file is open...
200 * Nope, open the log file...
203 if ((*lf
= cupsFileOpen(filename
, "a")) == NULL
)
206 * If the file is in CUPS_LOGDIR then try to create a missing directory...
209 if (!strncmp(filename
, CUPS_LOGDIR
, strlen(CUPS_LOGDIR
)))
212 * Try updating the permissions of the containing log directory, using
213 * the log file permissions as a basis...
216 mode_t log_dir_perm
= (mode_t
)(0300 | LogFilePerm
);
217 /* LogFilePerm + owner write/search */
218 if (log_dir_perm
& 0040)
219 log_dir_perm
|= 0010; /* Add group search */
220 if (log_dir_perm
& 0004)
221 log_dir_perm
|= 0001; /* Add other search */
223 cupsdCheckPermissions(CUPS_LOGDIR
, NULL
, log_dir_perm
, RunUser
, Group
, 1, -1);
225 *lf
= cupsFileOpen(filename
, "a");
231 asl_object_t m
; /* Log message */
233 m
= asl_new(ASL_TYPE_MSG
);
234 asl_set(m
, ASL_KEY_FACILITY
, "org.cups.cupsd");
235 asl_log(NULL
, m
, ASL_LEVEL_ERR
, "Unable to open log file \"%s\" - %s", filename
, strerror(errno
));
238 #elif defined(HAVE_SYSTEMD_SD_JOURNAL_H)
239 sd_journal_print(LOG_ERR
, "Unable to open log file \"%s\" - %s", filename
, strerror(errno
));
242 syslog(LOG_ERR
, "Unable to open log file \"%s\" - %s", filename
, strerror(errno
));
243 #endif /* HAVE_ASL_H */
245 if (FatalErrors
& CUPSD_FATAL_LOG
)
246 cupsdEndProcess(getpid(), 0);
252 if (strncmp(filename
, "/dev/", 5))
255 * Change ownership and permissions of non-device logs...
258 fchown(cupsFileNumber(*lf
), RunUser
, Group
);
259 fchmod(cupsFileNumber(*lf
), LogFilePerm
);
264 * Do we need to rotate the log?
267 if (strncmp(logname
, "/dev/", 5) && cupsFileTell(*lf
) > MaxLogSize
&&
276 strlcpy(backname
, filename
, sizeof(backname
));
277 strlcat(backname
, ".O", sizeof(backname
));
280 rename(filename
, backname
);
282 if ((*lf
= cupsFileOpen(filename
, "a")) == NULL
)
285 asl_object_t m
; /* Log message */
287 m
= asl_new(ASL_TYPE_MSG
);
288 asl_set(m
, ASL_KEY_FACILITY
, "org.cups.cupsd");
289 asl_log(NULL
, m
, ASL_LEVEL_ERR
, "Unable to open log file \"%s\" - %s", filename
, strerror(errno
));
292 #elif defined(HAVE_SYSTEMD_SD_JOURNAL_H)
293 sd_journal_print(LOG_ERR
, "Unable to open log file \"%s\" - %s", filename
, strerror(errno
));
296 syslog(LOG_ERR
, "Unable to open log file \"%s\" - %s", filename
, strerror(errno
));
297 #endif /* HAVE_ASL_H */
299 if (FatalErrors
& CUPSD_FATAL_LOG
)
300 cupsdEndProcess(getpid(), 0);
306 * Change ownership and permissions of non-device logs...
309 fchown(cupsFileNumber(*lf
), RunUser
, Group
);
310 fchmod(cupsFileNumber(*lf
), LogFilePerm
);
318 * 'cupsdGetDateTime()' - Returns a pointer to a date/time string.
321 char * /* O - Date/time string */
322 cupsdGetDateTime(struct timeval
*t
, /* I - Time value or NULL for current */
323 cupsd_time_t format
) /* I - Format to use */
325 struct timeval curtime
; /* Current time value */
326 struct tm
*date
; /* Date/time value */
327 static struct timeval last_time
= { 0, 0 };
328 /* Last time we formatted */
329 static char s
[1024]; /* Date/time string */
330 static const char * const months
[12] =/* Months */
348 * Make sure we have a valid time...
353 gettimeofday(&curtime
, NULL
);
357 if (t
->tv_sec
!= last_time
.tv_sec
||
358 (LogTimeFormat
== CUPSD_TIME_USECS
&& t
->tv_usec
!= last_time
.tv_usec
))
363 * Get the date and time from the UNIX time value, and then format it
364 * into a string. Note that we *can't* use the strftime() function since
365 * it is localized and will seriously confuse automatic programs if the
366 * month names are in the wrong language!
368 * Also, we use the "timezone" variable that contains the current timezone
369 * offset from GMT in seconds so that we are reporting local time in the
370 * log files. If you want GMT, set the TZ environment variable accordingly
371 * before starting the scheduler.
373 * (*BSD and Darwin store the timezone offset in the tm structure)
376 date
= localtime(&(t
->tv_sec
));
378 if (format
== CUPSD_TIME_STANDARD
)
379 snprintf(s
, sizeof(s
), "[%02d/%s/%04d:%02d:%02d:%02d %+03ld%02ld]",
380 date
->tm_mday
, months
[date
->tm_mon
], 1900 + date
->tm_year
,
381 date
->tm_hour
, date
->tm_min
, date
->tm_sec
,
382 #ifdef HAVE_TM_GMTOFF
383 date
->tm_gmtoff
/ 3600, (date
->tm_gmtoff
/ 60) % 60);
385 timezone
/ 3600, (timezone
/ 60) % 60);
386 #endif /* HAVE_TM_GMTOFF */
388 snprintf(s
, sizeof(s
), "[%02d/%s/%04d:%02d:%02d:%02d.%06d %+03ld%02ld]",
389 date
->tm_mday
, months
[date
->tm_mon
], 1900 + date
->tm_year
,
390 date
->tm_hour
, date
->tm_min
, date
->tm_sec
, (int)t
->tv_usec
,
391 #ifdef HAVE_TM_GMTOFF
392 date
->tm_gmtoff
/ 3600, (date
->tm_gmtoff
/ 60) % 60);
394 timezone
/ 3600, (timezone
/ 60) % 60);
395 #endif /* HAVE_TM_GMTOFF */
403 * 'cupsdLogFCMessage()' - Log a file checking message.
408 void *context
, /* I - Printer (if any) */
409 _cups_fc_result_t result
, /* I - Check result */
410 const char *message
) /* I - Message to log */
412 cupsd_printer_t
*p
= (cupsd_printer_t
*)context
;
414 cupsd_loglevel_t level
; /* Log level */
417 if (result
== _CUPS_FILE_CHECK_OK
)
418 level
= CUPSD_LOG_DEBUG2
;
420 level
= CUPSD_LOG_ERROR
;
424 cupsdLogMessage(level
, "%s: %s", p
->name
, message
);
426 if (result
== _CUPS_FILE_CHECK_MISSING
||
427 result
== _CUPS_FILE_CHECK_WRONG_TYPE
)
429 strlcpy(p
->state_message
, message
, sizeof(p
->state_message
));
431 if (cupsdSetPrinterReasons(p
, "+cups-missing-filter-warning"))
432 cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE
, p
, NULL
, "%s", message
);
434 else if (result
== _CUPS_FILE_CHECK_PERMISSIONS
||
435 result
== _CUPS_FILE_CHECK_RELATIVE_PATH
)
437 strlcpy(p
->state_message
, message
, sizeof(p
->state_message
));
439 if (cupsdSetPrinterReasons(p
, "+cups-insecure-filter-warning"))
440 cupsdAddEvent(CUPSD_EVENT_PRINTER_STATE
, p
, NULL
, "%s", message
);
444 cupsdLogMessage(level
, "%s", message
);
450 * 'cupsdLogGSSMessage()' - Log a GSSAPI error...
453 int /* O - 1 on success, 0 on error */
455 int level
, /* I - Log level */
456 OM_uint32 major_status
, /* I - Major GSSAPI status */
457 OM_uint32 minor_status
, /* I - Minor GSSAPI status */
458 const char *message
, /* I - printf-style message string */
459 ...) /* I - Additional args as needed */
461 OM_uint32 err_major_status
, /* Major status code for display */
462 err_minor_status
; /* Minor status code for display */
463 OM_uint32 msg_ctx
; /* Message context */
464 gss_buffer_desc major_status_string
= GSS_C_EMPTY_BUFFER
,
465 /* Major status message */
466 minor_status_string
= GSS_C_EMPTY_BUFFER
;
467 /* Minor status message */
468 int ret
; /* Return value */
469 char buffer
[8192]; /* Buffer for vsnprintf */
472 if (strchr(message
, '%'))
475 * Format the message string...
478 va_list ap
; /* Pointer to arguments */
480 va_start(ap
, message
);
481 vsnprintf(buffer
, sizeof(buffer
), message
, ap
);
488 err_major_status
= gss_display_status(&err_minor_status
,
493 &major_status_string
);
495 if (!GSS_ERROR(err_major_status
))
496 gss_display_status(&err_minor_status
, minor_status
, GSS_C_MECH_CODE
,
497 GSS_C_NULL_OID
, &msg_ctx
, &minor_status_string
);
499 ret
= cupsdLogMessage(level
, "%s: %s, %s", message
,
500 (char *)major_status_string
.value
,
501 (char *)minor_status_string
.value
);
502 gss_release_buffer(&err_minor_status
, &major_status_string
);
503 gss_release_buffer(&err_minor_status
, &minor_status_string
);
507 #endif /* HAVE_GSSAPI */
511 * 'cupsdLogClient()' - Log a client message.
514 int /* O - 1 on success, 0 on error */
515 cupsdLogClient(cupsd_client_t
*con
, /* I - Client connection */
516 int level
, /* I - Log level */
517 const char *message
, /* I - Printf-style message string */
518 ...) /* I - Additional arguments as needed */
520 va_list ap
, ap2
; /* Argument pointers */
521 char clientmsg
[1024];/* Format string for client message */
522 int status
; /* Formatting status */
526 * See if we want to log this message...
529 if (TestConfigFile
|| !ErrorLog
)
532 if (level
> LogLevel
)
536 * Format and write the log message...
540 snprintf(clientmsg
, sizeof(clientmsg
), "[Client %d] %s", con
->number
,
543 strlcpy(clientmsg
, message
, sizeof(clientmsg
));
545 va_start(ap
, message
);
550 status
= format_log_line(clientmsg
, ap2
);
558 return (cupsdWriteErrorLog(level
, log_line
));
560 return (cupsdWriteErrorLog(CUPSD_LOG_ERROR
,
561 "Unable to allocate memory for log line."));
566 * 'cupsdLogJob()' - Log a job message.
569 int /* O - 1 on success, 0 on error */
570 cupsdLogJob(cupsd_job_t
*job
, /* I - Job */
571 int level
, /* I - Log level */
572 const char *message
, /* I - Printf-style message string */
573 ...) /* I - Additional arguments as needed */
575 va_list ap
, ap2
; /* Argument pointers */
576 char jobmsg
[1024]; /* Format string for job message */
577 int status
; /* Formatting status */
581 * See if we want to log this message...
584 if (TestConfigFile
|| !ErrorLog
)
587 if ((level
> LogLevel
||
588 (level
== CUPSD_LOG_INFO
&& LogLevel
< CUPSD_LOG_DEBUG
)) &&
589 LogDebugHistory
<= 0)
593 if (!strcmp(ErrorLog
, "syslog"))
595 asl_object_t m
; /* Log message */
596 char job_id
[32], /* job-id string */
597 completed
[32]; /* job-impressions-completed string */
598 cupsd_printer_t
*printer
= job
->printer
? job
->printer
: cupsdFindDest(job
->dest
);
599 static const char * const job_states
[] =
600 { /* job-state strings */
610 snprintf(job_id
, sizeof(job_id
), "%d", job
->id
);
612 m
= asl_new(ASL_TYPE_MSG
);
613 asl_set(m
, ASL_KEY_FACILITY
, "org.cups.cupsd");
614 asl_set(m
, PWG_Event
, "JobStateChanged");
615 asl_set(m
, PWG_ServiceURI
, printer
->uri
);
616 asl_set(m
, PWG_JobID
, job_id
);
617 asl_set(m
, PWG_JobState
, job_states
[job
->state_value
- IPP_JSTATE_PENDING
]);
619 if (job
->impressions
)
621 snprintf(completed
, sizeof(completed
), "%d", ippGetInteger(job
->impressions
, 0));
622 asl_set(m
, PWG_JobImpressionsCompleted
, completed
);
625 va_start(ap
, message
);
626 asl_vlog(NULL
, m
, log_levels
[level
], message
, ap
);
633 #elif defined(HAVE_SYSTEMD_SD_JOURNAL_H)
634 if (!strcmp(ErrorLog
, "syslog"))
636 cupsd_printer_t
*printer
= job
->printer
? job
->printer
: cupsdFindDest(job
->dest
);
637 static const char * const job_states
[] =
638 { /* job-state strings */
648 va_start(ap
, message
);
653 status
= format_log_line(message
, ap2
);
660 sd_journal_send("MESSAGE=%s", log_line
,
661 "PRIORITY=%i", log_levels
[level
],
662 PWG_Event
"=JobStateChanged",
663 PWG_ServiceURI
"=%s", printer
->uri
,
664 PWG_JobID
"=%d", job
->id
,
665 PWG_JobState
"=%s", job_states
[job
->state_value
- IPP_JSTATE_PENDING
],
666 PWG_JobImpressionsCompleted
"=%d", ippGetInteger(job
->impressions
, 0),
671 #endif /* HAVE_ASL_H */
674 * Format and write the log message...
678 snprintf(jobmsg
, sizeof(jobmsg
), "[Job %d] %s", job
->id
, message
);
680 strlcpy(jobmsg
, message
, sizeof(jobmsg
));
682 va_start(ap
, message
);
687 status
= format_log_line(jobmsg
, ap2
);
698 (level
== CUPSD_LOG_INFO
&& LogLevel
< CUPSD_LOG_DEBUG
)) &&
702 * Add message to the job history...
705 cupsd_joblog_t
*temp
; /* Copy of log message */
706 size_t log_len
= strlen(log_line
);
707 /* Length of log message */
709 if ((temp
= malloc(sizeof(cupsd_joblog_t
) + log_len
)) != NULL
)
711 temp
->time
= time(NULL
);
712 memcpy(temp
->message
, log_line
, log_len
+ 1);
716 job
->history
= cupsArrayNew(NULL
, NULL
);
718 if (job
->history
&& temp
)
720 cupsArrayAdd(job
->history
, temp
);
722 if (cupsArrayCount(job
->history
) > LogDebugHistory
)
725 * Remove excess messages...
728 temp
= cupsArrayFirst(job
->history
);
729 cupsArrayRemove(job
->history
, temp
);
738 else if (level
<= LogLevel
&&
739 (level
!= CUPSD_LOG_INFO
|| LogLevel
>= CUPSD_LOG_DEBUG
))
740 return (cupsdWriteErrorLog(level
, log_line
));
745 return (cupsdWriteErrorLog(CUPSD_LOG_ERROR
,
746 "Unable to allocate memory for log line."));
751 * 'cupsdLogMessage()' - Log a message to the error log file.
754 int /* O - 1 on success, 0 on error */
755 cupsdLogMessage(int level
, /* I - Log level */
756 const char *message
, /* I - printf-style message string */
757 ...) /* I - Additional args as needed */
759 va_list ap
, ap2
; /* Argument pointers */
760 int status
; /* Formatting status */
764 * See if we want to log this message...
767 if ((TestConfigFile
|| !ErrorLog
) && level
<= CUPSD_LOG_WARN
)
769 va_start(ap
, message
);
772 asl_object_t m
; /* Log message */
774 m
= asl_new(ASL_TYPE_MSG
);
775 asl_set(m
, ASL_KEY_FACILITY
, "org.cups.cupsd");
776 asl_vlog(NULL
, m
, log_levels
[level
], message
, ap
);
779 #elif defined(HAVE_SYSTEMD_SD_JOURNAL_H)
780 sd_journal_printv(log_levels
[level
], message
, ap
);
782 #elif defined(HAVE_VSYSLOG)
783 vsyslog(LOG_LPR
| log_levels
[level
], message
, ap
);
786 vfprintf(stderr
, message
, ap
);
788 #endif /* HAVE_VSYSLOG */
795 if (level
> LogLevel
|| !ErrorLog
)
799 if (!strcmp(ErrorLog
, "syslog"))
801 asl_object_t m
; /* Log message */
803 m
= asl_new(ASL_TYPE_MSG
);
804 asl_set(m
, ASL_KEY_FACILITY
, "org.cups.cupsd");
806 va_start(ap
, message
);
807 asl_vlog(NULL
, m
, log_levels
[level
], message
, ap
);
814 #elif defined(HAVE_SYSTEMD_SD_JOURNAL_H)
815 if (!strcmp(ErrorLog
, "syslog"))
817 va_start(ap
, message
);
818 sd_journal_printv(log_levels
[level
], message
, ap
);
822 #endif /* HAVE_ASL_H */
825 * Format and write the log message...
828 va_start(ap
, message
);
833 status
= format_log_line(message
, ap2
);
841 return (cupsdWriteErrorLog(level
, log_line
));
843 return (cupsdWriteErrorLog(CUPSD_LOG_ERROR
,
844 "Unable to allocate memory for log line!"));
849 * 'cupsdLogPage()' - Log a page to the page log file.
852 int /* O - 1 on success, 0 on error */
853 cupsdLogPage(cupsd_job_t
*job
, /* I - Job being printed */
854 const char *page
) /* I - Page being printed */
856 int i
; /* Looping var */
857 char buffer
[2048], /* Buffer for page log */
858 *bufptr
, /* Pointer into buffer */
859 name
[256]; /* Attribute name */
860 const char *format
, /* Pointer into PageLogFormat */
861 *nameend
; /* End of attribute name */
862 ipp_attribute_t
*attr
; /* Current attribute */
863 char number
[256]; /* Page number */
864 int copies
; /* Number of copies */
868 * Format the line going into the page log...
874 strlcpy(number
, "1", sizeof(number
));
876 sscanf(page
, "%255s%d", number
, &copies
);
878 for (format
= PageLogFormat
, bufptr
= buffer
; *format
; format
++)
886 case '%' : /* Literal % */
887 if (bufptr
< (buffer
+ sizeof(buffer
) - 1))
891 case 'p' : /* Printer name */
892 strlcpy(bufptr
, job
->dest
, sizeof(buffer
) - (size_t)(bufptr
- buffer
));
893 bufptr
+= strlen(bufptr
);
896 case 'j' : /* Job ID */
897 snprintf(bufptr
, sizeof(buffer
) - (size_t)(bufptr
- buffer
), "%d", job
->id
);
898 bufptr
+= strlen(bufptr
);
901 case 'u' : /* Username */
902 strlcpy(bufptr
, job
->username
? job
->username
: "-", sizeof(buffer
) - (size_t)(bufptr
- buffer
));
903 bufptr
+= strlen(bufptr
);
906 case 'T' : /* Date and time */
907 strlcpy(bufptr
, cupsdGetDateTime(NULL
, LogTimeFormat
), sizeof(buffer
) - (size_t)(bufptr
- buffer
));
908 bufptr
+= strlen(bufptr
);
911 case 'P' : /* Page number */
912 strlcpy(bufptr
, number
, sizeof(buffer
) - (size_t)(bufptr
- buffer
));
913 bufptr
+= strlen(bufptr
);
916 case 'C' : /* Number of copies */
917 snprintf(bufptr
, sizeof(buffer
) - (size_t)(bufptr
- buffer
), "%d", copies
);
918 bufptr
+= strlen(bufptr
);
921 case '{' : /* {attribute} */
922 if ((nameend
= strchr(format
, '}')) != NULL
&& (size_t)(nameend
- format
- 2) < (sizeof(name
) - 1))
925 * Pull the name from inside the brackets...
928 memcpy(name
, format
+ 1, (size_t)(nameend
- format
- 1));
929 name
[nameend
- format
- 1] = '\0';
933 attr
= ippFindAttribute(job
->attrs
, name
, IPP_TAG_ZERO
);
934 if (!attr
&& !strcmp(name
, "job-billing"))
937 * Handle alias "job-account-id" (which was standardized after
938 * "job-billing" was defined for CUPS...
941 attr
= ippFindAttribute(job
->attrs
, "job-account-id", IPP_TAG_ZERO
);
943 else if (!attr
&& !strcmp(name
, "media"))
946 * Handle alias "media-col" which uses dimensions instead of
950 attr
= ippFindAttribute(job
->attrs
, "media-col/media-size", IPP_TAG_BEGIN_COLLECTION
);
956 * Add the attribute value...
960 i
< attr
->num_values
&&
961 bufptr
< (buffer
+ sizeof(buffer
) - 1);
967 switch (attr
->value_tag
)
969 case IPP_TAG_INTEGER
:
971 snprintf(bufptr
, sizeof(buffer
) - (size_t)(bufptr
- buffer
), "%d", attr
->values
[i
].integer
);
972 bufptr
+= strlen(bufptr
);
975 case IPP_TAG_BOOLEAN
:
976 snprintf(bufptr
, sizeof(buffer
) - (size_t)(bufptr
- buffer
), "%d", attr
->values
[i
].boolean
);
977 bufptr
+= strlen(bufptr
);
980 case IPP_TAG_TEXTLANG
:
981 case IPP_TAG_NAMELANG
:
984 case IPP_TAG_KEYWORD
:
986 case IPP_TAG_URISCHEME
:
987 case IPP_TAG_CHARSET
:
988 case IPP_TAG_LANGUAGE
:
989 case IPP_TAG_MIMETYPE
:
990 strlcpy(bufptr
, attr
->values
[i
].string
.text
, sizeof(buffer
) - (size_t)(bufptr
- buffer
));
991 bufptr
+= strlen(bufptr
);
994 case IPP_TAG_BEGIN_COLLECTION
:
995 if (!strcmp(attr
->name
, "media-size"))
997 ipp_attribute_t
*x_dimension
= ippFindAttribute(ippGetCollection(attr
, 0), "x-dimension", IPP_TAG_INTEGER
);
998 ipp_attribute_t
*y_dimension
= ippFindAttribute(ippGetCollection(attr
, 0), "y-dimension", IPP_TAG_INTEGER
);
999 /* Media dimensions */
1001 if (x_dimension
&& y_dimension
)
1003 pwg_media_t
*pwg
= pwgMediaForSize(ippGetInteger(x_dimension
, 0), ippGetInteger(y_dimension
, 0));
1004 /* PWG media name */
1005 strlcpy(bufptr
, pwg
->pwg
, sizeof(buffer
) - (size_t)(bufptr
- buffer
));
1011 strlcpy(bufptr
, "???", sizeof(buffer
) - (size_t)(bufptr
- buffer
));
1012 bufptr
+= strlen(bufptr
);
1017 else if (bufptr
< (buffer
+ sizeof(buffer
) - 1))
1023 if (bufptr
< (buffer
+ sizeof(buffer
) - 2))
1026 *bufptr
++ = *format
;
1031 else if (bufptr
< (buffer
+ sizeof(buffer
) - 1))
1032 *bufptr
++ = *format
;
1038 if (!strcmp(ErrorLog
, "syslog"))
1040 asl_object_t m
; /* Log message */
1041 char job_id
[32], /* job-id string */
1042 completed
[32]; /* job-impressions-completed string */
1043 static const char * const job_states
[] =
1044 { /* job-state strings */
1048 "ProcessingStopped",
1054 snprintf(job_id
, sizeof(job_id
), "%d", job
->id
);
1056 m
= asl_new(ASL_TYPE_MSG
);
1057 asl_set(m
, ASL_KEY_FACILITY
, "org.cups.cupsd");
1058 asl_set(m
, PWG_Event
, "JobStateChanged");
1059 asl_set(m
, PWG_ServiceURI
, job
->printer
->uri
);
1060 asl_set(m
, PWG_JobID
, job_id
);
1061 asl_set(m
, PWG_JobState
, job_states
[job
->state_value
- IPP_JSTATE_PENDING
]);
1063 if (job
->impressions
)
1065 snprintf(completed
, sizeof(completed
), "%d", ippGetInteger(job
->impressions
, 0));
1066 asl_set(m
, PWG_JobImpressionsCompleted
, completed
);
1069 asl_log(NULL
, m
, ASL_LEVEL_INFO
, "%s", buffer
);
1075 #elif defined(HAVE_SYSTEMD_SD_JOURNAL_H)
1076 if (!strcmp(ErrorLog
, "syslog"))
1078 static const char * const job_states
[] =
1079 { /* job-state strings */
1083 "ProcessingStopped",
1089 sd_journal_send("MESSAGE=%s", buffer
,
1090 "PRIORITY=%i", LOG_INFO
,
1091 PWG_Event
"=JobStateChanged",
1092 PWG_ServiceURI
"=%s", job
->printer
->uri
,
1093 PWG_JobID
"=%d", job
->id
,
1094 PWG_JobState
"=%s", job_states
[job
->state_value
- IPP_JSTATE_PENDING
],
1095 PWG_JobImpressionsCompleted
"=%d", ippGetInteger(job
->impressions
, 0),
1100 #elif defined(HAVE_VSYSLOG)
1102 * See if we are logging pages via syslog...
1105 if (!strcmp(PageLog
, "syslog"))
1107 syslog(LOG_INFO
, "%s", buffer
);
1111 #endif /* HAVE_ASL_H */
1114 * Not using syslog; check the log file...
1117 if (!cupsdCheckLogFile(&PageFile
, PageLog
))
1121 * Print a page log entry of the form:
1123 * printer user job-id [DD/MON/YYYY:HH:MM:SS +TTTT] page num-copies \
1127 cupsFilePrintf(PageFile
, "%s\n", buffer
);
1128 cupsFileFlush(PageFile
);
1135 * 'cupsdLogRequest()' - Log an HTTP request in Common Log Format.
1138 int /* O - 1 on success, 0 on error */
1139 cupsdLogRequest(cupsd_client_t
*con
, /* I - Request to log */
1140 http_status_t code
) /* I - Response code */
1142 char temp
[2048]; /* Temporary string for URI */
1143 static const char * const states
[] = /* HTTP client states... */
1163 * Filter requests as needed...
1166 if (AccessLogLevel
== CUPSD_ACCESSLOG_NONE
)
1168 else if (AccessLogLevel
< CUPSD_ACCESSLOG_ALL
)
1171 * Eliminate simple GET, POST, and PUT requests...
1174 if ((con
->operation
== HTTP_GET
&&
1175 strncmp(con
->uri
, "/admin/conf", 11) &&
1176 strncmp(con
->uri
, "/admin/log", 10)) ||
1177 (con
->operation
== HTTP_POST
&& !con
->request
&&
1178 strncmp(con
->uri
, "/admin", 6)) ||
1179 (con
->operation
!= HTTP_GET
&& con
->operation
!= HTTP_POST
&&
1180 con
->operation
!= HTTP_PUT
))
1183 if (con
->request
&& con
->response
&&
1184 (con
->response
->request
.status
.status_code
< IPP_REDIRECTION_OTHER_SITE
||
1185 con
->response
->request
.status
.status_code
== IPP_NOT_FOUND
))
1188 * Check successful requests...
1191 ipp_op_t op
= con
->request
->request
.op
.operation_id
;
1192 static cupsd_accesslog_t standard_ops
[] =
1194 CUPSD_ACCESSLOG_ALL
, /* reserved */
1195 CUPSD_ACCESSLOG_ALL
, /* reserved */
1196 CUPSD_ACCESSLOG_ACTIONS
,/* Print-Job */
1197 CUPSD_ACCESSLOG_ACTIONS
,/* Print-URI */
1198 CUPSD_ACCESSLOG_ACTIONS
,/* Validate-Job */
1199 CUPSD_ACCESSLOG_ACTIONS
,/* Create-Job */
1200 CUPSD_ACCESSLOG_ACTIONS
,/* Send-Document */
1201 CUPSD_ACCESSLOG_ACTIONS
,/* Send-URI */
1202 CUPSD_ACCESSLOG_ACTIONS
,/* Cancel-Job */
1203 CUPSD_ACCESSLOG_ALL
, /* Get-Job-Attributes */
1204 CUPSD_ACCESSLOG_ALL
, /* Get-Jobs */
1205 CUPSD_ACCESSLOG_ALL
, /* Get-Printer-Attributes */
1206 CUPSD_ACCESSLOG_ACTIONS
,/* Hold-Job */
1207 CUPSD_ACCESSLOG_ACTIONS
,/* Release-Job */
1208 CUPSD_ACCESSLOG_ACTIONS
,/* Restart-Job */
1209 CUPSD_ACCESSLOG_ALL
, /* reserved */
1210 CUPSD_ACCESSLOG_CONFIG
, /* Pause-Printer */
1211 CUPSD_ACCESSLOG_CONFIG
, /* Resume-Printer */
1212 CUPSD_ACCESSLOG_CONFIG
, /* Purge-Jobs */
1213 CUPSD_ACCESSLOG_CONFIG
, /* Set-Printer-Attributes */
1214 CUPSD_ACCESSLOG_ACTIONS
,/* Set-Job-Attributes */
1215 CUPSD_ACCESSLOG_CONFIG
, /* Get-Printer-Supported-Values */
1216 CUPSD_ACCESSLOG_ACTIONS
,/* Create-Printer-Subscription */
1217 CUPSD_ACCESSLOG_ACTIONS
,/* Create-Job-Subscription */
1218 CUPSD_ACCESSLOG_ALL
, /* Get-Subscription-Attributes */
1219 CUPSD_ACCESSLOG_ALL
, /* Get-Subscriptions */
1220 CUPSD_ACCESSLOG_ACTIONS
,/* Renew-Subscription */
1221 CUPSD_ACCESSLOG_ACTIONS
,/* Cancel-Subscription */
1222 CUPSD_ACCESSLOG_ALL
, /* Get-Notifications */
1223 CUPSD_ACCESSLOG_ACTIONS
,/* Send-Notifications */
1224 CUPSD_ACCESSLOG_ALL
, /* reserved */
1225 CUPSD_ACCESSLOG_ALL
, /* reserved */
1226 CUPSD_ACCESSLOG_ALL
, /* reserved */
1227 CUPSD_ACCESSLOG_ALL
, /* Get-Print-Support-Files */
1228 CUPSD_ACCESSLOG_CONFIG
, /* Enable-Printer */
1229 CUPSD_ACCESSLOG_CONFIG
, /* Disable-Printer */
1230 CUPSD_ACCESSLOG_CONFIG
, /* Pause-Printer-After-Current-Job */
1231 CUPSD_ACCESSLOG_ACTIONS
,/* Hold-New-Jobs */
1232 CUPSD_ACCESSLOG_ACTIONS
,/* Release-Held-New-Jobs */
1233 CUPSD_ACCESSLOG_CONFIG
, /* Deactivate-Printer */
1234 CUPSD_ACCESSLOG_CONFIG
, /* Activate-Printer */
1235 CUPSD_ACCESSLOG_CONFIG
, /* Restart-Printer */
1236 CUPSD_ACCESSLOG_CONFIG
, /* Shutdown-Printer */
1237 CUPSD_ACCESSLOG_CONFIG
, /* Startup-Printer */
1238 CUPSD_ACCESSLOG_ACTIONS
,/* Reprocess-Job */
1239 CUPSD_ACCESSLOG_ACTIONS
,/* Cancel-Current-Job */
1240 CUPSD_ACCESSLOG_ACTIONS
,/* Suspend-Current-Job */
1241 CUPSD_ACCESSLOG_ACTIONS
,/* Resume-Job */
1242 CUPSD_ACCESSLOG_ACTIONS
,/* Promote-Job */
1243 CUPSD_ACCESSLOG_ACTIONS
/* Schedule-Job-After */
1245 static cupsd_accesslog_t cups_ops
[] =
1247 CUPSD_ACCESSLOG_ALL
, /* CUPS-Get-Default */
1248 CUPSD_ACCESSLOG_ALL
, /* CUPS-Get-Printers */
1249 CUPSD_ACCESSLOG_CONFIG
, /* CUPS-Add-Modify-Printer */
1250 CUPSD_ACCESSLOG_CONFIG
, /* CUPS-Delete-Printer */
1251 CUPSD_ACCESSLOG_ALL
, /* CUPS-Get-Classes */
1252 CUPSD_ACCESSLOG_CONFIG
, /* CUPS-Add-Modify-Class */
1253 CUPSD_ACCESSLOG_CONFIG
, /* CUPS-Delete-Class */
1254 CUPSD_ACCESSLOG_CONFIG
, /* CUPS-Accept-Jobs */
1255 CUPSD_ACCESSLOG_CONFIG
, /* CUPS-Reject-Jobs */
1256 CUPSD_ACCESSLOG_CONFIG
, /* CUPS-Set-Default */
1257 CUPSD_ACCESSLOG_CONFIG
, /* CUPS-Get-Devices */
1258 CUPSD_ACCESSLOG_CONFIG
, /* CUPS-Get-PPDs */
1259 CUPSD_ACCESSLOG_ACTIONS
,/* CUPS-Move-Job */
1260 CUPSD_ACCESSLOG_ACTIONS
,/* CUPS-Authenticate-Job */
1261 CUPSD_ACCESSLOG_ALL
/* CUPS-Get-PPD */
1265 if ((op
<= IPP_SCHEDULE_JOB_AFTER
&& standard_ops
[op
] > AccessLogLevel
) ||
1266 (op
>= CUPS_GET_DEFAULT
&& op
<= CUPS_GET_PPD
&&
1267 cups_ops
[op
- CUPS_GET_DEFAULT
] > AccessLogLevel
))
1273 if (!strcmp(ErrorLog
, "syslog"))
1275 asl_object_t m
; /* Log message */
1277 m
= asl_new(ASL_TYPE_MSG
);
1278 asl_set(m
, ASL_KEY_FACILITY
, "org.cups.cupsd");
1280 asl_log(NULL
, m
, ASL_LEVEL_INFO
, "REQUEST %s - %s \"%s %s HTTP/%d.%d\" %d " CUPS_LLFMT
" %s %s\n",
1281 con
->http
->hostname
, con
->username
[0] != '\0' ? con
->username
: "-",
1282 states
[con
->operation
], _httpEncodeURI(temp
, con
->uri
, sizeof(temp
)),
1283 con
->http
->version
/ 100, con
->http
->version
% 100,
1284 code
, CUPS_LLCAST con
->bytes
,
1286 ippOpString(con
->request
->request
.op
.operation_id
) : "-",
1288 ippErrorString(con
->response
->request
.status
.status_code
) : "-");
1294 #elif defined(HAVE_SYSTEMD_SD_JOURNAL_H)
1295 if (!strcmp(ErrorLog
, "syslog"))
1297 sd_journal_print(LOG_INFO
, "REQUEST %s - %s \"%s %s HTTP/%d.%d\" %d " CUPS_LLFMT
" %s %s", con
->http
->hostname
, con
->username
[0] != '\0' ? con
->username
: "-", states
[con
->operation
], _httpEncodeURI(temp
, con
->uri
, sizeof(temp
)), con
->http
->version
/ 100, con
->http
->version
% 100, code
, CUPS_LLCAST con
->bytes
, con
->request
? ippOpString(con
->request
->request
.op
.operation_id
) : "-", con
->response
? ippErrorString(con
->response
->request
.status
.status_code
) : "-");
1301 #elif defined(HAVE_VSYSLOG)
1303 * See if we are logging accesses via syslog...
1306 if (!strcmp(AccessLog
, "syslog"))
1309 "REQUEST %s - %s \"%s %s HTTP/%d.%d\" %d " CUPS_LLFMT
" %s %s\n",
1310 con
->http
->hostname
, con
->username
[0] != '\0' ? con
->username
: "-",
1311 states
[con
->operation
], _httpEncodeURI(temp
, con
->uri
, sizeof(temp
)),
1312 con
->http
->version
/ 100, con
->http
->version
% 100,
1313 code
, CUPS_LLCAST con
->bytes
,
1315 ippOpString(con
->request
->request
.op
.operation_id
) : "-",
1317 ippErrorString(con
->response
->request
.status
.status_code
) : "-");
1321 #endif /* HAVE_ASL_H */
1324 * Not using syslog; check the log file...
1327 if (!cupsdCheckLogFile(&AccessFile
, AccessLog
))
1331 * Write a log of the request in "common log format"...
1334 cupsFilePrintf(AccessFile
,
1335 "%s - %s %s \"%s %s HTTP/%d.%d\" %d " CUPS_LLFMT
" %s %s\n",
1336 con
->http
->hostname
,
1337 con
->username
[0] != '\0' ? con
->username
: "-",
1338 cupsdGetDateTime(&(con
->start
), LogTimeFormat
),
1339 states
[con
->operation
],
1340 _httpEncodeURI(temp
, con
->uri
, sizeof(temp
)),
1341 con
->http
->version
/ 100, con
->http
->version
% 100,
1342 code
, CUPS_LLCAST con
->bytes
,
1344 ippOpString(con
->request
->request
.op
.operation_id
) : "-",
1346 ippErrorString(con
->response
->request
.status
.status_code
) :
1349 cupsFileFlush(AccessFile
);
1356 * 'cupsdWriteErrorLog()' - Write a line to the ErrorLog.
1359 int /* O - 1 on success, 0 on failure */
1360 cupsdWriteErrorLog(int level
, /* I - Log level */
1361 const char *message
) /* I - Message string */
1363 int ret
= 1; /* Return value */
1364 static const char levels
[] = /* Log levels... */
1380 if (!strcmp(ErrorLog
, "syslog"))
1382 asl_object_t m
; /* Log message */
1384 m
= asl_new(ASL_TYPE_MSG
);
1385 asl_set(m
, ASL_KEY_FACILITY
, "org.cups.cupsd");
1386 asl_log(NULL
, m
, ASL_LEVEL_INFO
, "%s", message
);
1392 #elif defined(HAVE_SYSTEMD_SD_JOURNAL_H)
1393 if (!strcmp(ErrorLog
, "syslog"))
1395 sd_journal_print(log_levels
[level
], "%s", message
);
1399 #elif defined(HAVE_VSYSLOG)
1401 * See if we are logging errors via syslog...
1404 if (!strcmp(ErrorLog
, "syslog"))
1406 syslog(log_levels
[level
], "%s", message
);
1409 #endif /* HAVE_ASL_H */
1412 * Not using syslog; check the log file...
1415 _cupsMutexLock(&log_mutex
);
1417 if (!cupsdCheckLogFile(&ErrorFile
, ErrorLog
))
1424 * Write the log message...
1427 cupsFilePrintf(ErrorFile
, "%c %s %s\n", levels
[level
],
1428 cupsdGetDateTime(NULL
, LogTimeFormat
), message
);
1429 cupsFileFlush(ErrorFile
);
1432 _cupsMutexUnlock(&log_mutex
);
1439 * 'format_log_line()' - Format a line for a log file.
1441 * This function resizes a global string buffer as needed. Each call returns
1442 * a pointer to this buffer, so the contents are only good until the next call
1443 * to format_log_line()...
1446 static int /* O - -1 for fatal, 0 for retry, 1 for success */
1447 format_log_line(const char *message
, /* I - Printf-style format string */
1448 va_list ap
) /* I - Argument list */
1450 ssize_t len
; /* Length of formatted line */
1454 * Allocate the line buffer as needed...
1459 log_linesize
= 8192;
1460 log_line
= malloc(log_linesize
);
1467 * Format the log message...
1470 len
= vsnprintf(log_line
, log_linesize
, message
, ap
);
1473 * Resize the buffer as needed...
1476 if ((size_t)len
>= log_linesize
&& log_linesize
< 65536)
1478 char *temp
; /* Temporary string pointer */
1485 else if (len
> 65536)
1488 temp
= realloc(log_line
, (size_t)len
);
1493 log_linesize
= (size_t)len
;