2 * "$Id: log.c 6875 2007-08-27 23:25:06Z mike $"
4 * Log file routines for the Common UNIX Printing System (CUPS).
6 * Copyright 2007 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 * cupsdGetDateTime() - Returns a pointer to a date/time string.
18 * cupsdLogGSSMessage() - Log a GSSAPI error...
19 * cupsdLogMessage() - Log a message to the error log file.
20 * cupsdLogPage() - Log a page to the page log file.
21 * cupsdLogRequest() - Log an HTTP request in Common Log Format.
22 * check_log_file() - Open/rotate a log file if it needs it.
26 * Include necessary headers...
38 static int check_log_file(cups_file_t
**, const char *);
42 * 'cupsdGetDateTime()' - Returns a pointer to a date/time string.
45 char * /* O - Date/time string */
46 cupsdGetDateTime(time_t t
) /* I - Time value */
48 struct tm
*date
; /* Date/time value */
49 static time_t last_time
= -1; /* Last time value */
50 static char s
[1024]; /* Date/time string */
51 static const char * const months
[12] =/* Months */
73 * Get the date and time from the UNIX time value, and then format it
74 * into a string. Note that we *can't* use the strftime() function since
75 * it is localized and will seriously confuse automatic programs if the
76 * month names are in the wrong language!
78 * Also, we use the "timezone" variable that contains the current timezone
79 * offset from GMT in seconds so that we are reporting local time in the
80 * log files. If you want GMT, set the TZ environment variable accordingly
81 * before starting the scheduler.
83 * (*BSD and Darwin store the timezone offset in the tm structure)
88 snprintf(s
, sizeof(s
), "[%02d/%s/%04d:%02d:%02d:%02d %+03ld%02ld]",
89 date
->tm_mday
, months
[date
->tm_mon
], 1900 + date
->tm_year
,
90 date
->tm_hour
, date
->tm_min
, date
->tm_sec
,
92 date
->tm_gmtoff
/ 3600, (date
->tm_gmtoff
/ 60) % 60);
94 timezone
/ 3600, (timezone
/ 60) % 60);
95 #endif /* HAVE_TM_GMTOFF */
104 * 'cupsdLogGSSMessage()' - Log a GSSAPI error...
107 int /* O - 1 on success, 0 on error */
109 int level
, /* I - Log level */
110 int major_status
, /* I - Major GSSAPI status */
111 int minor_status
, /* I - Minor GSSAPI status */
112 const char *message
, /* I - printf-style message string */
113 ...) /* I - Additional args as needed */
115 OM_uint32 err_major_status
, /* Major status code for display */
116 err_minor_status
; /* Minor status code for display */
117 OM_uint32 msg_ctx
; /* Message context */
118 gss_buffer_desc major_status_string
= GSS_C_EMPTY_BUFFER
,
119 /* Major status message */
120 minor_status_string
= GSS_C_EMPTY_BUFFER
;
121 /* Minor status message */
122 int ret
; /* Return value */
126 err_major_status
= gss_display_status(&err_minor_status
,
131 &major_status_string
);
133 if (!GSS_ERROR(err_major_status
))
134 err_major_status
= gss_display_status(&err_minor_status
,
139 &minor_status_string
);
141 ret
= cupsdLogMessage(level
, "%s: %s, %s", message
,
142 (char *)major_status_string
.value
,
143 (char *)minor_status_string
.value
);
144 gss_release_buffer(&err_minor_status
, &major_status_string
);
145 gss_release_buffer(&err_minor_status
, &minor_status_string
);
149 #endif /* HAVE_GSSAPI */
153 * 'cupsdLogMessage()' - Log a message to the error log file.
156 int /* O - 1 on success, 0 on error */
157 cupsdLogMessage(int level
, /* I - Log level */
158 const char *message
, /* I - printf-style message string */
159 ...) /* I - Additional args as needed */
161 int len
; /* Length of message */
162 va_list ap
; /* Argument pointer */
163 static const char levels
[] = /* Log levels... */
177 static const int syslevels
[] = /* SYSLOG levels... */
190 #endif /* HAVE_VSYSLOG */
191 static int linesize
= 0; /* Size of line for output file */
192 static char *line
= NULL
; /* Line for output file */
196 * See if we want to log this message...
201 if (level
<= CUPSD_LOG_WARN
)
203 va_start(ap
, message
);
204 vfprintf(stderr
, message
, ap
);
212 if (level
> LogLevel
|| !ErrorLog
)
217 * See if we are logging errors via syslog...
220 if (!strcmp(ErrorLog
, "syslog"))
222 va_start(ap
, message
);
223 vsyslog(syslevels
[level
], message
, ap
);
228 #endif /* HAVE_VSYSLOG */
231 * Not using syslog; check the log file...
234 if (!check_log_file(&ErrorFile
, ErrorLog
))
238 * Print the log level and date/time...
241 cupsFilePrintf(ErrorFile
, "%c %s ", levels
[level
], cupsdGetDateTime(time(NULL
)));
244 * Allocate the line buffer as needed...
250 line
= malloc(linesize
);
254 cupsFilePrintf(ErrorFile
,
255 "ERROR: Unable to allocate memory for line - %s\n",
257 cupsFileFlush(ErrorFile
);
264 * Format the log message...
267 va_start(ap
, message
);
268 len
= vsnprintf(line
, linesize
, message
, ap
);
272 * Resize the buffer as needed...
281 else if (len
> 65536)
284 line
= realloc(line
, len
);
290 cupsFilePrintf(ErrorFile
,
291 "ERROR: Unable to allocate memory for line - %s\n",
293 cupsFileFlush(ErrorFile
);
298 va_start(ap
, message
);
299 len
= vsnprintf(line
, linesize
, message
, ap
);
307 * Then the log message...
310 cupsFilePuts(ErrorFile
, line
);
316 if (len
> 0 && line
[len
- 1] != '\n')
317 cupsFilePutChar(ErrorFile
, '\n');
320 * Flush the line to the file and return...
323 cupsFileFlush(ErrorFile
);
330 * 'cupsdLogPage()' - Log a page to the page log file.
333 int /* O - 1 on success, 0 on error */
334 cupsdLogPage(cupsd_job_t
*job
, /* I - Job being printed */
335 const char *page
) /* I - Page being printed */
337 ipp_attribute_t
*billing
, /* job-billing attribute */
338 *hostname
; /* job-originating-host-name attribute */
341 billing
= ippFindAttribute(job
->attrs
, "job-billing", IPP_TAG_ZERO
);
342 hostname
= ippFindAttribute(job
->attrs
, "job-originating-host-name",
347 * See if we are logging pages via syslog...
350 if (!strcmp(PageLog
, "syslog"))
352 syslog(LOG_INFO
, "PAGE %s %s %d %s %s %s", job
->printer
->name
,
353 job
->username
? job
->username
: "-",
354 job
->id
, page
, billing
? billing
->values
[0].string
.text
: "-",
355 hostname
->values
[0].string
.text
);
359 #endif /* HAVE_VSYSLOG */
362 * Not using syslog; check the log file...
365 if (!check_log_file(&PageFile
, PageLog
))
369 * Print a page log entry of the form:
371 * printer job-id user [DD/MON/YYYY:HH:MM:SS +TTTT] page num-copies \
375 cupsFilePrintf(PageFile
, "%s %s %d %s %s %s %s\n", job
->printer
->name
,
376 job
->username
? job
->username
: "-",
377 job
->id
, cupsdGetDateTime(time(NULL
)), page
,
378 billing
? billing
->values
[0].string
.text
: "-",
379 hostname
->values
[0].string
.text
);
380 cupsFileFlush(PageFile
);
387 * 'cupsdLogRequest()' - Log an HTTP request in Common Log Format.
390 int /* O - 1 on success, 0 on error */
391 cupsdLogRequest(cupsd_client_t
*con
, /* I - Request to log */
392 http_status_t code
) /* I - Response code */
394 static const char * const states
[] = /* HTTP client states... */
415 * See if we are logging accesses via syslog...
418 if (!strcmp(AccessLog
, "syslog"))
421 "REQUEST %s - %s \"%s %s HTTP/%d.%d\" %d " CUPS_LLFMT
" %s %s\n",
422 con
->http
.hostname
, con
->username
[0] != '\0' ? con
->username
: "-",
423 states
[con
->operation
], con
->uri
,
424 con
->http
.version
/ 100, con
->http
.version
% 100,
425 code
, CUPS_LLCAST con
->bytes
,
427 ippOpString(con
->request
->request
.op
.operation_id
) : "-",
429 ippErrorString(con
->response
->request
.status
.status_code
) : "-");
433 #endif /* HAVE_VSYSLOG */
436 * Not using syslog; check the log file...
439 if (!check_log_file(&AccessFile
, AccessLog
))
443 * Write a log of the request in "common log format"...
446 cupsFilePrintf(AccessFile
,
447 "%s - %s %s \"%s %s HTTP/%d.%d\" %d " CUPS_LLFMT
" %s %s\n",
448 con
->http
.hostname
, con
->username
[0] != '\0' ? con
->username
: "-",
449 cupsdGetDateTime(con
->start
), states
[con
->operation
], con
->uri
,
450 con
->http
.version
/ 100, con
->http
.version
% 100,
451 code
, CUPS_LLCAST con
->bytes
,
453 ippOpString(con
->request
->request
.op
.operation_id
) : "-",
455 ippErrorString(con
->response
->request
.status
.status_code
) :
458 cupsFileFlush(AccessFile
);
465 * 'check_log_file()' - Open/rotate a log file if it needs it.
468 static int /* O - 1 if log file open */
469 check_log_file(cups_file_t
**lf
, /* IO - Log file */
470 const char *logname
) /* I - Log filename */
472 char backname
[1024], /* Backup log filename */
473 filename
[1024], /* Formatted log filename */
474 *ptr
; /* Pointer into filename */
475 const char *logptr
; /* Pointer into log filename */
479 * See if we have a log file to check...
482 if (!lf
|| !logname
|| !logname
[0])
486 * Format the filename as needed...
490 (strncmp(logname
, "/dev/", 5) && cupsFileTell(*lf
) > MaxLogSize
&&
494 * Handle format strings...
497 filename
[sizeof(filename
) - 1] = '\0';
499 if (logname
[0] != '/')
501 strlcpy(filename
, ServerRoot
, sizeof(filename
));
502 strlcat(filename
, "/", sizeof(filename
));
507 for (logptr
= logname
, ptr
= filename
+ strlen(filename
);
508 *logptr
&& ptr
< (filename
+ sizeof(filename
) - 1);
520 * Insert the server name...
523 strlcpy(ptr
, ServerName
, sizeof(filename
) - (ptr
- filename
));
529 * Otherwise just insert the character...
542 * See if the log file is open...
548 * Nope, open the log file...
551 if ((*lf
= cupsFileOpen(filename
, "a")) == NULL
)
554 * If the file is in CUPS_LOGDIR then try to create a missing directory...
557 if (!strncmp(filename
, CUPS_LOGDIR
, strlen(CUPS_LOGDIR
)))
559 cupsdCheckPermissions(CUPS_LOGDIR
, NULL
, 0755, RunUser
, Group
, 1, -1);
561 *lf
= cupsFileOpen(filename
, "a");
566 syslog(LOG_ERR
, "Unable to open log file \"%s\" - %s", filename
,
572 if (strncmp(filename
, "/dev/", 5))
575 * Change ownership and permissions of non-device logs...
578 fchown(cupsFileNumber(*lf
), RunUser
, Group
);
579 fchmod(cupsFileNumber(*lf
), LogFilePerm
);
584 * Do we need to rotate the log?
587 if (strncmp(logname
, "/dev/", 5) && cupsFileTell(*lf
) > MaxLogSize
&&
596 strcpy(backname
, filename
);
597 strlcat(backname
, ".O", sizeof(backname
));
600 rename(filename
, backname
);
602 if ((*lf
= cupsFileOpen(filename
, "a")) == NULL
)
604 syslog(LOG_ERR
, "Unable to open log file \"%s\" - %s", filename
,
611 * Change ownership and permissions of non-device logs...
614 fchown(cupsFileNumber(*lf
), RunUser
, Group
);
615 fchmod(cupsFileNumber(*lf
), LogFilePerm
);
623 * End of "$Id: log.c 6875 2007-08-27 23:25:06Z mike $".