summaryrefslogtreecommitdiffstats
path: root/src/lib/failures.h
blob: afb4c6f4ee1312cec74f4461f0577f88b55cc1ff (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#ifndef FAILURES_H
#define FAILURES_H

struct ip_addr;

/* Default exit status codes that we could use. */
enum fatal_exit_status {
	FATAL_LOGOPEN	= 80, /* Can't open log file */
	FATAL_LOGWRITE  = 81, /* Can't write to log file */
	FATAL_LOGERROR  = 82, /* Internal logging error */
	FATAL_OUTOFMEM	= 83, /* Out of memory */
	FATAL_EXEC	= 84, /* exec() failed */

	FATAL_DEFAULT	= 89
};

enum log_type {
	LOG_TYPE_DEBUG,
	LOG_TYPE_INFO,
	LOG_TYPE_WARNING,
	LOG_TYPE_ERROR,
	LOG_TYPE_FATAL,
	LOG_TYPE_PANIC,

	LOG_TYPE_COUNT,
	/* special case */
	LOG_TYPE_OPTION
};

struct failure_line {
	pid_t pid;
	enum log_type log_type;
	/* If non-zero, the first log_prefix_len bytes in text indicate
	   the log prefix. This implies disable_log_prefix=TRUE. */
	unsigned int log_prefix_len;
	/* Disable the global log prefix. */
	bool disable_log_prefix;
	const char *text;
};

struct failure_context {
	enum log_type type;
	int exit_status; /* for LOG_TYPE_FATAL */
	const struct tm *timestamp; /* NULL = use time() + localtime() */
	unsigned int timestamp_usecs;
	const char *log_prefix; /* override the default log prefix */
	/* If non-0, insert the log type text (e.g. "Info: ") at this position
	   in the log_prefix instead of appending it. */
	unsigned int log_prefix_type_pos;
};

#define DEFAULT_FAILURE_STAMP_FORMAT "%b %d %H:%M:%S "

typedef void failure_callback_t(const struct failure_context *ctx,
				const char *format, va_list args);

extern const char *failure_log_type_prefixes[];
extern const char *failure_log_type_names[];

void i_log_type(const struct failure_context *ctx, const char *format, ...)
	ATTR_FORMAT(2, 3);
void i_log_typev(const struct failure_context *ctx, const char *format,
		 va_list args) ATTR_FORMAT(2, 0);

void i_panic(const char *format, ...) ATTR_FORMAT(1, 2) ATTR_NORETURN ATTR_COLD;
void i_unreached(const char *source_filename, int source_linenum)
	ATTR_NORETURN ATTR_COLD;
#define i_unreached() \
	i_unreached(__FILE__, __LINE__)
void i_fatal(const char *format, ...) ATTR_FORMAT(1, 2) ATTR_NORETURN ATTR_COLD;
void i_error(const char *format, ...) ATTR_FORMAT(1, 2) ATTR_COLD;
void i_warning(const char *format, ...) ATTR_FORMAT(1, 2);
void i_info(const char *format, ...) ATTR_FORMAT(1, 2);
void i_debug(const char *format, ...) ATTR_FORMAT(1, 2);

void i_fatal_status(int status, const char *format, ...)
	ATTR_FORMAT(2, 3) ATTR_NORETURN ATTR_COLD;

/* Change failure handlers. */
#ifndef __cplusplus
void i_set_fatal_handler(failure_callback_t *callback ATTR_NORETURN);
#else
/* Older g++ doesn't like attributes in parameters */
void i_set_fatal_handler(failure_callback_t *callback);
#endif
void i_set_error_handler(failure_callback_t *callback);
void i_set_info_handler(failure_callback_t *callback);
void i_set_debug_handler(failure_callback_t *callback);
void i_get_failure_handlers(failure_callback_t **fatal_callback_r,
			    failure_callback_t **error_callback_r,
			    failure_callback_t **info_callback_r,
			    failure_callback_t **debug_callback_r);

/* Send failures to file. */
void default_fatal_handler(const struct failure_context *ctx,
			   const char *format, va_list args)
	ATTR_NORETURN ATTR_FORMAT(2, 0);
void default_error_handler(const struct failure_context *ctx,
			   const char *format, va_list args)
	ATTR_FORMAT(2, 0);

/* Send failures to syslog() */
void i_syslog_fatal_handler(const struct failure_context *ctx,
			    const char *format, va_list args)
	ATTR_NORETURN ATTR_FORMAT(2, 0);
void i_syslog_error_handler(const struct failure_context *ctx,
			    const char *format, va_list args)
	ATTR_FORMAT(2, 0);

/* Open syslog and set failure/info/debug handlers to use it. */
void i_set_failure_syslog(const char *ident, int options, int facility);

/* Send failures to specified log file instead of stderr. */
void i_set_failure_file(const char *path, const char *prefix);

/* Send errors to stderr using internal error protocol. */
void i_set_failure_internal(void);
/* Returns TRUE if the given callback handler was set via
   i_set_failure_internal(). */
bool i_failure_handler_is_internal(failure_callback_t *const callback);
/* If writing to log fails, ignore it instead of existing with
   FATAL_LOGWRITE or FATAL_LOGERROR. */
void i_set_failure_ignore_errors(bool ignore);

/* Send informational messages to specified log file. i_set_failure_*()
   functions modify the info file too, so call this function after them. */
void i_set_info_file(const char *path);

/* Send debug-level message to the given log file. The i_set_info_file() 
   function modifies also the debug log file, so call this function after it. */
void i_set_debug_file(const char *path);

/* Set the failure prefix. */
void i_set_failure_prefix(const char *prefix_fmt, ...) ATTR_FORMAT(1, 2);
/* Set prefix to "". */
void i_unset_failure_prefix(void);
/* Returns the current failure prefix (never NULL). */
const char *i_get_failure_prefix(void);
/* Prefix failures with a timestamp. fmt is in strftime() format. */
void i_set_failure_timestamp_format(const char *fmt);
/* When logging with internal error protocol, update the process's current
   IP address / log prefix by sending it to log process. This is mainly used to
   improve the error message if the process crashes. */
void i_set_failure_send_ip(const struct ip_addr *ip);
void i_set_failure_send_prefix(const char *prefix);

/* Call the callback before exit()ing. The callback may update the status. */
void i_set_failure_exit_callback(void (*callback)(int *status));
/* Call the exit callback and exit() */
void failure_exit(int status) ATTR_NORETURN ATTR_COLD;

/* Parse a line logged using internal failure handler */
void i_failure_parse_line(const char *line, struct failure_line *failure);

void failures_deinit(void);

#endif