Coverage Report

Created: 2026-01-10 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dovecot/src/lib/failures.c
Line
Count
Source
1
/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
2
3
#include "lib.h"
4
#include "ioloop.h"
5
#include "str.h"
6
#include "hostpid.h"
7
#include "net.h"
8
#include "process-title.h"
9
#include "lib-signals.h"
10
#include "backtrace-string.h"
11
#include "printf-format-fix.h"
12
#include "write-full.h"
13
#include "time-util.h"
14
#include "failures-private.h"
15
16
#include <unistd.h>
17
#include <fcntl.h>
18
#include <syslog.h>
19
#include <time.h>
20
#include <poll.h>
21
22
0
#define LOG_TYPE_FLAG_PREFIX_LEN 0x40
23
0
#define LOG_TYPE_FLAG_DISABLE_LOG_PREFIX 0x80
24
25
const char *failure_log_type_prefixes[] = {
26
  "Debug: ",
27
  "Info: ",
28
  "Warning: ",
29
  "Error: ",
30
  "Fatal: ",
31
  "Panic: "
32
};
33
static_assert_array_size(failure_log_type_prefixes, LOG_TYPE_COUNT);
34
35
const char *failure_log_type_names[LOG_TYPE_COUNT] = {
36
  "debug", "info", "warning", "error", "fatal", "panic"
37
};
38
39
static int log_fd_write(int fd, const unsigned char *data, size_t len);
40
41
static void error_handler_real(const struct failure_context *ctx,
42
          const char *format, va_list args);
43
44
/* Initialize working defaults */
45
static failure_callback_t *fatal_handler ATTR_NORETURN =
46
  default_fatal_handler;
47
static failure_callback_t *error_handler = default_error_handler;
48
static failure_callback_t *info_handler = default_error_handler;
49
static failure_callback_t *debug_handler = default_error_handler;
50
static void (*failure_exit_callback)(int *) = NULL;
51
52
static struct failure_context failure_ctx_debug = { .type = LOG_TYPE_DEBUG };
53
static struct failure_context failure_ctx_info = { .type = LOG_TYPE_INFO };
54
static struct failure_context failure_ctx_warning = { .type = LOG_TYPE_WARNING };
55
static struct failure_context failure_ctx_error = { .type = LOG_TYPE_ERROR };
56
57
static int log_fd = STDERR_FILENO, log_info_fd = STDERR_FILENO,
58
     log_debug_fd = STDERR_FILENO;
59
static char *syslog_ident = NULL;
60
static char *log_prefix = NULL;
61
static char *log_stamp_format = NULL, *log_stamp_format_suffix = NULL;
62
static bool failure_ignore_errors = FALSE, log_prefix_sent = FALSE;
63
static bool coredump_on_error = FALSE;
64
static void log_timestamp_add(const struct failure_context *ctx, string_t *str);
65
static void log_prefix_add(const struct failure_context *ctx, string_t *str);
66
static int i_failure_send_option_forced(const char *key, const char *value);
67
static int internal_send_split(string_t *full_str, size_t prefix_len);
68
69
static bool log_fd_can_close(int fd)
70
0
{
71
0
  return fd != STDOUT_FILENO && fd != STDERR_FILENO;
72
0
}
73
74
static const char *log_prefix_sanitize(const char *str)
75
0
{
76
  /* we really only care about LFs, which can break everything. */
77
0
  return t_str_replace(str, '\n', ' ');
78
0
}
79
80
static int ATTR_FORMAT(2, 0)
81
default_write(const struct failure_context *ctx,
82
        const char *format, va_list args)
83
1
{
84
1
  string_t *data = t_str_new(256);
85
1
  log_timestamp_add(ctx, data);
86
1
  log_prefix_add(ctx, data);
87
1
  size_t prefix_len = str_len(data);
88
89
  /* make sure there's no %n in there and fix %m */
90
1
  str_vprintfa(data, printf_format_fix(format), args);
91
92
1
  int fd;
93
1
  switch (ctx->type) {
94
0
  case LOG_TYPE_DEBUG:
95
0
    fd = log_debug_fd;
96
0
    break;
97
1
  case LOG_TYPE_INFO:
98
1
    fd = log_info_fd;
99
1
    break;
100
0
  default:
101
0
    fd = log_fd;
102
0
    break;
103
1
  }
104
105
1
  const char *p;
106
1
  while ((p = strchr(str_c(data), '\n')) != NULL) {
107
0
    size_t line_len = p - str_c(data) + 1;
108
0
    if (log_fd_write(fd, str_data(data), line_len) < 0)
109
0
      return -1;
110
    /* delete the written line, not including the log prefix */
111
0
    str_delete(data, prefix_len, line_len - prefix_len);
112
0
  }
113
114
1
  str_append_c(data, '\n');
115
1
  return log_fd_write(fd, str_data(data), str_len(data));
116
1
}
117
118
static void default_on_handler_failure(const struct failure_context *ctx)
119
0
{
120
0
  const char *log_type = "info";
121
0
  switch (ctx->type) {
122
0
  case LOG_TYPE_DEBUG:
123
0
    log_type = "debug";
124
    /* fall through */
125
0
  case LOG_TYPE_INFO:
126
    /* we failed to log to info/debug log, try to log the
127
       write error to error log - maybe that'll work. */
128
0
    i_fatal_status(FATAL_LOGWRITE, "write() failed to %s log: %m",
129
0
             log_type);
130
0
  default:
131
0
    failure_exit(FATAL_LOGWRITE);
132
0
  }
133
0
}
134
135
static int ATTR_FORMAT(2, 0)
136
syslog_write(const struct failure_context *ctx,
137
       const char *format, va_list args)
138
0
{
139
0
  string_t *data = t_str_new(128);
140
0
  if (ctx->type == LOG_TYPE_INFO) {
141
0
    if (ctx->log_prefix != NULL)
142
0
      str_append(data, log_prefix_sanitize(ctx->log_prefix));
143
0
    else if (log_prefix != NULL)
144
0
      str_append(data, log_prefix);
145
0
  } else {
146
0
    log_prefix_add(ctx, data);
147
0
  }
148
0
  size_t prefix_len = str_len(data);
149
0
  str_vprintfa(data, format, args);
150
151
0
  int level = LOG_ERR;
152
0
  switch (ctx->type) {
153
0
  case LOG_TYPE_DEBUG:
154
0
    level = LOG_DEBUG;
155
0
    break;
156
0
  case LOG_TYPE_INFO:
157
0
    level = LOG_INFO;
158
0
    break;
159
0
  case LOG_TYPE_WARNING:
160
0
    level = LOG_WARNING;
161
0
    break;
162
0
  case LOG_TYPE_ERROR:
163
0
    level = LOG_ERR;
164
0
    break;
165
0
  case LOG_TYPE_FATAL:
166
0
  case LOG_TYPE_PANIC:
167
0
    level = LOG_CRIT;
168
0
    break;
169
0
  case LOG_TYPE_COUNT:
170
0
  case LOG_TYPE_OPTION:
171
0
    i_unreached();
172
0
  }
173
0
  char *p;
174
0
  while ((p = strchr(str_c_modifiable(data) + prefix_len, '\n')) != NULL) {
175
0
    size_t line_len = p - str_c_modifiable(data) + 1;
176
0
    *p = '\0';
177
0
    syslog(level, "%s", str_c(data));
178
    /* delete the written line, not including the log prefix */
179
0
    i_assert(line_len > prefix_len);
180
0
    str_delete(data, prefix_len, line_len - prefix_len);
181
0
  }
182
183
0
  syslog(level, "%s", str_c(data));
184
0
  return 0;
185
0
}
186
187
static void syslog_on_handler_failure(const struct failure_context *ctx ATTR_UNUSED)
188
0
{
189
0
  failure_exit(FATAL_LOGERROR);
190
0
}
191
192
static int ATTR_FORMAT(2, 0)
193
internal_write(const struct failure_context *ctx,
194
         const char *format, va_list args)
195
0
{
196
0
  string_t *data;
197
0
  unsigned char log_type = ctx->type + 1;
198
199
0
  if (ctx->log_prefix != NULL) {
200
0
    log_type |= LOG_TYPE_FLAG_DISABLE_LOG_PREFIX;
201
0
    if (ctx->log_prefix_type_pos != 0)
202
0
      log_type |= LOG_TYPE_FLAG_PREFIX_LEN;
203
0
  } else if (!log_prefix_sent && log_prefix != NULL) {
204
0
    if (i_failure_send_option_forced("prefix", log_prefix) < 0) {
205
      /* Failed to write log prefix. The log message writing
206
         would likely fail as well, but don't even try since
207
         the log prefix would be wrong. */
208
0
      return -1;
209
0
    }
210
0
    log_prefix_sent = TRUE;
211
0
  }
212
213
0
  data = t_str_new(128);
214
0
  str_printfa(data, "\001%c%s ", log_type, my_pid);
215
0
  if ((log_type & LOG_TYPE_FLAG_PREFIX_LEN) != 0)
216
0
    str_printfa(data, "%u ", ctx->log_prefix_type_pos);
217
0
  if (ctx->log_prefix != NULL)
218
0
    str_append(data, log_prefix_sanitize(ctx->log_prefix));
219
0
  size_t prefix_len = str_len(data);
220
221
0
  str_vprintfa(data, format, args);
222
223
0
  if (str_len(data)+1 <= PIPE_BUF && strchr(str_c(data), '\n') == NULL) {
224
    /* fast path: Log line is short enough and has no LFs */
225
0
    str_append_c(data, '\n');
226
0
    return log_fd_write(STDERR_FILENO,
227
0
            str_data(data), str_len(data));
228
0
  }
229
0
  return internal_send_split(data, prefix_len);
230
0
}
231
232
static void internal_on_handler_failure(const struct failure_context *ctx ATTR_UNUSED)
233
0
{
234
0
  failure_exit(FATAL_LOGERROR);
235
0
}
236
237
static struct failure_handler_vfuncs default_handler_vfuncs = {
238
  .write = &default_write,
239
  .on_handler_failure = &default_on_handler_failure,
240
};
241
242
static struct failure_handler_vfuncs syslog_handler_vfuncs = {
243
  .write = &syslog_write,
244
  .on_handler_failure = &syslog_on_handler_failure,
245
};
246
247
static struct failure_handler_vfuncs internal_handler_vfuncs = {
248
  .write = &internal_write,
249
  .on_handler_failure = &internal_on_handler_failure,
250
};
251
252
struct failure_handler_config failure_handler = { .fatal_err_reset = FATAL_LOGWRITE,
253
             .v = &default_handler_vfuncs };
254
255
static int common_handler(const struct failure_context *ctx,
256
        const char *format, va_list args)
257
1
{
258
1
  static int recursed = 0;
259
1
  int ret;
260
261
1
  if (recursed >= 2) {
262
    /* we're being called from some signal handler or we ran
263
       out of memory */
264
0
    return -1;
265
0
  }
266
1
  recursed++;
267
268
1
  T_BEGIN {
269
1
    ret = failure_handler.v->write(ctx, format, args);
270
1
  } T_END;
271
272
1
  if (ret < 0 && failure_ignore_errors)
273
0
    ret = 0;
274
275
1
  recursed--;
276
1
  return ret;
277
1
}
278
279
static void error_handler_real(const struct failure_context *ctx,
280
       const char *format, va_list args)
281
1
{
282
1
  if (common_handler(ctx, format, args) < 0)
283
0
    failure_handler.v->on_handler_failure(ctx);
284
1
  if (ctx->type == LOG_TYPE_ERROR && coredump_on_error)
285
0
    abort();
286
1
}
287
288
static void ATTR_FORMAT(2, 0)
289
i_internal_error_handler(const struct failure_context *ctx,
290
       const char *format, va_list args);
291
292
/* kludgy .. we want to trust log_stamp_format with -Wformat-nonliteral */
293
static const char *
294
get_log_stamp_format(const char *format_arg, unsigned int timestamp_usecs)
295
  ATTR_FORMAT_ARG(1);
296
297
static const char *get_log_stamp_format(const char *format_arg ATTR_UNUSED,
298
          unsigned int timestamp_usecs)
299
0
{
300
0
  if (log_stamp_format_suffix == NULL)
301
0
    return log_stamp_format;
302
0
  return t_strdup_printf("%s%06u%s", log_stamp_format,
303
0
             timestamp_usecs, log_stamp_format_suffix);
304
0
}
305
306
void failure_exit(int status)
307
0
{
308
0
  static bool recursed = FALSE;
309
310
0
  if (failure_exit_callback != NULL && !recursed) {
311
0
    recursed = TRUE;
312
0
    failure_exit_callback(&status);
313
0
  }
314
0
  lib_exit(status);
315
0
}
316
317
static void log_timestamp_add(const struct failure_context *ctx, string_t *str)
318
1
{
319
1
  const struct tm *tm = ctx->timestamp;
320
1
  char buf[256];
321
1
  struct timeval now;
322
323
1
  if (log_stamp_format != NULL) {
324
0
    if (tm == NULL) {
325
0
      i_gettimeofday(&now);
326
0
      tm = localtime(&now.tv_sec);
327
0
    } else {
328
0
      now.tv_usec = ctx->timestamp_usecs;
329
0
    }
330
331
0
    if (strftime(buf, sizeof(buf),
332
0
           get_log_stamp_format("unused", now.tv_usec), tm) > 0)
333
0
      str_append(str, buf);
334
0
  }
335
1
}
336
337
static void log_prefix_add(const struct failure_context *ctx, string_t *str)
338
1
{
339
1
  if (ctx->log_prefix == NULL) {
340
    /* use global log prefix */
341
1
    if (log_prefix != NULL)
342
0
      str_append(str, log_prefix);
343
1
    str_append(str, failure_log_type_prefixes[ctx->type]);
344
1
  } else if (ctx->log_prefix_type_pos == 0) {
345
0
    str_append(str, log_prefix_sanitize(ctx->log_prefix));
346
0
    str_append(str, failure_log_type_prefixes[ctx->type]);
347
0
  } else {
348
0
    const char *prefix = log_prefix_sanitize(ctx->log_prefix);
349
0
    i_assert(ctx->log_prefix_type_pos <= strlen(prefix));
350
0
    str_append_data(str, prefix, ctx->log_prefix_type_pos);
351
0
    str_append(str, failure_log_type_prefixes[ctx->type]);
352
0
    str_append(str, prefix + ctx->log_prefix_type_pos);
353
0
  }
354
1
}
355
356
static void fd_wait_writable(int fd)
357
0
{
358
0
  struct pollfd pfd = {
359
0
    .fd = fd,
360
0
    .events = POLLOUT | POLLERR | POLLHUP | POLLNVAL,
361
0
  };
362
363
  /* Use poll() instead of ioloop, because we don't want to recurse back
364
     to log writing in case something fails. */
365
0
  if (poll(&pfd, 1, -1) < 0 && errno != EINTR) {
366
    /* Unexpected error. We're already blocking on log writes,
367
       so we can't log it. */
368
0
    abort();
369
0
  }
370
0
}
371
372
static int log_fd_write(int fd, const unsigned char *data, size_t len)
373
1
{
374
1
  ssize_t ret;
375
1
  unsigned int prev_signal_term_counter = signal_term_counter;
376
1
  unsigned int terminal_eintr_count = 0;
377
1
  const char *old_title = NULL;
378
1
  bool failed = FALSE, process_title_changed = FALSE;
379
380
1
  while (!failed &&
381
1
         (ret = write(fd, data, len)) != (ssize_t)len) {
382
0
    if (ret > 0) {
383
      /* some was written, continue.. */
384
0
      data += ret;
385
0
      len -= ret;
386
0
      continue;
387
0
    }
388
0
    if (ret == 0) {
389
      /* out of disk space? */
390
0
      errno = ENOSPC;
391
0
      failed = TRUE;
392
0
      break;
393
0
    }
394
0
    switch (errno) {
395
0
    case EAGAIN: {
396
      /* Log fd is nonblocking - wait until we can write more.
397
         Indicate in process title that the process is waiting
398
         because it's waiting on the log.
399
400
         Remember that the log fd is shared across processes,
401
         which also means the log fd flags are shared. So if
402
         one process changes the O_NONBLOCK flag for a log fd,
403
         all the processes see the change. To avoid problems,
404
         we'll wait using poll() instead of changing the
405
         O_NONBLOCK flag. */
406
0
      if (!process_title_changed) {
407
0
        const char *title;
408
409
0
        process_title_changed = TRUE;
410
0
        old_title = t_strdup(process_title_get());
411
0
        if (old_title == NULL)
412
0
          title = "[blocking on log write]";
413
0
        else
414
0
          title = t_strdup_printf("%s - [blocking on log write]",
415
0
                old_title);
416
0
        process_title_set(title);
417
0
      }
418
0
      fd_wait_writable(fd);
419
0
      break;
420
0
    }
421
0
    case EINTR:
422
0
      if (prev_signal_term_counter == signal_term_counter) {
423
        /* non-terminal signal. ignore. */
424
0
      } else if (terminal_eintr_count++ == 0) {
425
        /* we'd rather not die in the middle of
426
           writing to log. try again once more */
427
0
      } else {
428
        /* received two terminal signals.
429
           someone wants us dead. */
430
0
        failed = TRUE;
431
0
        break;
432
0
      }
433
0
      break;
434
0
    default:
435
0
      failed = TRUE;
436
0
      break;
437
0
    }
438
0
    prev_signal_term_counter = signal_term_counter;
439
0
  }
440
1
  if (process_title_changed)
441
0
    process_title_set(old_title);
442
1
  return failed ? -1 : 0;
443
1
}
444
445
static void ATTR_NORETURN
446
default_fatal_finish(enum log_type type, int status)
447
0
{
448
0
  const char *backtrace, *error;
449
0
  static int recursed = 0;
450
451
0
  recursed++;
452
0
  if ((type == LOG_TYPE_PANIC || status == FATAL_OUTOFMEM) &&
453
0
      recursed == 1) {
454
0
    if (backtrace_get(&backtrace, &error) == 0)
455
0
      i_error("Raw backtrace: %s", backtrace);
456
0
  }
457
0
  recursed--;
458
459
0
  if (type == LOG_TYPE_PANIC || getenv("CORE_ERROR") != NULL ||
460
0
      (status == FATAL_OUTOFMEM && getenv("CORE_OUTOFMEM") != NULL))
461
0
    abort();
462
0
  else
463
0
    failure_exit(status);
464
0
}
465
466
static void ATTR_NORETURN fatal_handler_real(const struct failure_context *ctx,
467
          const char *format, va_list args)
468
0
{
469
0
  int status = ctx->exit_status;
470
0
  if (common_handler(ctx, format, args) < 0 &&
471
0
      status == FATAL_DEFAULT)
472
0
    status = failure_handler.fatal_err_reset;
473
0
  default_fatal_finish(ctx->type, status);
474
0
}
475
476
void default_fatal_handler(const struct failure_context *ctx,
477
         const char *format, va_list args)
478
0
{
479
0
  failure_handler.v = &default_handler_vfuncs;
480
0
  failure_handler.fatal_err_reset = FATAL_LOGWRITE;
481
0
  fatal_handler_real(ctx, format, args);
482
0
}
483
484
void default_error_handler(const struct failure_context *ctx,
485
         const char *format, va_list args)
486
1
{
487
1
  failure_handler.v = &default_handler_vfuncs;
488
1
  failure_handler.fatal_err_reset = FATAL_LOGWRITE;
489
1
  error_handler_real(ctx, format, args);
490
1
}
491
492
void i_log_type(const struct failure_context *ctx, const char *format, ...)
493
0
{
494
0
  va_list args;
495
496
0
  va_start(args, format);
497
0
  i_log_typev(ctx, format, args);
498
0
  va_end(args);
499
0
}
500
501
void i_log_typev(const struct failure_context *ctx, const char *format,
502
     va_list args)
503
0
{
504
0
  switch (ctx->type) {
505
0
  case LOG_TYPE_DEBUG:
506
0
    debug_handler(ctx, format, args);
507
0
    break;
508
0
  case LOG_TYPE_INFO:
509
0
    info_handler(ctx, format, args);
510
0
    break;
511
0
  default:
512
0
    error_handler(ctx, format, args);
513
0
  }
514
0
}
515
516
void i_panic(const char *format, ...)
517
0
{
518
0
  struct failure_context ctx;
519
0
  va_list args;
520
521
0
  lib_set_clean_exit(TRUE);
522
0
  i_zero(&ctx);
523
0
  ctx.type = LOG_TYPE_PANIC;
524
525
0
  va_start(args, format);
526
0
  fatal_handler(&ctx, format, args);
527
0
  i_unreached();
528
  /*va_end(args);*/
529
0
}
530
531
void i_fatal(const char *format, ...)
532
0
{
533
0
  struct failure_context ctx;
534
0
  va_list args;
535
536
0
  lib_set_clean_exit(TRUE);
537
0
  i_zero(&ctx);
538
0
  ctx.type = LOG_TYPE_FATAL;
539
0
  ctx.exit_status = FATAL_DEFAULT;
540
541
0
  va_start(args, format);
542
0
  fatal_handler(&ctx, format, args);
543
0
  i_unreached();
544
  /*va_end(args);*/
545
0
}
546
547
void i_fatal_status(int status, const char *format, ...)
548
0
{
549
0
  struct failure_context ctx;
550
0
  va_list args;
551
552
0
  lib_set_clean_exit(TRUE);
553
0
  i_zero(&ctx);
554
0
  ctx.type = LOG_TYPE_FATAL;
555
0
  ctx.exit_status = status;
556
557
0
  va_start(args, format);
558
0
  fatal_handler(&ctx, format, args);
559
0
  i_unreached();
560
  /*va_end(args);*/
561
0
}
562
563
void i_error(const char *format, ...)
564
0
{
565
0
  int old_errno = errno;
566
0
  va_list args;
567
568
0
  va_start(args, format);
569
0
  error_handler(&failure_ctx_error, format, args);
570
0
  va_end(args);
571
572
0
  errno = old_errno;
573
0
}
574
575
void i_warning(const char *format, ...)
576
0
{
577
0
  int old_errno = errno;
578
0
  va_list args;
579
580
0
  va_start(args, format);
581
0
  error_handler(&failure_ctx_warning, format, args);
582
0
  va_end(args);
583
584
0
  errno = old_errno;
585
0
}
586
587
void i_info(const char *format, ...)
588
1
{
589
1
  int old_errno = errno;
590
1
  va_list args;
591
592
1
  va_start(args, format);
593
1
  info_handler(&failure_ctx_info, format, args);
594
1
  va_end(args);
595
596
1
  errno = old_errno;
597
1
}
598
599
void i_debug(const char *format, ...)
600
0
{
601
0
  int old_errno = errno;
602
0
  va_list args;
603
604
0
  va_start(args, format);
605
0
  debug_handler(&failure_ctx_debug, format, args);
606
0
  va_end(args);
607
608
0
  errno = old_errno;
609
0
}
610
611
void i_set_fatal_handler(failure_callback_t *callback ATTR_NORETURN)
612
0
{
613
0
        fatal_handler = callback;
614
0
}
615
616
void i_set_error_handler(failure_callback_t *callback)
617
0
{
618
0
  coredump_on_error = getenv("CORE_ERROR") != NULL;
619
0
  error_handler = callback;
620
0
}
621
622
void i_set_info_handler(failure_callback_t *callback)
623
0
{
624
0
  info_handler = callback;
625
0
}
626
627
void i_set_debug_handler(failure_callback_t *callback)
628
0
{
629
0
  debug_handler = callback;
630
0
}
631
632
void i_get_failure_handlers(failure_callback_t **fatal_callback_r,
633
          failure_callback_t **error_callback_r,
634
          failure_callback_t **info_callback_r,
635
          failure_callback_t **debug_callback_r)
636
0
{
637
0
  *fatal_callback_r = fatal_handler;
638
0
  *error_callback_r = error_handler;
639
0
  *info_callback_r = info_handler;
640
0
  *debug_callback_r = debug_handler;
641
0
}
642
643
void i_syslog_fatal_handler(const struct failure_context *ctx,
644
          const char *format, va_list args)
645
0
{
646
0
  failure_handler.v = &syslog_handler_vfuncs;
647
0
  failure_handler.fatal_err_reset = FATAL_LOGERROR;
648
0
  fatal_handler_real(ctx, format, args);
649
0
}
650
651
void i_syslog_error_handler(const struct failure_context *ctx,
652
          const char *format, va_list args)
653
0
{
654
0
  failure_handler.v = &syslog_handler_vfuncs;
655
0
  failure_handler.fatal_err_reset = FATAL_LOGERROR;
656
0
  error_handler_real(ctx, format, args);
657
0
}
658
659
void i_set_failure_syslog(const char *ident, int options, int facility)
660
0
{
661
  /* openlog() keeps using the pointer directly. Duplicate it in case
662
     caller frees the string. */
663
0
  i_free(syslog_ident);
664
0
  syslog_ident = i_strdup(ident);
665
0
  openlog(syslog_ident, options, facility);
666
667
0
  i_set_fatal_handler(i_syslog_fatal_handler);
668
0
  i_set_error_handler(i_syslog_error_handler);
669
0
  i_set_info_handler(i_syslog_error_handler);
670
0
  i_set_debug_handler(i_syslog_error_handler);
671
0
}
672
673
static void open_log_file(int *fd, const char *path)
674
0
{
675
0
  const char *str;
676
677
0
  if (log_fd_can_close(*fd)) {
678
0
    if (close(*fd) < 0) {
679
0
      str = t_strdup_printf("close(%d) failed: %m\n", *fd);
680
0
      (void)write_full(STDERR_FILENO, str, strlen(str));
681
0
    }
682
0
  }
683
684
0
  if (path == NULL || strcmp(path, "/dev/stderr") == 0)
685
0
    *fd = STDERR_FILENO;
686
0
  else if (strcmp(path, "/dev/stdout") == 0)
687
0
    *fd = STDOUT_FILENO;
688
0
  else {
689
0
    *fd = open(path, O_CREAT | O_APPEND | O_WRONLY, 0600);
690
0
    if (*fd == -1) {
691
0
      *fd = STDERR_FILENO;
692
0
      str = t_strdup_printf("Can't open log file %s: %m\n",
693
0
                path);
694
0
      (void)write_full(STDERR_FILENO, str, strlen(str));
695
0
      if (fd == &log_fd)
696
0
        failure_exit(FATAL_LOGOPEN);
697
0
      else
698
0
        i_fatal_status(FATAL_LOGOPEN, "%s", str);
699
0
    }
700
0
    fd_close_on_exec(*fd, TRUE);
701
0
  }
702
0
}
703
704
void i_set_failure_file(const char *path, const char *prefix)
705
0
{
706
0
  i_set_failure_prefix("%s", prefix);
707
708
0
  if (log_fd_can_close(log_info_fd) && log_info_fd != log_fd) {
709
0
    if (close(log_info_fd) < 0)
710
0
      i_error("close(%d) failed: %m", log_info_fd);
711
0
  }
712
713
0
  if (log_fd_can_close(log_debug_fd) && log_debug_fd != log_info_fd &&
714
0
      log_debug_fd != log_fd) {
715
0
    if (close(log_debug_fd) < 0)
716
0
      i_error("close(%d) failed: %m", log_debug_fd);
717
0
  }
718
719
0
  open_log_file(&log_fd, path);
720
  /* if info/debug logs are elsewhere, i_set_info/debug_file()
721
     overrides these later. */
722
0
  log_info_fd = log_fd;
723
0
  log_debug_fd = log_fd;
724
725
0
  i_set_fatal_handler(default_fatal_handler);
726
0
  i_set_error_handler(default_error_handler);
727
0
  i_set_info_handler(default_error_handler);
728
0
  i_set_debug_handler(default_error_handler);
729
0
}
730
731
static int i_failure_send_option_forced(const char *key, const char *value)
732
0
{
733
0
  const char *str;
734
735
0
  str = t_strdup_printf("\001%c%s %s=%s\n", LOG_TYPE_OPTION+1,
736
0
            my_pid, key, value);
737
0
  return log_fd_write(STDERR_FILENO, (const unsigned char *)str,
738
0
          strlen(str));
739
0
}
740
741
static void i_failure_send_option(const char *key, const char *value)
742
0
{
743
0
  if (error_handler == i_internal_error_handler)
744
0
    (void)i_failure_send_option_forced(key, value);
745
0
}
746
747
void i_set_failure_prefix(const char *prefix_fmt, ...)
748
0
{
749
0
  va_list args;
750
751
0
  va_start(args, prefix_fmt);
752
0
  i_free(log_prefix);
753
0
  T_BEGIN {
754
0
    log_prefix = i_strdup(log_prefix_sanitize(
755
0
      t_strdup_vprintf(prefix_fmt, args)));
756
0
  } T_END;
757
0
  va_end(args);
758
759
0
  log_prefix_sent = FALSE;
760
0
}
761
762
void i_unset_failure_prefix(void)
763
0
{
764
0
  i_free(log_prefix);
765
0
  log_prefix = i_strdup("");
766
0
  log_prefix_sent = FALSE;
767
0
}
768
769
const char *i_get_failure_prefix(void)
770
0
{
771
0
  return log_prefix != NULL ? log_prefix : "";
772
0
}
773
774
static int internal_send_split(string_t *full_str, size_t prefix_len)
775
0
{
776
  /* This function splits the log line into PIPE_BUF sized blocks, so
777
     the log process doesn't see partial lines. The log prefix is
778
     repeated for each sent line. However, if the log prefix is
779
     excessively long, we're still going to send the log lines even
780
     if they are longer than PIPE_BUF. LINE_MIN_TEXT_LEN controls the
781
     minimum number of bytes we're going to send of the actual log line
782
     regardless of the log prefix length. (Alternative solution could be
783
     to just forcibly split the line to PIPE_BUF length blocks without
784
     repeating the log prefix for subsequent lines.) */
785
0
#define LINE_MIN_TEXT_LEN 128
786
#if LINE_MIN_TEXT_LEN >= PIPE_BUF
787
#  error LINE_MIN_TEXT_LEN too large
788
#endif
789
0
  string_t *str;
790
0
  size_t max_text_len, pos = prefix_len;
791
792
0
  str = t_str_new(PIPE_BUF);
793
0
  str_append_data(str, str_data(full_str), prefix_len);
794
0
  if (prefix_len < PIPE_BUF) {
795
0
    max_text_len = I_MAX(PIPE_BUF - prefix_len - 1,
796
0
             LINE_MIN_TEXT_LEN);
797
0
  } else {
798
0
    max_text_len = LINE_MIN_TEXT_LEN;
799
0
  }
800
801
0
  while (pos < str_len(full_str)) {
802
0
    str_truncate(str, prefix_len);
803
0
    const char *text = str_c(full_str) + pos;
804
0
    const char *lf = strchr(text, '\n');
805
0
    size_t line_len;
806
0
    if (lf == NULL || (size_t)(lf - text) > max_text_len) {
807
0
      str_append_max(str, text, max_text_len);
808
0
      str_append_c(str, '\n');
809
0
      line_len = max_text_len;
810
0
    } else {
811
      /* write up to and including the LF */
812
0
      line_len = lf - text + 1;
813
0
      str_append_data(str, text, line_len);
814
0
    }
815
0
    if (log_fd_write(STDERR_FILENO,
816
0
         str_data(str), str_len(str)) < 0)
817
0
      return -1;
818
0
    pos += line_len;
819
0
  }
820
0
  return 0;
821
0
}
822
823
824
static bool line_parse_prefix(const char *line, enum log_type *log_type_r,
825
            bool *replace_prefix_r, bool *have_prefix_len_r)
826
0
{
827
0
  if (*line != 1)
828
0
    return FALSE;
829
830
0
  unsigned char log_type = (line[1] & 0x3f);
831
0
  if (log_type == '\0') {
832
0
    i_warning("Broken log line follows (type=NUL)");
833
0
    return FALSE;
834
0
  }
835
0
  log_type--;
836
837
0
  if (log_type > LOG_TYPE_OPTION) {
838
0
    i_warning("Broken log line follows (type=%d)", log_type);
839
0
    return FALSE;
840
0
  }
841
0
  *log_type_r = log_type;
842
0
  *replace_prefix_r = (line[1] & LOG_TYPE_FLAG_DISABLE_LOG_PREFIX) != 0;
843
0
  *have_prefix_len_r = (line[1] & LOG_TYPE_FLAG_PREFIX_LEN) != 0;
844
0
  return TRUE;
845
0
}
846
847
void i_failure_parse_line(const char *line, struct failure_line *failure)
848
0
{
849
0
  bool have_prefix_len = FALSE;
850
851
0
  i_zero(failure);
852
0
  if (!line_parse_prefix(line, &failure->log_type,
853
0
             &failure->disable_log_prefix,
854
0
             &have_prefix_len)) {
855
0
    failure->log_type = LOG_TYPE_ERROR;
856
0
    failure->text = line;
857
0
    return;
858
0
  }
859
860
0
  line += 2;
861
0
  failure->text = line;
862
0
  while (*line >= '0' && *line <= '9') {
863
0
    failure->pid = failure->pid*10 + (*line - '0');
864
0
    line++;
865
0
  }
866
0
  if (*line != ' ') {
867
    /* some old protocol? */
868
0
    failure->pid = 0;
869
0
    return;
870
0
  }
871
0
  line++;
872
873
0
  if (have_prefix_len) {
874
0
    if (str_parse_uint(line, &failure->log_prefix_len, &line) < 0 ||
875
0
        line[0] != ' ') {
876
      /* unexpected, but ignore */
877
0
    } else {
878
0
      line++;
879
0
      if (failure->log_prefix_len > strlen(line)) {
880
        /* invalid */
881
0
        failure->log_prefix_len = 0;
882
0
      }
883
0
    }
884
0
  }
885
0
  failure->text = line;
886
0
}
887
888
static void ATTR_NORETURN ATTR_FORMAT(2, 0)
889
i_internal_fatal_handler(const struct failure_context *ctx,
890
       const char *format, va_list args)
891
0
{
892
0
  failure_handler.v = &internal_handler_vfuncs;
893
0
  failure_handler.fatal_err_reset = FATAL_LOGERROR;
894
0
  fatal_handler_real(ctx, format, args);
895
896
897
0
}
898
899
static void
900
i_internal_error_handler(const struct failure_context *ctx,
901
       const char *format, va_list args)
902
0
{
903
0
  failure_handler.v = &internal_handler_vfuncs;
904
0
  failure_handler.fatal_err_reset = FATAL_LOGERROR;
905
0
  error_handler_real(ctx, format, args);
906
0
}
907
908
void i_set_failure_internal(void)
909
0
{
910
0
  fd_set_nonblock(STDERR_FILENO, TRUE);
911
0
  i_set_fatal_handler(i_internal_fatal_handler);
912
0
  i_set_error_handler(i_internal_error_handler);
913
0
  i_set_info_handler(i_internal_error_handler);
914
0
  i_set_debug_handler(i_internal_error_handler);
915
0
}
916
917
bool i_failure_handler_is_internal(failure_callback_t *const callback)
918
0
{
919
0
  return callback == i_internal_fatal_handler ||
920
0
    callback == i_internal_error_handler;
921
0
}
922
923
void i_set_failure_ignore_errors(bool ignore)
924
0
{
925
0
  failure_ignore_errors = ignore;
926
0
}
927
928
void i_set_info_file(const char *path)
929
0
{
930
0
  if (log_info_fd == log_fd)
931
0
    log_info_fd = STDERR_FILENO;
932
933
0
  open_log_file(&log_info_fd, path);
934
0
        info_handler = default_error_handler;
935
  /* write debug-level messages to the info_log_path,
936
    until i_set_debug_file() was called */
937
0
  log_debug_fd = log_info_fd;
938
0
  i_set_debug_handler(default_error_handler);
939
0
}
940
941
void i_set_debug_file(const char *path)
942
0
{
943
0
  if (log_debug_fd == log_fd || log_debug_fd == log_info_fd)
944
0
    log_debug_fd = STDERR_FILENO;
945
946
0
  open_log_file(&log_debug_fd, path);
947
0
  debug_handler = default_error_handler;
948
0
}
949
950
bool i_failure_have_stdout_logs(void)
951
0
{
952
0
  return log_fd == STDOUT_FILENO ||
953
0
    log_info_fd == STDOUT_FILENO ||
954
0
    log_debug_fd == STDOUT_FILENO;
955
0
}
956
957
void i_set_failure_timestamp_format(const char *fmt)
958
0
{
959
0
  const char *p;
960
961
0
  i_free(log_stamp_format);
962
0
  i_free_and_null(log_stamp_format_suffix);
963
964
0
  p = strstr(fmt, "%{usecs}");
965
0
  if (p == NULL)
966
0
    log_stamp_format = i_strdup(fmt);
967
0
  else {
968
0
    log_stamp_format = i_strdup_until(fmt, p);
969
0
    log_stamp_format_suffix = i_strdup(p + 8);
970
0
  }
971
0
}
972
973
void i_set_failure_send_ip(const struct ip_addr *ip)
974
0
{
975
0
  i_failure_send_option("ip", net_ip2addr(ip));
976
0
}
977
978
void i_set_failure_send_prefix(const char *prefix)
979
0
{
980
0
  i_failure_send_option("prefix", prefix);
981
0
}
982
983
void i_set_failure_exit_callback(void (*callback)(int *status))
984
0
{
985
0
  failure_exit_callback = callback;
986
0
}
987
988
void failures_deinit(void)
989
0
{
990
0
  if (log_debug_fd == log_info_fd || log_debug_fd == log_fd)
991
0
    log_debug_fd = STDERR_FILENO;
992
993
0
  if (log_info_fd == log_fd)
994
0
    log_info_fd = STDERR_FILENO;
995
996
0
  if (log_fd_can_close(log_fd)) {
997
0
    i_close_fd(&log_fd);
998
0
    log_fd = STDERR_FILENO;
999
0
  }
1000
1001
0
  if (log_fd_can_close(log_info_fd)) {
1002
0
    i_close_fd(&log_info_fd);
1003
0
    log_info_fd = STDERR_FILENO;
1004
0
  }
1005
1006
0
  if (log_fd_can_close(log_debug_fd)) {
1007
0
    i_close_fd(&log_debug_fd);
1008
0
    log_debug_fd = STDERR_FILENO;
1009
0
  }
1010
1011
0
  i_free_and_null(log_prefix);
1012
0
  i_free_and_null(log_stamp_format);
1013
0
  i_free_and_null(log_stamp_format_suffix);
1014
0
  i_free(syslog_ident);
1015
0
}
1016
1017
#undef i_unreached
1018
void i_unreached(const char *source_filename, int source_linenum)
1019
0
{
1020
0
  i_panic("file %s: line %d: unreached", source_filename, source_linenum);
1021
0
}