~ubuntu-branches/ubuntu/utopic/cups/utopic

« back to all changes in this revision

Viewing changes to .pc/fix-job-history-logging.patch/scheduler/log.c

  • Committer: Package Import Robot
  • Author(s): Didier Raboud, Till Kamppeter, Steve Langasek, Didier Raboud
  • Date: 2014-01-03 18:42:39 UTC
  • mfrom: (99.2.3 sid)
  • Revision ID: package-import@ubuntu.com-20140103184239-85wju2l7weie4dgo
Tags: 1.7.0-1
* New 1.7.0 upstream release

[ Till Kamppeter ]
* Refresh most patches with quilt
* Removed usb-backend-do-not-crash-if-usb-disabled-in-bios and
  cupsd-no-crash-on-avahi-threaded-poll-shutdown patches as they got
  applied upstream
* Removed drop-arch-specifics-from-doc patch as it is not needed
  anymore
* Updated drop_unnecessary_dependencies, manpage-hyphen-minus,
  manpage-translations and ppd-poll-with-client-conf patches manually
  to apply to the new CUPS version
* Added error counting exception from
  usb-backend-do-not-crash-if-usb-disabled-in-bios to
  tests-ignore-warnings
* Install the newly added ippfind utility and its manpage in
  cups-client
* Added pwg.h to libcups2-dev package
* Call dh_auto_clean only if the file Makedefs is present, to avoid a
  FTBFS
* Added color management extensions from Joe Simon's GSoC 2013
  project.
* Patch cups-files.conf to activate CUPS daemon syncing of files when
  closing, so that config files (like printers.conf) do not
  mysteriously disappear (LP: #1157972)
* In the AppArmor profile, allow execution of programs in
  /etc/cups/interfaces/, needed to make CUPS working with queues based
  on System V interface scripts, especially PPD-less queues
  auto-generated by cups-browsed from cups-filters 1.0.41 on.
* Silenced AppArmor noise from udev.conf in syslog (LP: #1229766)

[ Steve Langasek ]
* Add cups-filters (>= 1.0.42) as alternative to foomatic-filters
  (which is deprecated) in package relationships

[ Didier Raboud ]
* Remove Roger Leigh from uploaders on his request with thanks for his
  past work!
* Switch avahi LSB Should-Start dependency to be avahi-daemon; also
  bump package relationship to >= 0.6.31-3~ (Closes: #731608)
* Refresh the manpage translation files
* Move the USB backend quirk rules file to cups-server-common
* Add 38 new 1.7.0 libcups2 symbols
* Mark one C++ libcupsppdc1 symbol as optional as it isn't exported in
  1.7.0 anymore
* Import Fedora patches:
  - to avoid sign-extending CRCs in gz decompression
  - to build with full read-only relocations
  - to fix job history logging (upstream patch)
  - to set the internal default for SyncOnClose to Yes, instead of
    only configuring it to Yes
  - to fix a stringpool corruption issue
  - to prevent USB timeouts causing incorrect print output
* Import Fedora patch updates:
  - to dont-use-dbus-from-two-threads patch so it removes a call to
    avahi_threaded_poll_stop()
  - to avoid_stale_lockfile_in_dbus_notifier patch to call _exit when
    handling SIGTERM
* Move manpage-translations patch at the very end of the patch series
  to have it include all our patches

Show diffs side-by-side

added added

removed removed

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