Coverage Report

Created: 2026-01-17 06:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/isc/log.c
Line
Count
Source
1
/*
2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3
 *
4
 * SPDX-License-Identifier: MPL-2.0
5
 *
6
 * This Source Code Form is subject to the terms of the Mozilla Public
7
 * License, v. 2.0. If a copy of the MPL was not distributed with this
8
 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9
 *
10
 * See the COPYRIGHT file distributed with this work for additional
11
 * information regarding copyright ownership.
12
 */
13
14
/*! \file */
15
16
#include <errno.h>
17
#include <inttypes.h>
18
#include <limits.h>
19
#include <stdbool.h>
20
#include <stdlib.h>
21
#include <sys/stat.h>
22
#include <sys/types.h> /* dev_t FreeBSD 2.1 */
23
#include <time.h>
24
#include <unistd.h>
25
26
#include <isc/atomic.h>
27
#include <isc/dir.h>
28
#include <isc/errno.h>
29
#include <isc/file.h>
30
#include <isc/log.h>
31
#include <isc/magic.h>
32
#include <isc/mem.h>
33
#include <isc/stdio.h>
34
#include <isc/string.h>
35
#include <isc/thread.h>
36
#include <isc/time.h>
37
#include <isc/urcu.h>
38
#include <isc/util.h>
39
40
2
#define LCTX_MAGIC      ISC_MAGIC('L', 'c', 't', 'x')
41
#define VALID_CONTEXT(lctx) ISC_MAGIC_VALID(lctx, LCTX_MAGIC)
42
43
2
#define LCFG_MAGIC     ISC_MAGIC('L', 'c', 'f', 'g')
44
#define VALID_CONFIG(lcfg) ISC_MAGIC_VALID(lcfg, LCFG_MAGIC)
45
46
static thread_local bool forcelog = false;
47
48
/*
49
 * XXXDCL make dynamic?
50
 */
51
#define LOG_BUFFER_SIZE (8 * 1024)
52
53
/*
54
 * Private isc_log_t data type.
55
 */
56
typedef struct isc_log isc_log_t;
57
58
/*!
59
 * This is the structure that holds each named channel.  A simple linked
60
 * list chains all of the channels together, so an individual channel is
61
 * found by doing strcmp()s with the names down the list.  Their should
62
 * be no performance penalty from this as it is expected that the number
63
 * of named channels will be no more than a dozen or so, and name lookups
64
 * from the head of the list are only done when isc_log_usechannel() is
65
 * called, which should also be very infrequent.
66
 */
67
typedef struct isc_logchannel isc_logchannel_t;
68
69
struct isc_logchannel {
70
  char *name;
71
  unsigned int type;
72
  int level;
73
  unsigned int flags;
74
  isc_logdestination_t destination;
75
  ISC_LINK(isc_logchannel_t) link;
76
};
77
78
/*!
79
 * The logchannellist structure associates categories and modules with
80
 * channels.  First the appropriate channellist is found based on the
81
 * category, and then each structure in the linked list is checked for
82
 * a matching module.  It is expected that the number of channels
83
 * associated with any given category will be very short, no more than
84
 * three or four in the more unusual cases.
85
 */
86
typedef struct isc_logchannellist isc_logchannellist_t;
87
88
struct isc_logchannellist {
89
  isc_logmodule_t module;
90
  isc_logchannel_t *channel;
91
  ISC_LINK(isc_logchannellist_t) link;
92
};
93
94
/*!
95
 * This structure is used to remember messages for pruning via
96
 * isc_log_[v]write1().
97
 */
98
typedef struct isc_logmessage isc_logmessage_t;
99
100
struct isc_logmessage {
101
  char *text;
102
  isc_time_t time;
103
  ISC_LINK(isc_logmessage_t) link;
104
};
105
106
/*!
107
 * The isc_logconfig structure is used to store the configurable information
108
 * about where messages are actually supposed to be sent -- the information
109
 * that could changed based on some configuration file, as opposed to the
110
 * the category/module specification of isc_log_[v]write[1] that is compiled
111
 * into a program, or the debug_level which is dynamic state information.
112
 */
113
struct isc_logconfig {
114
  unsigned int magic;
115
  isc_log_t *lctx;
116
  ISC_LIST(isc_logchannel_t) channels;
117
  ISC_LIST(isc_logchannellist_t) channellists[ISC_LOGCATEGORY_MAX];
118
  int_fast32_t highest_level;
119
  char *tag;
120
  bool dynamic;
121
};
122
123
/*!
124
 * This isc_log structure provides the context for the isc_log functions.
125
 * The log context locks itself in isc_log_doit, the internal backend to
126
 * isc_log_write.  The locking is necessary both to provide exclusive access
127
 * to the buffer into which the message is formatted and to guard against
128
 * competing threads trying to write to the same syslog resource.
129
 *
130
 * FIXME: We can remove the locking by using per-thread .buffer.
131
 */
132
struct isc_log {
133
  /* Not locked. */
134
  unsigned int magic;
135
  isc_mem_t *mctx;
136
  atomic_int_fast32_t debug_level;
137
  /* RCU-protected pointer */
138
  isc_logconfig_t *logconfig;
139
  isc_mutex_t lock;
140
  /* Locked by isc_log lock. */
141
  char buffer[LOG_BUFFER_SIZE];
142
  atomic_bool dynamic;
143
  atomic_int_fast32_t highest_level;
144
};
145
146
/*!
147
 * Used when ISC_LOG_PRINTLEVEL is enabled for a channel.
148
 */
149
static const char *log_level_strings[] = { "debug",   "info",  "notice",
150
             "warning", "error", "critical" };
151
152
/*!
153
 * Used to convert ISC_LOG_* priorities into syslog priorities.
154
 * XXXDCL This will need modification for NT.
155
 */
156
static const int syslog_map[] = { LOG_DEBUG,   LOG_INFO, LOG_NOTICE,
157
          LOG_WARNING, LOG_ERR,  LOG_CRIT };
158
159
/*!
160
 * When adding new categories, a corresponding ISC_LOGCATEGORY_foo
161
 * definition needs to be added to <isc/log.h>.
162
 *
163
 * The default category is provided so that the internal default can
164
 * be overridden.  Since the default is always looked up as the first
165
 * channellist in the log context, it must come first in isc_categories[].
166
 */
167
static const char *categories_description[] = {
168
  /* libisc categories */
169
  [ISC_LOGCATEGORY_DEFAULT] = "default",
170
  [ISC_LOGCATEGORY_GENERAL] = "general",
171
  [ISC_LOGCATEGORY_SSLKEYLOG] = "sslkeylog",
172
  /* dns categories */
173
  [DNS_LOGCATEGORY_CNAME] = "cname",
174
  [DNS_LOGCATEGORY_DATABASE] = "database",
175
  [DNS_LOGCATEGORY_DISPATCH] = "dispatch",
176
  [DNS_LOGCATEGORY_DNSSEC] = "dnssec",
177
  [DNS_LOGCATEGORY_DNSTAP] = "dnstap",
178
  [DNS_LOGCATEGORY_EDNS_DISABLED] = "edns-disabled",
179
  [DNS_LOGCATEGORY_LAME_SERVERS] = "lame-servers",
180
  [DNS_LOGCATEGORY_NOTIFY] = "notify",
181
  [DNS_LOGCATEGORY_NSID] = "nsid",
182
  [DNS_LOGCATEGORY_RESOLVER] = "resolver",
183
  [DNS_LOGCATEGORY_RPZ] = "rpz",
184
  [DNS_LOGCATEGORY_RPZ_PASSTHRU] = "rpz-passthru",
185
  [DNS_LOGCATEGORY_RRL] = "rate-limit",
186
  [DNS_LOGCATEGORY_SECURITY] = "security",
187
  [DNS_LOGCATEGORY_SPILL] = "spill",
188
  [DNS_LOGCATEGORY_UPDATE_POLICY] = "update-policy",
189
  [DNS_LOGCATEGORY_XFER_IN] = "xfer-in",
190
  [DNS_LOGCATEGORY_XFER_OUT] = "xfer-out",
191
  [DNS_LOGCATEGORY_ZONELOAD] = "zoneload",
192
  [DNS_LOGCATEGORY_ZONEVERSION] = "zoneversion",
193
  /* ns categories */
194
  [NS_LOGCATEGORY_CLIENT] = "client",
195
  [NS_LOGCATEGORY_DRA] = "dns-reporting-agent",
196
  [NS_LOGCATEGORY_NETWORK] = "network",
197
  [NS_LOGCATEGORY_QUERIES] = "queries",
198
  [NS_LOGCATEGORY_QUERY_ERRORS] = "query-errors",
199
  [NS_LOGCATEGORY_RESPONSES] = "responses",
200
  [NS_LOGCATEGORY_SERVE_STALE] = "serve-stale",
201
  [NS_LOGCATEGORY_TAT] = "trust-anchor-telemetry",
202
  [NS_LOGCATEGORY_UPDATE] = "update",
203
  [NS_LOGCATEGORY_UPDATE_SECURITY] = "update-security",
204
  /* cfg categories */
205
  [CFG_LOGCATEGORY_CONFIG] = "config",
206
  /* named categories */
207
  [NAMED_LOGCATEGORY_UNMATCHED] = "unmatched",
208
  /* delv categories */
209
  [DELV_LOGCATEGORY_DEFAULT] = "delv",
210
};
211
212
/*!
213
 * See above comment for categories, and apply it to modules.
214
 */
215
static const char *modules_description[] = {
216
  /* isc modules */
217
  [ISC_LOGMODULE_DEFAULT] = "no_module",
218
  [ISC_LOGMODULE_SOCKET] = "socket",
219
  [ISC_LOGMODULE_TIME] = "time",
220
  [ISC_LOGMODULE_INTERFACE] = "interface",
221
  [ISC_LOGMODULE_TIMER] = "timer",
222
  [ISC_LOGMODULE_FILE] = "file",
223
  [ISC_LOGMODULE_NETMGR] = "netmgr",
224
  [ISC_LOGMODULE_OTHER] = "other",
225
  [ISC_LOGMODULE_CRYPTO] = "crypto",
226
  /* dns modules */
227
  [DNS_LOGMODULE_DB] = "dns/db",
228
  [DNS_LOGMODULE_RDATA] = "dns/rdata",
229
  [DNS_LOGMODULE_MASTER] = "dns/master",
230
  [DNS_LOGMODULE_MESSAGE] = "dns/message",
231
  [DNS_LOGMODULE_CACHE] = "dns/cache",
232
  [DNS_LOGMODULE_CONFIG] = "dns/config",
233
  [DNS_LOGMODULE_RESOLVER] = "dns/resolver",
234
  [DNS_LOGMODULE_ZONE] = "dns/zone",
235
  [DNS_LOGMODULE_JOURNAL] = "dns/journal",
236
  [DNS_LOGMODULE_ADB] = "dns/adb",
237
  [DNS_LOGMODULE_XFER_IN] = "dns/xfrin",
238
  [DNS_LOGMODULE_XFER_OUT] = "dns/xfrout",
239
  [DNS_LOGMODULE_ACL] = "dns/acl",
240
  [DNS_LOGMODULE_VALIDATOR] = "dns/validator",
241
  [DNS_LOGMODULE_DISPATCH] = "dns/dispatch",
242
  [DNS_LOGMODULE_REQUEST] = "dns/request",
243
  [DNS_LOGMODULE_MASTERDUMP] = "dns/masterdump",
244
  [DNS_LOGMODULE_TSIG] = "dns/tsig",
245
  [DNS_LOGMODULE_TKEY] = "dns/tkey",
246
  [DNS_LOGMODULE_SDB] = "dns/sdb",
247
  [DNS_LOGMODULE_DIFF] = "dns/diff",
248
  [DNS_LOGMODULE_HINTS] = "dns/hints",
249
  [DNS_LOGMODULE_UNUSED1] = "dns/unused1",
250
  [DNS_LOGMODULE_DLZ] = "dns/dlz",
251
  [DNS_LOGMODULE_DNSSEC] = "dns/dnssec",
252
  [DNS_LOGMODULE_CRYPTO] = "dns/crypto",
253
  [DNS_LOGMODULE_PACKETS] = "dns/packets",
254
  [DNS_LOGMODULE_NTA] = "dns/nta",
255
  [DNS_LOGMODULE_DYNDB] = "dns/dyndb",
256
  [DNS_LOGMODULE_DNSTAP] = "dns/dnstap",
257
  [DNS_LOGMODULE_SSU] = "dns/ssu",
258
  [DNS_LOGMODULE_QP] = "dns/qp",
259
  [DNS_LOGMODULE_RPZ] = "dns/rpz",
260
  [DNS_LOGMODULE_CATZ] = "dns/catz",
261
  /* ns modules */
262
  [NS_LOGMODULE_CLIENT] = "ns/client",
263
  [NS_LOGMODULE_QUERY] = "ns/query",
264
  [NS_LOGMODULE_INTERFACEMGR] = "ns/interfacemgr",
265
  [NS_LOGMODULE_UPDATE] = "ns/update",
266
  [NS_LOGMODULE_XFER_IN] = "ns/xfer-in",
267
  [NS_LOGMODULE_XFER_OUT] = "ns/xfer-out",
268
  [NS_LOGMODULE_NOTIFY] = "ns/notify",
269
  [NS_LOGMODULE_HOOKS] = "ns/hooks",
270
  /* cfg modules */
271
  [CFG_LOGMODULE_PARSER] = "isccfg/parser",
272
  /* named modules */
273
  [NAMED_LOGMODULE_MAIN] = "main",
274
  [NAMED_LOGMODULE_SERVER] = "server",
275
  [NAMED_LOGMODULE_CONTROL] = "control",
276
  /* delv modules */
277
  [DELV_LOGMODULE_DEFAULT] = "delv",
278
};
279
280
/*!
281
 * This essentially constant structure must be filled in at run time,
282
 * because its channel member is pointed to a channel that is created
283
 * dynamically with isc_log_createchannel.
284
 */
285
static isc_logchannellist_t default_channel;
286
287
/*!
288
 * libisc logs to this context.
289
 */
290
static isc_log_t *isc__lctx = NULL;
291
292
/*!
293
 * Forward declarations.
294
 */
295
static void
296
assignchannel(isc_logconfig_t *lcfg, const isc_logcategory_t category,
297
        const isc_logmodule_t module, isc_logchannel_t *channel);
298
299
static void
300
sync_highest_level(isc_logconfig_t *lcfg);
301
302
static isc_result_t
303
greatest_version(isc_logfile_t *file, int versions, int *greatest);
304
305
static void
306
isc_log_doit(isc_logcategory_t category, isc_logmodule_t module, int level,
307
       const char *format, va_list args) ISC_FORMAT_PRINTF(4, 0);
308
309
/*@{*/
310
/*!
311
 * Convenience macros.
312
 */
313
314
2
#define FACILITY(channel)  (channel->destination.facility)
315
4
#define FILE_NAME(channel)   (channel->destination.file.name)
316
4
#define FILE_STREAM(channel)   (channel->destination.file.stream)
317
4
#define FILE_VERSIONS(channel)   (channel->destination.file.versions)
318
4
#define FILE_SUFFIX(channel)   (channel->destination.file.suffix)
319
4
#define FILE_MAXSIZE(channel)  (channel->destination.file.maximum_size)
320
0
#define FILE_MAXREACHED(channel) (channel->destination.file.maximum_reached)
321
322
/*@}*/
323
/****
324
**** Public interfaces.
325
****/
326
327
void
328
2
isc_logconfig_create(isc_logconfig_t **lcfgp) {
329
2
  REQUIRE(lcfgp != NULL && *lcfgp == NULL);
330
2
  REQUIRE(VALID_CONTEXT(isc__lctx));
331
332
2
  int level = ISC_LOG_INFO;
333
334
2
  isc_logconfig_t *lcfg = isc_mem_get(isc__lctx->mctx, sizeof(*lcfg));
335
336
2
  *lcfg = (isc_logconfig_t){
337
2
    .magic = LCFG_MAGIC,
338
2
    .lctx = isc__lctx,
339
2
    .channels = ISC_LIST_INITIALIZER,
340
2
    .highest_level = level,
341
2
  };
342
343
  /*
344
   * Create the default channels:
345
   *      default_syslog, default_stderr, default_debug and null.
346
   */
347
2
  isc_log_createchannel(lcfg, "default_syslog", ISC_LOG_TOSYSLOG, level,
348
2
            ISC_LOGDESTINATION_SYSLOG(LOG_DAEMON), 0);
349
350
2
  isc_log_createchannel(lcfg, "default_stderr", ISC_LOG_TOFILEDESC, level,
351
2
            ISC_LOGDESTINATION_STDERR, ISC_LOG_PRINTTIME);
352
353
  /*
354
   * Set the default category's channel to default_stderr,
355
   * which is at the head of the channels list because it was
356
   * just created.
357
   */
358
2
  default_channel.channel = ISC_LIST_HEAD(lcfg->channels);
359
360
2
  isc_log_createchannel(lcfg, "default_debug", ISC_LOG_TOFILEDESC,
361
2
            ISC_LOG_DYNAMIC, ISC_LOGDESTINATION_STDERR,
362
2
            ISC_LOG_PRINTTIME);
363
364
2
  isc_log_createchannel(lcfg, "null", ISC_LOG_TONULL, ISC_LOG_DYNAMIC,
365
2
            NULL, 0);
366
367
2
  *lcfgp = lcfg;
368
2
}
369
370
isc_logconfig_t *
371
0
isc_logconfig_get(void) {
372
0
  REQUIRE(VALID_CONTEXT(isc__lctx));
373
374
0
  return rcu_dereference(isc__lctx->logconfig);
375
0
}
376
377
void
378
0
isc_logconfig_set(isc_logconfig_t *lcfg) {
379
0
  REQUIRE(VALID_CONTEXT(isc__lctx));
380
0
  REQUIRE(VALID_CONFIG(lcfg));
381
0
  REQUIRE(lcfg->lctx == isc__lctx);
382
383
0
  isc_logconfig_t *old_cfg = rcu_xchg_pointer(&isc__lctx->logconfig,
384
0
                lcfg);
385
0
  sync_highest_level(lcfg);
386
0
  synchronize_rcu();
387
388
0
  if (old_cfg != NULL) {
389
0
    isc_logconfig_destroy(&old_cfg);
390
0
  }
391
0
}
392
393
void
394
0
isc_logconfig_destroy(isc_logconfig_t **lcfgp) {
395
0
  isc_logconfig_t *lcfg = NULL;
396
0
  isc_mem_t *mctx = NULL;
397
0
  char *filename = NULL;
398
399
0
  REQUIRE(lcfgp != NULL && VALID_CONFIG(*lcfgp));
400
401
0
  lcfg = *lcfgp;
402
0
  *lcfgp = NULL;
403
404
  /*
405
   * This function cannot be called with a logconfig that is in
406
   * use by a log context.
407
   */
408
0
  REQUIRE(lcfg->lctx != NULL);
409
410
0
  rcu_read_lock();
411
0
  REQUIRE(rcu_dereference(lcfg->lctx->logconfig) != lcfg);
412
0
  rcu_read_unlock();
413
414
0
  mctx = lcfg->lctx->mctx;
415
416
0
  ISC_LIST_FOREACH(lcfg->channels, channel, link) {
417
0
    if (channel->type == ISC_LOG_TOFILE) {
418
      /*
419
       * The filename for the channel may have ultimately
420
       * started its life in user-land as a const string,
421
       * but in isc_log_createchannel it gets copied
422
       * into writable memory and is not longer truly const.
423
       */
424
0
      filename = UNCONST(FILE_NAME(channel));
425
0
      isc_mem_free(mctx, filename);
426
427
0
      if (FILE_STREAM(channel) != NULL) {
428
0
        (void)fclose(FILE_STREAM(channel));
429
0
      }
430
0
    }
431
432
0
    isc_mem_free(mctx, channel->name);
433
0
    isc_mem_put(mctx, channel, sizeof(*channel));
434
0
  }
435
436
0
  for (size_t i = 0; i < ARRAY_SIZE(lcfg->channellists); i++) {
437
0
    ISC_LIST_FOREACH(lcfg->channellists[i], item, link) {
438
0
      ISC_LIST_UNLINK(lcfg->channellists[i], item, link);
439
0
      isc_mem_put(mctx, item, sizeof(*item));
440
0
    }
441
0
  }
442
443
0
  lcfg->dynamic = false;
444
0
  if (lcfg->tag != NULL) {
445
0
    isc_mem_free(lcfg->lctx->mctx, lcfg->tag);
446
0
  }
447
0
  lcfg->highest_level = 0;
448
0
  lcfg->magic = 0;
449
450
0
  isc_mem_put(mctx, lcfg, sizeof(*lcfg));
451
0
}
452
453
isc_logcategory_t
454
0
isc_log_categorybyname(const char *name) {
455
0
  REQUIRE(VALID_CONTEXT(isc__lctx));
456
0
  REQUIRE(name != NULL);
457
458
0
  for (isc_logcategory_t category = 0; category < ISC_LOGCATEGORY_MAX;
459
0
       category++)
460
0
  {
461
0
    if (strcmp(categories_description[category], name) == 0) {
462
0
      return category;
463
0
    }
464
0
  }
465
466
0
  return ISC_LOGCATEGORY_INVALID;
467
0
}
468
469
void
470
isc_log_createchannel(isc_logconfig_t *lcfg, const char *name,
471
          unsigned int type, int level,
472
          const isc_logdestination_t *destination,
473
8
          unsigned int flags) {
474
8
  isc_logchannel_t *channel;
475
8
  isc_mem_t *mctx;
476
8
  unsigned int permitted = ISC_LOG_PRINTALL | ISC_LOG_DEBUGONLY |
477
8
         ISC_LOG_BUFFERED | ISC_LOG_ISO8601 |
478
8
         ISC_LOG_UTC | ISC_LOG_TZINFO;
479
480
8
  REQUIRE(VALID_CONFIG(lcfg));
481
8
  REQUIRE(name != NULL);
482
8
  REQUIRE(type == ISC_LOG_TOSYSLOG || type == ISC_LOG_TOFILE ||
483
8
    type == ISC_LOG_TOFILEDESC || type == ISC_LOG_TONULL);
484
8
  REQUIRE(destination != NULL || type == ISC_LOG_TONULL);
485
8
  REQUIRE(level >= ISC_LOG_CRITICAL);
486
8
  REQUIRE((flags & ~permitted) == 0);
487
8
  REQUIRE(!(flags & ISC_LOG_UTC) || !(flags & ISC_LOG_TZINFO));
488
489
  /* FIXME: find duplicate names? */
490
491
8
  mctx = lcfg->lctx->mctx;
492
493
8
  channel = isc_mem_get(mctx, sizeof(*channel));
494
495
8
  channel->name = isc_mem_strdup(mctx, name);
496
497
8
  channel->type = type;
498
8
  channel->level = level;
499
8
  channel->flags = flags;
500
8
  ISC_LINK_INIT(channel, link);
501
502
8
  switch (type) {
503
2
  case ISC_LOG_TOSYSLOG:
504
2
    FACILITY(channel) = destination->facility;
505
2
    break;
506
507
0
  case ISC_LOG_TOFILE:
508
    /*
509
     * The file name is copied because greatest_version wants
510
     * to scribble on it, so it needs to be definitely in
511
     * writable memory.
512
     */
513
0
    FILE_NAME(channel) = isc_mem_strdup(mctx,
514
0
                destination->file.name);
515
0
    FILE_STREAM(channel) = NULL;
516
0
    FILE_VERSIONS(channel) = destination->file.versions;
517
0
    FILE_SUFFIX(channel) = destination->file.suffix;
518
0
    FILE_MAXSIZE(channel) = destination->file.maximum_size;
519
0
    FILE_MAXREACHED(channel) = false;
520
0
    break;
521
522
4
  case ISC_LOG_TOFILEDESC:
523
4
    FILE_NAME(channel) = NULL;
524
4
    FILE_STREAM(channel) = destination->file.stream;
525
4
    FILE_MAXSIZE(channel) = 0;
526
4
    FILE_VERSIONS(channel) = ISC_LOG_ROLLNEVER;
527
4
    FILE_SUFFIX(channel) = isc_log_rollsuffix_increment;
528
4
    break;
529
530
2
  case ISC_LOG_TONULL:
531
    /* Nothing. */
532
2
    break;
533
534
0
  default:
535
0
    UNREACHABLE();
536
8
  }
537
538
8
  ISC_LIST_PREPEND(lcfg->channels, channel, link);
539
540
  /*
541
   * If default_stderr was redefined, make the default category
542
   * point to the new default_stderr.
543
   */
544
8
  if (strcmp(name, "default_stderr") == 0) {
545
2
    default_channel.channel = channel;
546
2
  }
547
8
}
548
549
isc_result_t
550
isc_log_usechannel(isc_logconfig_t *lcfg, const char *name,
551
       const isc_logcategory_t category,
552
0
       const isc_logmodule_t module) {
553
0
  isc_logchannel_t *channel = NULL;
554
555
0
  REQUIRE(VALID_CONFIG(lcfg));
556
0
  REQUIRE(name != NULL);
557
0
  REQUIRE(category >= ISC_LOGCATEGORY_DEFAULT &&
558
0
    category < ISC_LOGCATEGORY_MAX);
559
0
  REQUIRE(module >= ISC_LOGMODULE_DEFAULT && module < ISC_LOGMODULE_MAX);
560
561
0
  ISC_LIST_FOREACH(lcfg->channels, c, link) {
562
0
    if (strcmp(name, c->name) == 0) {
563
0
      channel = c;
564
0
      break;
565
0
    }
566
0
  }
567
568
0
  if (channel == NULL) {
569
0
    return ISC_R_NOTFOUND;
570
0
  }
571
572
0
  if (category != ISC_LOGCATEGORY_DEFAULT) {
573
0
    assignchannel(lcfg, category, module, channel);
574
0
  } else {
575
    /*
576
     * Assign to all categories.  Note that this includes
577
     * the default channel.
578
     */
579
0
    for (size_t i = ISC_LOGCATEGORY_DEFAULT;
580
0
         i < ISC_LOGCATEGORY_MAX; i++)
581
0
    {
582
0
      assignchannel(lcfg, i, module, channel);
583
0
    }
584
0
  }
585
586
  /*
587
   * Update the highest logging level, if the current lcfg is in use.
588
   */
589
0
  rcu_read_lock();
590
0
  if (rcu_dereference(lcfg->lctx->logconfig) == lcfg) {
591
0
    sync_highest_level(lcfg);
592
0
  }
593
0
  rcu_read_unlock();
594
595
0
  return ISC_R_SUCCESS;
596
0
}
597
598
void
599
isc_log_createandusechannel(isc_logconfig_t *lcfg, const char *name,
600
          unsigned int type, int level,
601
          const isc_logdestination_t *destination,
602
          unsigned int flags,
603
          const isc_logcategory_t category,
604
0
          const isc_logmodule_t module) {
605
0
  isc_log_createchannel(lcfg, name, type, level, destination, flags);
606
0
  RUNTIME_CHECK(isc_log_usechannel(lcfg, name, category, module) ==
607
0
          ISC_R_SUCCESS);
608
0
}
609
610
void
611
isc_log_write(isc_logcategory_t category, isc_logmodule_t module, int level,
612
0
        const char *format, ...) {
613
0
  va_list args;
614
615
  /*
616
   * Contract checking is done in isc_log_doit().
617
   */
618
619
0
  va_start(args, format);
620
0
  isc_log_doit(category, module, level, format, args);
621
0
  va_end(args);
622
0
}
623
624
void
625
isc_log_vwrite(isc_logcategory_t category, isc_logmodule_t module, int level,
626
0
         const char *format, va_list args) {
627
  /*
628
   * Contract checking is done in isc_log_doit().
629
   */
630
0
  isc_log_doit(category, module, level, format, args);
631
0
}
632
633
void
634
0
isc_log_setdebuglevel(unsigned int level) {
635
0
  REQUIRE(VALID_CONTEXT(isc__lctx));
636
637
0
  atomic_store_release(&isc__lctx->debug_level, level);
638
  /*
639
   * Close ISC_LOG_DEBUGONLY channels if level is zero.
640
   */
641
0
  if (level == 0) {
642
0
    rcu_read_lock();
643
0
    isc_logconfig_t *lcfg = rcu_dereference(isc__lctx->logconfig);
644
0
    if (lcfg != NULL) {
645
0
      LOCK(&isc__lctx->lock);
646
0
      ISC_LIST_FOREACH(lcfg->channels, channel, link) {
647
0
        if (channel->type == ISC_LOG_TOFILE &&
648
0
            (channel->flags & ISC_LOG_DEBUGONLY) != 0 &&
649
0
            FILE_STREAM(channel) != NULL)
650
0
        {
651
0
          (void)fclose(FILE_STREAM(channel));
652
0
          FILE_STREAM(channel) = NULL;
653
0
        }
654
0
      }
655
0
      UNLOCK(&isc__lctx->lock);
656
0
    }
657
0
    rcu_read_unlock();
658
0
  }
659
0
}
660
661
unsigned int
662
0
isc_log_getdebuglevel(void) {
663
0
  REQUIRE(VALID_CONTEXT(isc__lctx));
664
665
0
  return atomic_load_acquire(&isc__lctx->debug_level);
666
0
}
667
668
void
669
0
isc_log_settag(isc_logconfig_t *lcfg, const char *tag) {
670
0
  REQUIRE(VALID_CONFIG(lcfg));
671
672
0
  if (tag != NULL && *tag != '\0') {
673
0
    if (lcfg->tag != NULL) {
674
0
      isc_mem_free(lcfg->lctx->mctx, lcfg->tag);
675
0
    }
676
0
    lcfg->tag = isc_mem_strdup(lcfg->lctx->mctx, tag);
677
0
  } else {
678
0
    if (lcfg->tag != NULL) {
679
0
      isc_mem_free(lcfg->lctx->mctx, lcfg->tag);
680
0
    }
681
0
  }
682
0
}
683
684
char *
685
0
isc_log_gettag(isc_logconfig_t *lcfg) {
686
0
  REQUIRE(VALID_CONFIG(lcfg));
687
688
0
  return lcfg->tag;
689
0
}
690
691
/* XXXDCL NT  -- This interface will assuredly be changing. */
692
void
693
0
isc_log_opensyslog(const char *tag, int options, int facility) {
694
0
  (void)openlog(tag, options, facility);
695
0
}
696
697
void
698
0
isc_log_closefilelogs(void) {
699
0
  REQUIRE(VALID_CONTEXT(isc__lctx));
700
701
0
  rcu_read_lock();
702
0
  isc_logconfig_t *lcfg = rcu_dereference(isc__lctx->logconfig);
703
0
  if (lcfg != NULL) {
704
0
    LOCK(&isc__lctx->lock);
705
0
    ISC_LIST_FOREACH(lcfg->channels, channel, link) {
706
0
      if (channel->type == ISC_LOG_TOFILE &&
707
0
          FILE_STREAM(channel) != NULL)
708
0
      {
709
0
        (void)fclose(FILE_STREAM(channel));
710
0
        FILE_STREAM(channel) = NULL;
711
0
      }
712
0
    }
713
0
    UNLOCK(&isc__lctx->lock);
714
0
  }
715
0
  rcu_read_unlock();
716
0
}
717
718
/****
719
**** Internal functions
720
****/
721
722
static void
723
assignchannel(isc_logconfig_t *lcfg, const isc_logcategory_t category,
724
0
        const isc_logmodule_t module, isc_logchannel_t *channel) {
725
0
  REQUIRE(VALID_CONFIG(lcfg));
726
0
  REQUIRE(channel != NULL);
727
728
0
  isc_log_t *lctx = lcfg->lctx;
729
730
0
  REQUIRE(category >= ISC_LOGCATEGORY_DEFAULT &&
731
0
    category < ISC_LOGCATEGORY_MAX);
732
0
  REQUIRE(module >= ISC_LOGMODULE_DEFAULT && module < ISC_LOGMODULE_MAX);
733
734
0
  isc_logchannellist_t *new_item = isc_mem_get(lctx->mctx,
735
0
                 sizeof(*new_item));
736
737
0
  new_item->channel = channel;
738
0
  new_item->module = module;
739
0
  ISC_LIST_INITANDPREPEND(lcfg->channellists[category], new_item, link);
740
741
  /*
742
   * Remember the highest logging level set by any channel in the
743
   * logging config, so isc_log_doit() can quickly return if the
744
   * message is too high to be logged by any channel.
745
   */
746
0
  if (channel->type != ISC_LOG_TONULL) {
747
0
    if (lcfg->highest_level < channel->level) {
748
0
      lcfg->highest_level = channel->level;
749
0
    }
750
0
    if (channel->level == ISC_LOG_DYNAMIC) {
751
0
      lcfg->dynamic = true;
752
0
    }
753
0
  }
754
0
}
755
756
static void
757
0
sync_highest_level(isc_logconfig_t *lcfg) {
758
0
  atomic_store(&isc__lctx->highest_level, lcfg->highest_level);
759
0
  atomic_store(&isc__lctx->dynamic, lcfg->dynamic);
760
0
}
761
762
static isc_result_t
763
0
greatest_version(isc_logfile_t *file, int versions, int *greatestp) {
764
0
  char *digit_end;
765
0
  char dirbuf[PATH_MAX + 1];
766
0
  const char *bname;
767
0
  const char *dirname = ".";
768
0
  int version, greatest = -1;
769
0
  isc_dir_t dir;
770
0
  isc_result_t result;
771
0
  size_t bnamelen;
772
773
0
  bname = strrchr(file->name, '/');
774
0
  if (bname != NULL) {
775
    /*
776
     * Copy the complete file name to dirbuf.
777
     */
778
0
    size_t len = strlcpy(dirbuf, file->name, sizeof(dirbuf));
779
0
    if (len >= sizeof(dirbuf)) {
780
0
      result = ISC_R_NOSPACE;
781
0
      syslog(LOG_ERR, "unable to remove log files: %s",
782
0
             isc_result_totext(result));
783
0
      return result;
784
0
    }
785
786
    /*
787
     * Truncate after trailing '/' so the code works for
788
     * files in the root directory.
789
     */
790
0
    bname++;
791
0
    dirbuf[bname - file->name] = '\0';
792
0
    dirname = dirbuf;
793
0
  } else {
794
0
    bname = file->name;
795
0
  }
796
0
  bnamelen = strlen(bname);
797
798
0
  isc_dir_init(&dir);
799
0
  RETERR(isc_dir_open(&dir, dirname));
800
801
0
  while (isc_dir_read(&dir) == ISC_R_SUCCESS) {
802
0
    if (dir.entry.length > bnamelen &&
803
0
        strncmp(dir.entry.name, bname, bnamelen) == 0 &&
804
0
        dir.entry.name[bnamelen] == '.')
805
0
    {
806
0
      version = strtol(&dir.entry.name[bnamelen + 1],
807
0
           &digit_end, 10);
808
      /*
809
       * Remove any backup files that exceed versions.
810
       */
811
0
      if (*digit_end == '\0' && version >= versions) {
812
0
        int n = dirfd(dir.handle);
813
0
        if (n >= 0) {
814
0
          n = unlinkat(n, dir.entry.name, 0);
815
0
        }
816
0
        if (n < 0) {
817
0
          result = isc_errno_toresult(errno);
818
0
          if (result != ISC_R_SUCCESS &&
819
0
              result != ISC_R_FILENOTFOUND)
820
0
          {
821
0
            syslog(LOG_ERR,
822
0
                   "unable to remove log "
823
0
                   "file '%s%s': %s",
824
0
                   bname == file->name
825
0
                     ? ""
826
0
                     : dirname,
827
0
                   dir.entry.name,
828
0
                   isc_result_totext(
829
0
                     result));
830
0
          }
831
0
        }
832
0
      } else if (*digit_end == '\0' && version > greatest) {
833
0
        greatest = version;
834
0
      }
835
0
    }
836
0
  }
837
0
  isc_dir_close(&dir);
838
839
0
  *greatestp = greatest;
840
0
  return ISC_R_SUCCESS;
841
0
}
842
843
static void
844
0
insert_sort(int64_t to_keep[], int64_t versions, int64_t version) {
845
0
  int i = 0;
846
0
  while (i < versions && version < to_keep[i]) {
847
0
    i++;
848
0
  }
849
0
  if (i == versions) {
850
0
    return;
851
0
  }
852
0
  if (i < versions - 1) {
853
0
    memmove(&to_keep[i + 1], &to_keep[i],
854
0
      sizeof(to_keep[0]) * (versions - i - 1));
855
0
  }
856
0
  to_keep[i] = version;
857
0
}
858
859
static int64_t
860
last_to_keep(int64_t versions, isc_dir_t *dirp, const char *bname,
861
0
       size_t bnamelen) {
862
0
  int64_t to_keep[ISC_LOG_MAX_VERSIONS] = { 0 };
863
0
  int64_t version = 0;
864
865
0
  if (versions <= 0) {
866
0
    return INT64_MAX;
867
0
  }
868
869
0
  if (versions > ISC_LOG_MAX_VERSIONS) {
870
0
    versions = ISC_LOG_MAX_VERSIONS;
871
0
  }
872
  /*
873
   * First we fill 'to_keep' structure using insertion sort
874
   */
875
0
  memset(to_keep, 0, sizeof(to_keep));
876
0
  while (isc_dir_read(dirp) == ISC_R_SUCCESS) {
877
0
    char *digit_end = NULL;
878
0
    char *ename = NULL;
879
880
0
    if (dirp->entry.length <= bnamelen ||
881
0
        strncmp(dirp->entry.name, bname, bnamelen) != 0 ||
882
0
        dirp->entry.name[bnamelen] != '.')
883
0
    {
884
0
      continue;
885
0
    }
886
887
0
    ename = &dirp->entry.name[bnamelen + 1];
888
0
    version = strtoull(ename, &digit_end, 10);
889
0
    if (*digit_end == '\0') {
890
0
      insert_sort(to_keep, versions, version);
891
0
    }
892
0
  }
893
894
0
  isc_dir_reset(dirp);
895
896
  /*
897
   * to_keep[versions - 1] is the last one we want to keep
898
   */
899
0
  return to_keep[versions - 1];
900
0
}
901
902
static isc_result_t
903
0
remove_old_tsversions(isc_logfile_t *file, int versions) {
904
0
  char *digit_end;
905
0
  char dirbuf[PATH_MAX + 1];
906
0
  const char *bname;
907
0
  const char *dirname = ".";
908
0
  int64_t version, last = INT64_MAX;
909
0
  isc_dir_t dir;
910
0
  isc_result_t result;
911
0
  size_t bnamelen;
912
913
0
  bname = strrchr(file->name, '/');
914
0
  if (bname != NULL) {
915
    /*
916
     * Copy the complete file name to dirbuf.
917
     */
918
0
    size_t len = strlcpy(dirbuf, file->name, sizeof(dirbuf));
919
0
    if (len >= sizeof(dirbuf)) {
920
0
      result = ISC_R_NOSPACE;
921
0
      syslog(LOG_ERR, "unable to remove log files: %s",
922
0
             isc_result_totext(result));
923
0
      return result;
924
0
    }
925
926
    /*
927
     * Truncate after trailing '/' so the code works for
928
     * files in the root directory.
929
     */
930
0
    bname++;
931
0
    dirbuf[bname - file->name] = '\0';
932
0
    dirname = dirbuf;
933
0
  } else {
934
0
    bname = file->name;
935
0
  }
936
0
  bnamelen = strlen(bname);
937
938
0
  isc_dir_init(&dir);
939
0
  RETERR(isc_dir_open(&dir, dirname));
940
941
0
  last = last_to_keep(versions, &dir, bname, bnamelen);
942
943
0
  while (isc_dir_read(&dir) == ISC_R_SUCCESS) {
944
0
    if (dir.entry.length > bnamelen &&
945
0
        strncmp(dir.entry.name, bname, bnamelen) == 0 &&
946
0
        dir.entry.name[bnamelen] == '.')
947
0
    {
948
0
      version = strtoull(&dir.entry.name[bnamelen + 1],
949
0
             &digit_end, 10);
950
      /*
951
       * Remove any backup files that exceed versions.
952
       */
953
0
      if (*digit_end == '\0' && version < last) {
954
0
        int n = dirfd(dir.handle);
955
0
        if (n >= 0) {
956
0
          n = unlinkat(n, dir.entry.name, 0);
957
0
        }
958
0
        if (n < 0) {
959
0
          result = isc_errno_toresult(errno);
960
0
          if (result != ISC_R_SUCCESS &&
961
0
              result != ISC_R_FILENOTFOUND)
962
0
          {
963
0
            syslog(LOG_ERR,
964
0
                   "unable to remove log "
965
0
                   "file '%s%s': %s",
966
0
                   bname == file->name
967
0
                     ? ""
968
0
                     : dirname,
969
0
                   dir.entry.name,
970
0
                   isc_result_totext(
971
0
                     result));
972
0
          }
973
0
        }
974
0
      }
975
0
    }
976
0
  }
977
0
  isc_dir_close(&dir);
978
0
  return ISC_R_SUCCESS;
979
0
}
980
981
static isc_result_t
982
0
roll_increment(isc_logfile_t *file) {
983
0
  int i, n, greatest;
984
0
  char current[PATH_MAX + 1];
985
0
  char newpath[PATH_MAX + 1];
986
0
  const char *path;
987
0
  isc_result_t result = ISC_R_SUCCESS;
988
989
0
  REQUIRE(file != NULL);
990
0
  REQUIRE(file->versions != 0);
991
992
0
  path = file->name;
993
994
0
  if (file->versions == ISC_LOG_ROLLINFINITE) {
995
    /*
996
     * Find the first missing entry in the log file sequence.
997
     */
998
0
    for (greatest = 0; greatest < INT_MAX; greatest++) {
999
0
      n = snprintf(current, sizeof(current), "%s.%u", path,
1000
0
             (unsigned int)greatest);
1001
0
      if (n >= (int)sizeof(current) || n < 0 ||
1002
0
          !isc_file_exists(current))
1003
0
      {
1004
0
        break;
1005
0
      }
1006
0
    }
1007
0
  } else {
1008
    /*
1009
     * Get the largest existing version and remove any
1010
     * version greater than the permitted version.
1011
     */
1012
0
    RETERR(greatest_version(file, file->versions, &greatest));
1013
1014
    /*
1015
     * Increment if greatest is not the actual maximum value.
1016
     */
1017
0
    if (greatest < file->versions - 1) {
1018
0
      greatest++;
1019
0
    }
1020
0
  }
1021
1022
0
  for (i = greatest; i > 0; i--) {
1023
0
    result = ISC_R_SUCCESS;
1024
0
    n = snprintf(current, sizeof(current), "%s.%u", path,
1025
0
           (unsigned int)(i - 1));
1026
0
    if (n >= (int)sizeof(current) || n < 0) {
1027
0
      result = ISC_R_NOSPACE;
1028
0
    }
1029
0
    if (result == ISC_R_SUCCESS) {
1030
0
      n = snprintf(newpath, sizeof(newpath), "%s.%u", path,
1031
0
             (unsigned int)i);
1032
0
      if (n >= (int)sizeof(newpath) || n < 0) {
1033
0
        result = ISC_R_NOSPACE;
1034
0
      }
1035
0
    }
1036
0
    if (result == ISC_R_SUCCESS) {
1037
0
      result = isc_file_rename(current, newpath);
1038
0
    }
1039
0
    if (result != ISC_R_SUCCESS && result != ISC_R_FILENOTFOUND) {
1040
0
      syslog(LOG_ERR,
1041
0
             "unable to rename log file '%s.%u' to "
1042
0
             "'%s.%u': %s",
1043
0
             path, i - 1, path, i, isc_result_totext(result));
1044
0
    }
1045
0
  }
1046
1047
0
  n = snprintf(newpath, sizeof(newpath), "%s.0", path);
1048
0
  if (n >= (int)sizeof(newpath) || n < 0) {
1049
0
    result = ISC_R_NOSPACE;
1050
0
  } else {
1051
0
    result = isc_file_rename(path, newpath);
1052
0
  }
1053
0
  if (result != ISC_R_SUCCESS && result != ISC_R_FILENOTFOUND) {
1054
0
    syslog(LOG_ERR, "unable to rename log file '%s' to '%s.0': %s",
1055
0
           path, path, isc_result_totext(result));
1056
0
  }
1057
1058
0
  return ISC_R_SUCCESS;
1059
0
}
1060
1061
static isc_result_t
1062
0
roll_timestamp(isc_logfile_t *file) {
1063
0
  int n;
1064
0
  char newts[PATH_MAX + 1];
1065
0
  char newpath[PATH_MAX + 1];
1066
0
  const char *path;
1067
0
  isc_time_t now;
1068
0
  isc_result_t result = ISC_R_SUCCESS;
1069
1070
0
  REQUIRE(file != NULL);
1071
0
  REQUIRE(file->versions != 0);
1072
1073
0
  path = file->name;
1074
1075
  /*
1076
   * First find all the logfiles and remove the oldest ones
1077
   * Save one fewer than file->versions because we'll be renaming
1078
   * the existing file to a timestamped version after this.
1079
   */
1080
0
  if (file->versions != ISC_LOG_ROLLINFINITE) {
1081
0
    remove_old_tsversions(file, file->versions - 1);
1082
0
  }
1083
1084
  /* Then just rename the current logfile */
1085
0
  now = isc_time_now();
1086
0
  isc_time_formatshorttimestamp(&now, newts, PATH_MAX + 1);
1087
0
  n = snprintf(newpath, sizeof(newpath), "%s.%s", path, newts);
1088
0
  if (n >= (int)sizeof(newpath) || n < 0) {
1089
0
    result = ISC_R_NOSPACE;
1090
0
  } else {
1091
0
    result = isc_file_rename(path, newpath);
1092
0
  }
1093
0
  if (result != ISC_R_SUCCESS && result != ISC_R_FILENOTFOUND) {
1094
0
    syslog(LOG_ERR, "unable to rename log file '%s' to '%s.0': %s",
1095
0
           path, path, isc_result_totext(result));
1096
0
  }
1097
1098
0
  return ISC_R_SUCCESS;
1099
0
}
1100
1101
isc_result_t
1102
0
isc_logfile_roll(isc_logfile_t *file) {
1103
0
  isc_result_t result;
1104
1105
0
  REQUIRE(file != NULL);
1106
1107
  /*
1108
   * Do nothing (not even excess version trimming) if ISC_LOG_ROLLNEVER
1109
   * is specified.  Apparently complete external control over the log
1110
   * files is desired.
1111
   */
1112
0
  if (file->versions == ISC_LOG_ROLLNEVER) {
1113
0
    return ISC_R_SUCCESS;
1114
0
  } else if (file->versions == 0) {
1115
0
    result = isc_file_remove(file->name);
1116
0
    if (result != ISC_R_SUCCESS && result != ISC_R_FILENOTFOUND) {
1117
0
      syslog(LOG_ERR, "unable to remove log file '%s': %s",
1118
0
             file->name, isc_result_totext(result));
1119
0
    }
1120
0
    return ISC_R_SUCCESS;
1121
0
  }
1122
1123
0
  switch (file->suffix) {
1124
0
  case isc_log_rollsuffix_increment:
1125
0
    return roll_increment(file);
1126
0
  case isc_log_rollsuffix_timestamp:
1127
0
    return roll_timestamp(file);
1128
0
  default:
1129
0
    return ISC_R_UNEXPECTED;
1130
0
  }
1131
0
}
1132
1133
static isc_result_t
1134
0
isc_log_open(isc_logchannel_t *channel) {
1135
0
  struct stat statbuf;
1136
0
  bool regular_file;
1137
0
  bool roll = false;
1138
0
  isc_result_t result = ISC_R_SUCCESS;
1139
0
  const char *path;
1140
1141
0
  REQUIRE(channel->type == ISC_LOG_TOFILE);
1142
0
  REQUIRE(FILE_STREAM(channel) == NULL);
1143
1144
0
  path = FILE_NAME(channel);
1145
1146
0
  REQUIRE(path != NULL && *path != '\0');
1147
1148
  /*
1149
   * Determine type of file; only regular files will be
1150
   * version renamed, and only if the base file exists
1151
   * and either has no size limit or has reached its size limit.
1152
   */
1153
0
  if (stat(path, &statbuf) == 0) {
1154
0
    regular_file = S_ISREG(statbuf.st_mode) ? true : false;
1155
    /* XXXDCL if not regular_file complain? */
1156
0
    if ((FILE_MAXSIZE(channel) == 0 &&
1157
0
         FILE_VERSIONS(channel) != ISC_LOG_ROLLNEVER) ||
1158
0
        (FILE_MAXSIZE(channel) > 0 &&
1159
0
         statbuf.st_size >= FILE_MAXSIZE(channel)))
1160
0
    {
1161
0
      roll = regular_file;
1162
0
    }
1163
0
  } else if (errno == ENOENT) {
1164
0
    regular_file = true;
1165
0
    POST(regular_file);
1166
0
  } else {
1167
0
    result = ISC_R_INVALIDFILE;
1168
0
  }
1169
1170
  /*
1171
   * Version control.
1172
   */
1173
0
  if (result == ISC_R_SUCCESS && roll) {
1174
0
    if (FILE_VERSIONS(channel) == ISC_LOG_ROLLNEVER) {
1175
0
      return ISC_R_MAXSIZE;
1176
0
    }
1177
0
    result = isc_logfile_roll(&channel->destination.file);
1178
0
    if (result != ISC_R_SUCCESS) {
1179
0
      if ((channel->flags & ISC_LOG_OPENERR) == 0) {
1180
0
        syslog(LOG_ERR,
1181
0
               "isc_log_open: isc_logfile_roll '%s' "
1182
0
               "failed: %s",
1183
0
               FILE_NAME(channel),
1184
0
               isc_result_totext(result));
1185
0
        channel->flags |= ISC_LOG_OPENERR;
1186
0
      }
1187
0
      return result;
1188
0
    }
1189
0
  }
1190
1191
0
  result = isc_stdio_open(path, "a", &FILE_STREAM(channel));
1192
1193
0
  return result;
1194
0
}
1195
1196
ISC_NO_SANITIZE_THREAD bool
1197
0
isc_log_wouldlog(int level) {
1198
  /*
1199
   * Try to avoid locking the mutex for messages which can't
1200
   * possibly be logged to any channels -- primarily debugging
1201
   * messages that the debug level is not high enough to print.
1202
   *
1203
   * If the level is (mathematically) less than or equal to the
1204
   * highest_level, or if there is a dynamic channel and the level is
1205
   * less than or equal to the debug level, the main loop must be
1206
   * entered to see if the message should really be output.
1207
   */
1208
0
  if (isc__lctx == NULL) {
1209
0
    return false;
1210
0
  }
1211
0
  if (forcelog) {
1212
0
    return true;
1213
0
  }
1214
1215
0
  int highest_level = atomic_load_acquire(&isc__lctx->highest_level);
1216
0
  if (level <= highest_level) {
1217
0
    return true;
1218
0
  }
1219
0
  if (atomic_load_acquire(&isc__lctx->dynamic)) {
1220
0
    int debug_level = atomic_load_acquire(&isc__lctx->debug_level);
1221
0
    if (level <= debug_level) {
1222
0
      return true;
1223
0
    }
1224
0
  }
1225
1226
0
  return false;
1227
0
}
1228
1229
static void
1230
isc_log_doit(isc_logcategory_t category, isc_logmodule_t module, int level,
1231
0
       const char *format, va_list args) {
1232
0
  int syslog_level;
1233
0
  const char *time_string;
1234
0
  char local_time[64] = { 0 };
1235
0
  char iso8601z_string[64] = { 0 };
1236
0
  char iso8601l_string[64] = { 0 };
1237
0
  char iso8601tz_string[64] = { 0 };
1238
0
  char level_string[24] = { 0 };
1239
0
  struct stat statbuf;
1240
0
  bool matched = false;
1241
0
  bool printtime, iso8601, utc, tzinfo, printtag, printcolon;
1242
0
  bool printcategory, printmodule, printlevel, buffered;
1243
0
  isc_logchannel_t *channel;
1244
0
  isc_logchannellist_t *category_channels;
1245
0
  int_fast32_t dlevel;
1246
0
  isc_result_t result;
1247
1248
0
  REQUIRE(isc__lctx == NULL || VALID_CONTEXT(isc__lctx));
1249
0
  REQUIRE(category > ISC_LOGCATEGORY_DEFAULT &&
1250
0
    category < ISC_LOGCATEGORY_MAX);
1251
0
  REQUIRE(module > ISC_LOGMODULE_DEFAULT && module < ISC_LOGMODULE_MAX);
1252
0
  REQUIRE(level != ISC_LOG_DYNAMIC);
1253
0
  REQUIRE(format != NULL);
1254
1255
0
  if (!isc_log_wouldlog(level)) {
1256
0
    return;
1257
0
  }
1258
1259
0
  rcu_read_lock();
1260
0
  LOCK(&isc__lctx->lock);
1261
1262
0
  isc__lctx->buffer[0] = '\0';
1263
1264
0
  isc_logconfig_t *lcfg = rcu_dereference(isc__lctx->logconfig);
1265
0
  if (lcfg == NULL) {
1266
0
    goto unlock;
1267
0
  }
1268
1269
0
  category_channels = ISC_LIST_HEAD(lcfg->channellists[category]);
1270
1271
0
  do {
1272
    /*
1273
     * If the channel list end was reached and a match was
1274
     * made, everything is finished.
1275
     */
1276
0
    if (category_channels == NULL && matched) {
1277
0
      break;
1278
0
    }
1279
1280
0
    if (category_channels == NULL && !matched &&
1281
0
        category_channels != ISC_LIST_HEAD(lcfg->channellists[0]))
1282
0
    {
1283
      /*
1284
       * No category/module pair was explicitly
1285
       * configured. Try the category named "default".
1286
       */
1287
0
      category_channels =
1288
0
        ISC_LIST_HEAD(lcfg->channellists[0]);
1289
0
    }
1290
1291
0
    if (category_channels == NULL && !matched) {
1292
      /*
1293
       * No matching module was explicitly configured
1294
       * for the category named "default".  Use the
1295
       * internal default channel.
1296
       */
1297
0
      category_channels = &default_channel;
1298
0
    }
1299
1300
0
    if (category_channels->module != ISC_LOGMODULE_DEFAULT &&
1301
0
        category_channels->module != module)
1302
0
    {
1303
0
      category_channels = ISC_LIST_NEXT(category_channels,
1304
0
                link);
1305
0
      continue;
1306
0
    }
1307
1308
0
    matched = true;
1309
1310
0
    channel = category_channels->channel;
1311
0
    category_channels = ISC_LIST_NEXT(category_channels, link);
1312
1313
0
    if (!forcelog) {
1314
0
      dlevel = atomic_load_acquire(&isc__lctx->debug_level);
1315
0
      if (((channel->flags & ISC_LOG_DEBUGONLY) != 0) &&
1316
0
          dlevel == 0)
1317
0
      {
1318
0
        continue;
1319
0
      }
1320
1321
0
      if (channel->level == ISC_LOG_DYNAMIC) {
1322
0
        if (dlevel < level) {
1323
0
          continue;
1324
0
        }
1325
0
      } else if (channel->level < level) {
1326
0
        continue;
1327
0
      }
1328
0
    }
1329
1330
0
    if ((channel->flags & ISC_LOG_PRINTTIME) != 0 &&
1331
0
        local_time[0] == '\0')
1332
0
    {
1333
0
      isc_time_t isctime;
1334
1335
0
      isctime = isc_time_now();
1336
1337
0
      isc_time_formattimestamp(&isctime, local_time,
1338
0
             sizeof(local_time));
1339
0
      isc_time_formatISO8601ms(&isctime, iso8601z_string,
1340
0
             sizeof(iso8601z_string));
1341
0
      isc_time_formatISO8601Lms(&isctime, iso8601l_string,
1342
0
              sizeof(iso8601l_string));
1343
0
      isc_time_formatISO8601TZms(&isctime, iso8601tz_string,
1344
0
               sizeof(iso8601tz_string));
1345
0
    }
1346
1347
0
    if ((channel->flags & ISC_LOG_PRINTLEVEL) != 0 &&
1348
0
        level_string[0] == '\0')
1349
0
    {
1350
0
      if (level < ISC_LOG_CRITICAL) {
1351
0
        snprintf(level_string, sizeof(level_string),
1352
0
           "level %d: ", level);
1353
0
      } else if (level > ISC_LOG_DYNAMIC) {
1354
0
        snprintf(level_string, sizeof(level_string),
1355
0
           "%s %d: ", log_level_strings[0],
1356
0
           level);
1357
0
      } else {
1358
0
        snprintf(level_string, sizeof(level_string),
1359
0
           "%s: ", log_level_strings[-level]);
1360
0
      }
1361
0
    }
1362
1363
    /*
1364
     * Only format the message once.
1365
     */
1366
0
    if (isc__lctx->buffer[0] == '\0') {
1367
0
      (void)vsnprintf(isc__lctx->buffer,
1368
0
          sizeof(isc__lctx->buffer), format,
1369
0
          args);
1370
0
    }
1371
1372
0
    utc = ((channel->flags & ISC_LOG_UTC) != 0);
1373
0
    tzinfo = ((channel->flags & ISC_LOG_TZINFO) != 0);
1374
0
    iso8601 = ((channel->flags & ISC_LOG_ISO8601) != 0);
1375
0
    printtime = ((channel->flags & ISC_LOG_PRINTTIME) != 0);
1376
0
    printtag = ((channel->flags &
1377
0
           (ISC_LOG_PRINTTAG | ISC_LOG_PRINTPREFIX)) != 0 &&
1378
0
          lcfg->tag != NULL);
1379
0
    printcolon = ((channel->flags & ISC_LOG_PRINTTAG) != 0 &&
1380
0
            lcfg->tag != NULL);
1381
0
    printcategory = ((channel->flags & ISC_LOG_PRINTCATEGORY) != 0);
1382
0
    printmodule = ((channel->flags & ISC_LOG_PRINTMODULE) != 0);
1383
0
    printlevel = ((channel->flags & ISC_LOG_PRINTLEVEL) != 0);
1384
0
    buffered = ((channel->flags & ISC_LOG_BUFFERED) != 0);
1385
1386
0
    if (printtime) {
1387
0
      if (iso8601) {
1388
0
        if (utc) {
1389
0
          time_string = iso8601z_string;
1390
0
        } else if (tzinfo) {
1391
0
          time_string = iso8601tz_string;
1392
0
        } else {
1393
0
          time_string = iso8601l_string;
1394
0
        }
1395
0
      } else {
1396
0
        time_string = local_time;
1397
0
      }
1398
0
    } else {
1399
0
      time_string = "";
1400
0
    }
1401
1402
0
    switch (channel->type) {
1403
0
    case ISC_LOG_TOFILE:
1404
0
      if (FILE_MAXREACHED(channel)) {
1405
        /*
1406
         * If the file can be rolled, OR
1407
         * If the file no longer exists, OR
1408
         * If the file is less than the maximum
1409
         * size, (such as if it had been renamed
1410
         * and a new one touched, or it was
1411
         * truncated in place)
1412
         * ... then close it to trigger
1413
         * reopening.
1414
         */
1415
0
        if (FILE_VERSIONS(channel) !=
1416
0
              ISC_LOG_ROLLNEVER ||
1417
0
            (stat(FILE_NAME(channel), &statbuf) != 0 &&
1418
0
             errno == ENOENT) ||
1419
0
            statbuf.st_size < FILE_MAXSIZE(channel))
1420
0
        {
1421
0
          if (FILE_STREAM(channel) != NULL) {
1422
0
            (void)fclose(
1423
0
              FILE_STREAM(channel));
1424
0
            FILE_STREAM(channel) = NULL;
1425
0
          }
1426
0
          FILE_MAXREACHED(channel) = false;
1427
0
        } else {
1428
          /*
1429
           * Eh, skip it.
1430
           */
1431
0
          break;
1432
0
        }
1433
0
      }
1434
1435
0
      if (FILE_STREAM(channel) == NULL) {
1436
0
        result = isc_log_open(channel);
1437
0
        if (result != ISC_R_SUCCESS &&
1438
0
            result != ISC_R_MAXSIZE &&
1439
0
            (channel->flags & ISC_LOG_OPENERR) == 0)
1440
0
        {
1441
0
          syslog(LOG_ERR,
1442
0
                 "isc_log_open '%s' "
1443
0
                 "failed: %s",
1444
0
                 FILE_NAME(channel),
1445
0
                 isc_result_totext(result));
1446
0
          channel->flags |= ISC_LOG_OPENERR;
1447
0
        }
1448
0
        if (result != ISC_R_SUCCESS) {
1449
0
          break;
1450
0
        }
1451
0
        channel->flags &= ~ISC_LOG_OPENERR;
1452
0
      }
1453
0
      FALLTHROUGH;
1454
1455
0
    case ISC_LOG_TOFILEDESC:
1456
0
      fprintf(FILE_STREAM(channel), "%s%s%s%s%s%s%s%s%s%s\n",
1457
0
        printtime ? time_string : "",
1458
0
        printtime ? " " : "", printtag ? lcfg->tag : "",
1459
0
        printcolon ? ": " : "",
1460
0
        printcategory ? categories_description[category]
1461
0
                : "",
1462
0
        printcategory ? ": " : "",
1463
0
        printmodule ? modules_description[module] : "",
1464
0
        printmodule ? ": " : "",
1465
0
        printlevel ? level_string : "",
1466
0
        isc__lctx->buffer);
1467
1468
0
      if (!buffered) {
1469
0
        fflush(FILE_STREAM(channel));
1470
0
      }
1471
1472
      /*
1473
       * If the file now exceeds its maximum size
1474
       * threshold, note it so that it will not be
1475
       * logged to any more.
1476
       */
1477
0
      if (FILE_MAXSIZE(channel) > 0) {
1478
0
        INSIST(channel->type == ISC_LOG_TOFILE);
1479
1480
        /* XXXDCL NT fstat/fileno */
1481
        /* XXXDCL complain if fstat fails? */
1482
0
        if (fstat(fileno(FILE_STREAM(channel)),
1483
0
            &statbuf) >= 0 &&
1484
0
            statbuf.st_size > FILE_MAXSIZE(channel))
1485
0
        {
1486
0
          FILE_MAXREACHED(channel) = true;
1487
0
        }
1488
0
      }
1489
1490
0
      break;
1491
1492
0
    case ISC_LOG_TOSYSLOG:
1493
0
      if (level > 0) {
1494
0
        syslog_level = LOG_DEBUG;
1495
0
      } else if (level < ISC_LOG_CRITICAL) {
1496
0
        syslog_level = LOG_CRIT;
1497
0
      } else {
1498
0
        syslog_level = syslog_map[-level];
1499
0
      }
1500
1501
0
      (void)syslog(
1502
0
        FACILITY(channel) | syslog_level,
1503
0
        "%s%s%s%s%s%s%s%s%s%s",
1504
0
        printtime ? time_string : "",
1505
0
        printtime ? " " : "", printtag ? lcfg->tag : "",
1506
0
        printcolon ? ": " : "",
1507
0
        printcategory ? categories_description[category]
1508
0
                : "",
1509
0
        printcategory ? ": " : "",
1510
0
        printmodule ? modules_description[module] : "",
1511
0
        printmodule ? ": " : "",
1512
0
        printlevel ? level_string : "",
1513
0
        isc__lctx->buffer);
1514
0
      break;
1515
1516
0
    case ISC_LOG_TONULL:
1517
0
      break;
1518
0
    }
1519
0
  } while (1);
1520
1521
0
unlock:
1522
0
  UNLOCK(&isc__lctx->lock);
1523
0
  rcu_read_unlock();
1524
0
}
1525
1526
void
1527
0
isc_log_setforcelog(bool v) {
1528
0
  forcelog = v;
1529
0
}
1530
1531
void
1532
2
isc__log_initialize(void) {
1533
2
  REQUIRE(isc__lctx == NULL);
1534
1535
2
  isc_mem_t *mctx = NULL;
1536
1537
2
  isc_mem_create("log", &mctx);
1538
2
  isc_mem_setdebugging(mctx, 0);
1539
1540
2
  isc__lctx = isc_mem_get(mctx, sizeof(*isc__lctx));
1541
2
  *isc__lctx = (isc_log_t){
1542
2
    .magic = LCTX_MAGIC,
1543
2
    .mctx = mctx, /* implicit attach */
1544
2
  };
1545
1546
2
  isc_mutex_init(&isc__lctx->lock);
1547
1548
  /* Create default logging configuration */
1549
2
  isc_logconfig_t *lcfg = NULL;
1550
2
  isc_logconfig_create(&lcfg);
1551
1552
2
  atomic_init(&isc__lctx->highest_level, lcfg->highest_level);
1553
2
  atomic_init(&isc__lctx->dynamic, lcfg->dynamic);
1554
1555
2
  isc__lctx->logconfig = lcfg;
1556
2
}
1557
1558
void
1559
0
isc__log_shutdown(void) {
1560
  /*
1561
   * There is a data race when the QP database reclaims chunks on the
1562
   * call_rcu threads and tries to log the number of reclaimed chunks
1563
   * while the server is shutting down.  Work around this by adding
1564
   * an rcu_barrier() before shutting down the global logging context.
1565
   */
1566
0
  rcu_barrier();
1567
1568
0
  REQUIRE(VALID_CONTEXT(isc__lctx));
1569
1570
0
  isc_mem_t *mctx = isc__lctx->mctx;
1571
1572
  /* Stop the logging as a first thing */
1573
0
  atomic_store_release(&isc__lctx->debug_level, 0);
1574
0
  atomic_store_release(&isc__lctx->highest_level, 0);
1575
0
  atomic_store_release(&isc__lctx->dynamic, false);
1576
1577
0
  if (isc__lctx->logconfig != NULL) {
1578
0
    isc_logconfig_destroy(&isc__lctx->logconfig);
1579
0
  }
1580
1581
0
  isc_mutex_destroy(&isc__lctx->lock);
1582
1583
  isc_mem_putanddetach(&mctx, isc__lctx, sizeof(*isc__lctx));
1584
0
}