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