/src/systemd/src/basic/log.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
2 | | #pragma once |
3 | | |
4 | | #include <stdio.h> |
5 | | #include <string.h> |
6 | | #include <syslog.h> |
7 | | |
8 | | #include "forward.h" |
9 | | |
10 | | /* Some structures we reference but don't want to pull in headers for */ |
11 | | struct iovec; |
12 | | struct signalfd_siginfo; |
13 | | |
14 | | typedef enum LogTarget{ |
15 | | LOG_TARGET_CONSOLE, |
16 | | LOG_TARGET_KMSG, |
17 | | LOG_TARGET_JOURNAL, |
18 | | LOG_TARGET_SYSLOG, |
19 | | LOG_TARGET_CONSOLE_PREFIXED, |
20 | | LOG_TARGET_JOURNAL_OR_KMSG, |
21 | | LOG_TARGET_SYSLOG_OR_KMSG, |
22 | | LOG_TARGET_AUTO, /* console if stderr is not journal, JOURNAL_OR_KMSG otherwise */ |
23 | | LOG_TARGET_NULL, |
24 | | _LOG_TARGET_SINGLE_MAX = LOG_TARGET_SYSLOG + 1, |
25 | | _LOG_TARGET_MAX = LOG_TARGET_NULL + 1, |
26 | | _LOG_TARGET_INVALID = -EINVAL, |
27 | | } LogTarget; |
28 | | |
29 | | /* This log level disables logging completely. It can only be passed to log_set_max_level() and cannot be |
30 | | * used as a regular log level. */ |
31 | | #define LOG_NULL (LOG_EMERG - 1) |
32 | | assert_cc(LOG_NULL == -1); |
33 | | |
34 | | #define SYNTHETIC_ERRNO(num) (ABS(num) | (1 << 30)) |
35 | | #define IS_SYNTHETIC_ERRNO(val) (((val) >> 30) == 1) |
36 | 21.0k | #define ERRNO_VALUE(val) (ABS(val) & ~(1 << 30)) |
37 | | |
38 | | /* The callback function to be invoked when syntax warnings are seen |
39 | | * in the unit files. */ |
40 | | typedef void (*log_syntax_callback_t)(const char *unit, int level, void *userdata); |
41 | | void set_log_syntax_callback(log_syntax_callback_t cb, void *userdata); |
42 | | |
43 | 0 | static inline void clear_log_syntax_callback(dummy_t *dummy) { |
44 | 0 | set_log_syntax_callback(/* cb= */ NULL, /* userdata= */ NULL); |
45 | 0 | } Unexecuted instantiation: systemctl-compat-halt.c:clear_log_syntax_callback Unexecuted instantiation: systemctl-compat-runlevel.c:clear_log_syntax_callback Unexecuted instantiation: systemctl-compat-shutdown.c:clear_log_syntax_callback Unexecuted instantiation: systemctl-compat-telinit.c:clear_log_syntax_callback Unexecuted instantiation: systemctl-daemon-reload.c:clear_log_syntax_callback Unexecuted instantiation: systemctl-logind.c:clear_log_syntax_callback Unexecuted instantiation: systemctl-start-unit.c:clear_log_syntax_callback Unexecuted instantiation: systemctl-sysv-compat.c:clear_log_syntax_callback Unexecuted instantiation: systemctl-util.c:clear_log_syntax_callback Unexecuted instantiation: systemctl.c:clear_log_syntax_callback Unexecuted instantiation: fuzz-systemctl-parse-argv.c:clear_log_syntax_callback |
46 | | |
47 | | const char* log_target_to_string(LogTarget target) _const_; |
48 | | LogTarget log_target_from_string(const char *s) _pure_; |
49 | | void log_set_target(LogTarget target); |
50 | | void log_set_target_and_open(LogTarget target); |
51 | | int log_set_target_from_string(const char *e); |
52 | | LogTarget log_get_target(void) _pure_; |
53 | | void log_settle_target(void); |
54 | | |
55 | | int log_set_max_level(int level); |
56 | | int log_set_max_level_from_string(const char *e); |
57 | | int log_get_max_level(void) _pure_; |
58 | | int log_get_target_max_level(LogTarget target); |
59 | | int log_max_levels_to_string(int level, char **ret); |
60 | | |
61 | | void log_set_facility(int facility); |
62 | | |
63 | | void log_show_color(bool b); |
64 | | bool log_get_show_color(void) _pure_; |
65 | | void log_show_location(bool b); |
66 | | bool log_get_show_location(void) _pure_; |
67 | | void log_show_time(bool b); |
68 | | bool log_get_show_time(void) _pure_; |
69 | | void log_show_tid(bool b); |
70 | | bool log_get_show_tid(void) _pure_; |
71 | | |
72 | | int log_show_color_from_string(const char *e); |
73 | | int log_show_location_from_string(const char *e); |
74 | | int log_show_time_from_string(const char *e); |
75 | | int log_show_tid_from_string(const char *e); |
76 | | |
77 | | /* Functions below that open and close logs or configure logging based on the |
78 | | * environment should not be called from library code — this is always a job |
79 | | * for the application itself. */ |
80 | | |
81 | | bool stderr_is_journal(void); |
82 | | int log_open(void); |
83 | | void log_close(void); |
84 | | void log_forget_fds(void); |
85 | | |
86 | | void log_parse_environment_variables(void); |
87 | | void log_parse_environment(void); |
88 | | |
89 | | int log_dispatch_internal( |
90 | | int level, |
91 | | int error, |
92 | | const char *file, |
93 | | int line, |
94 | | const char *func, |
95 | | const char *object_field, |
96 | | const char *object, |
97 | | const char *extra_field, |
98 | | const char *extra, |
99 | | char *buffer); |
100 | | |
101 | | int log_internal( |
102 | | int level, |
103 | | int error, |
104 | | const char *file, |
105 | | int line, |
106 | | const char *func, |
107 | | const char *format, ...) _printf_(6,7); |
108 | | |
109 | | int log_internalv( |
110 | | int level, |
111 | | int error, |
112 | | const char *file, |
113 | | int line, |
114 | | const char *func, |
115 | | const char *format, |
116 | | va_list ap) _printf_(6,0); |
117 | | |
118 | | int log_object_internalv( |
119 | | int level, |
120 | | int error, |
121 | | const char *file, |
122 | | int line, |
123 | | const char *func, |
124 | | const char *object_field, |
125 | | const char *object, |
126 | | const char *extra_field, |
127 | | const char *extra, |
128 | | const char *format, |
129 | | va_list ap) _printf_(10,0); |
130 | | |
131 | | int log_object_internal( |
132 | | int level, |
133 | | int error, |
134 | | const char *file, |
135 | | int line, |
136 | | const char *func, |
137 | | const char *object_field, |
138 | | const char *object, |
139 | | const char *extra_field, |
140 | | const char *extra, |
141 | | const char *format, ...) _printf_(10,11); |
142 | | |
143 | | int log_struct_internal( |
144 | | int level, |
145 | | int error, |
146 | | const char *file, |
147 | | int line, |
148 | | const char *func, |
149 | | const char *format, ...) _sentinel_; |
150 | | |
151 | | int log_oom_internal( |
152 | | int level, |
153 | | const char *file, |
154 | | int line, |
155 | | const char *func); |
156 | | |
157 | | int log_format_iovec( |
158 | | struct iovec *iovec, |
159 | | size_t iovec_len, |
160 | | size_t *n, |
161 | | bool newline_separator, |
162 | | int error, |
163 | | const char *format, |
164 | | va_list ap) _printf_(6, 0); |
165 | | |
166 | | int log_struct_iovec_internal( |
167 | | int level, |
168 | | int error, |
169 | | const char *file, |
170 | | int line, |
171 | | const char *func, |
172 | | const struct iovec *input_iovec, |
173 | | size_t n_input_iovec); |
174 | | |
175 | | /* This modifies the buffer passed! */ |
176 | | int log_dump_internal( |
177 | | int level, |
178 | | int error, |
179 | | const char *file, |
180 | | int line, |
181 | | const char *func, |
182 | | char *buffer); |
183 | | |
184 | | #define log_dispatch(level, error, buffer) \ |
185 | | log_dispatch_internal(level, error, PROJECT_FILE, __LINE__, __func__, NULL, NULL, NULL, NULL, buffer) |
186 | | |
187 | | /* Logging with level */ |
188 | | #define log_full_errno_zerook(level, error, ...) \ |
189 | 10.5k | ({ \ |
190 | 10.5k | int _level = (level), _e = (error); \ |
191 | 10.5k | _e = (log_get_max_level() >= LOG_PRI(_level)) \ |
192 | 10.5k | ? log_internal(_level, _e, PROJECT_FILE, __LINE__, __func__, __VA_ARGS__) \ |
193 | 10.5k | : -ERRNO_VALUE(_e); \ |
194 | 10.5k | _e < 0 ? _e : -ESTRPIPE; \ |
195 | 1 | }) |
196 | | |
197 | | #if BUILD_MODE_DEVELOPER && !defined(TEST_CODE) |
198 | 4.19k | # define ASSERT_NON_ZERO(x) assert((x) != 0) |
199 | | #else |
200 | | # define ASSERT_NON_ZERO(x) |
201 | | #endif |
202 | | |
203 | | #define log_full_errno(level, error, ...) \ |
204 | 9.50k | ({ \ |
205 | 9.50k | int _error = (error); \ |
206 | 9.50k | ASSERT_NON_ZERO(_error); \ |
207 | 9.50k | log_full_errno_zerook(level, _error, __VA_ARGS__); \ |
208 | 9.50k | }) |
209 | | |
210 | | #define log_full(level, fmt, ...) \ |
211 | 1.03k | ({ \ |
212 | 1.03k | if (BUILD_MODE_DEVELOPER) \ |
213 | 1.03k | assert(!strstr(fmt, "%m")); \ |
214 | 1.03k | (void) log_full_errno_zerook(level, 0, fmt, ##__VA_ARGS__); \ |
215 | 1 | }) |
216 | | |
217 | | int log_emergency_level(void); |
218 | | |
219 | | /* Normal logging */ |
220 | 0 | #define log_debug(...) log_full(LOG_DEBUG, __VA_ARGS__) |
221 | 616 | #define log_info(...) log_full(LOG_INFO, __VA_ARGS__) |
222 | 1 | #define log_notice(...) log_full(LOG_NOTICE, __VA_ARGS__) |
223 | 0 | #define log_warning(...) log_full(LOG_WARNING, __VA_ARGS__) |
224 | 422 | #define log_error(...) log_full(LOG_ERR, __VA_ARGS__) |
225 | | #define log_emergency(...) log_full(log_emergency_level(), __VA_ARGS__) |
226 | | |
227 | | /* Logging triggered by an errno-like error */ |
228 | 0 | #define log_debug_errno(error, ...) log_full_errno(LOG_DEBUG, error, __VA_ARGS__) |
229 | 105 | #define log_info_errno(error, ...) log_full_errno(LOG_INFO, error, __VA_ARGS__) |
230 | | #define log_notice_errno(error, ...) log_full_errno(LOG_NOTICE, error, __VA_ARGS__) |
231 | 0 | #define log_warning_errno(error, ...) log_full_errno(LOG_WARNING, error, __VA_ARGS__) |
232 | 9.40k | #define log_error_errno(error, ...) log_full_errno(LOG_ERR, error, __VA_ARGS__) |
233 | | #define log_emergency_errno(error, ...) log_full_errno(log_emergency_level(), error, __VA_ARGS__) |
234 | | |
235 | | /* This logs at the specified level the first time it is called, and then |
236 | | * logs at debug. If the specified level is debug, this logs only the first |
237 | | * time it is called. */ |
238 | | #define log_once(level, ...) \ |
239 | | ({ \ |
240 | | if (ONCE) \ |
241 | | log_full(level, __VA_ARGS__); \ |
242 | | else if (LOG_PRI(level) != LOG_DEBUG) \ |
243 | | log_debug(__VA_ARGS__); \ |
244 | | }) |
245 | | |
246 | | #define log_once_errno(level, error, ...) \ |
247 | | ({ \ |
248 | | int _err = (error); \ |
249 | | if (ONCE) \ |
250 | | _err = log_full_errno(level, _err, __VA_ARGS__); \ |
251 | | else if (LOG_PRI(level) != LOG_DEBUG) \ |
252 | | _err = log_debug_errno(_err, __VA_ARGS__); \ |
253 | | else \ |
254 | | _err = -ERRNO_VALUE(_err); \ |
255 | | _err; \ |
256 | | }) |
257 | | |
258 | | #if LOG_TRACE |
259 | | # define log_trace(...) log_debug(__VA_ARGS__) |
260 | | # define log_trace_errno(...) log_debug_errno(__VA_ARGS__) |
261 | | #else |
262 | | # define log_trace(...) do {} while (0) |
263 | | # define log_trace_errno(e, ...) (-ERRNO_VALUE(e)) |
264 | | #endif |
265 | | |
266 | | /* Structured logging */ |
267 | | #define log_struct_errno(level, error, ...) \ |
268 | | log_struct_internal(level, error, PROJECT_FILE, __LINE__, __func__, __VA_ARGS__, NULL) |
269 | | #define log_struct(level, ...) log_struct_errno(level, 0, __VA_ARGS__) |
270 | | |
271 | | #define log_struct_iovec_errno(level, error, iovec, n_iovec) \ |
272 | | log_struct_iovec_internal(level, error, PROJECT_FILE, __LINE__, __func__, iovec, n_iovec) |
273 | | #define log_struct_iovec(level, iovec, n_iovec) log_struct_iovec_errno(level, 0, iovec, n_iovec) |
274 | | |
275 | | /* This modifies the buffer passed! */ |
276 | | #define log_dump(level, buffer) \ |
277 | | log_dump_internal(level, 0, PROJECT_FILE, __LINE__, __func__, buffer) |
278 | | |
279 | 0 | #define log_oom_full(level) log_oom_internal(level, PROJECT_FILE, __LINE__, __func__) |
280 | 0 | #define log_oom() log_oom_full(LOG_ERR) |
281 | | #define log_oom_debug() log_oom_full(LOG_DEBUG) |
282 | | #define log_oom_warning() log_oom_full(LOG_WARNING) |
283 | | |
284 | | bool log_on_console(void) _pure_; |
285 | | |
286 | | /* Helper to wrap the main message in structured logging. The macro doesn't do much, |
287 | | * except to provide visual grouping of the format string and its arguments. */ |
288 | | #if LOG_MESSAGE_VERIFICATION || defined(__COVERITY__) |
289 | | /* Do a fake formatting of the message string to let the scanner verify the arguments against the format |
290 | | * message. The variable will never be set to true, but we don't tell the compiler that :) */ |
291 | | extern bool _log_message_dummy; |
292 | | # define LOG_ITEM(fmt, ...) "%.0d" fmt, (_log_message_dummy && printf(fmt, ##__VA_ARGS__)), ##__VA_ARGS__ |
293 | | # define LOG_MESSAGE(fmt, ...) LOG_ITEM("MESSAGE=" fmt, ##__VA_ARGS__) |
294 | | #else |
295 | | # define LOG_ITEM(fmt, ...) fmt, ##__VA_ARGS__ |
296 | | # define LOG_MESSAGE(fmt, ...) "MESSAGE=" fmt, ##__VA_ARGS__ |
297 | | #endif |
298 | | |
299 | | #define LOG_MESSAGE_ID(id) LOG_ITEM("MESSAGE_ID=" id) |
300 | | |
301 | | void log_received_signal(int level, const struct signalfd_siginfo *si); |
302 | | |
303 | | /* If turned on, any requests for a log target involving "syslog" will be implicitly upgraded to the equivalent journal target */ |
304 | | void log_set_upgrade_syslog_to_journal(bool b); |
305 | | |
306 | | /* If turned on, and log_open() is called, we'll not use STDERR_FILENO for logging ever, but rather open /dev/console */ |
307 | | void log_set_always_reopen_console(bool b); |
308 | | |
309 | | /* If turned on, we'll open the log stream implicitly if needed on each individual log call. This is normally not |
310 | | * desired as we want to reuse our logging streams. It is useful however */ |
311 | | void log_set_open_when_needed(bool b); |
312 | | |
313 | | /* If turned on, then we'll never use IPC-based logging, i.e. never log to syslog or the journal. We'll only log to |
314 | | * stderr, the console or kmsg */ |
315 | | void log_set_prohibit_ipc(bool b); |
316 | | |
317 | | int log_dup_console(void); |
318 | | |
319 | | int log_syntax_internal( |
320 | | const char *unit, |
321 | | int level, |
322 | | const char *config_file, |
323 | | unsigned config_line, |
324 | | int error, |
325 | | const char *file, |
326 | | int line, |
327 | | const char *func, |
328 | | const char *format, ...) _printf_(9, 10); |
329 | | |
330 | | int log_syntax_invalid_utf8_internal( |
331 | | const char *unit, |
332 | | int level, |
333 | | const char *config_file, |
334 | | unsigned config_line, |
335 | | const char *file, |
336 | | int line, |
337 | | const char *func, |
338 | | const char *rvalue); |
339 | | |
340 | | int log_syntax_parse_error_internal( |
341 | | const char *unit, |
342 | | const char *config_file, |
343 | | unsigned config_line, |
344 | | int error, |
345 | | bool critical, /* When true, propagate the passed error, otherwise this always returns 0. */ |
346 | | const char *file, |
347 | | int line, |
348 | | const char *func, |
349 | | const char *lvalue, |
350 | | const char *rvalue); |
351 | | |
352 | | #define log_syntax(unit, level, config_file, config_line, error, ...) \ |
353 | | ({ \ |
354 | | int _level = (level), _e = (error); \ |
355 | | (log_get_max_level() >= LOG_PRI(_level)) \ |
356 | | ? log_syntax_internal(unit, _level, config_file, config_line, _e, PROJECT_FILE, __LINE__, __func__, __VA_ARGS__) \ |
357 | | : -ERRNO_VALUE(_e); \ |
358 | | }) |
359 | | |
360 | | #define log_syntax_invalid_utf8(unit, level, config_file, config_line, rvalue) \ |
361 | | ({ \ |
362 | | int _level = (level); \ |
363 | | (log_get_max_level() >= LOG_PRI(_level)) \ |
364 | | ? log_syntax_invalid_utf8_internal(unit, _level, config_file, config_line, PROJECT_FILE, __LINE__, __func__, rvalue) \ |
365 | | : -EINVAL; \ |
366 | | }) |
367 | | |
368 | | #define log_syntax_parse_error_full(unit, config_file, config_line, error, critical, lvalue, rvalue) \ |
369 | | log_syntax_parse_error_internal(unit, config_file, config_line, error, critical, PROJECT_FILE, __LINE__, __func__, lvalue, rvalue) |
370 | | |
371 | | #define log_syntax_parse_error(unit, config_file, config_line, error, lvalue, rvalue) \ |
372 | | log_syntax_parse_error_full(unit, config_file, config_line, error, /* critical = */ false, lvalue, rvalue) |
373 | | |
374 | | #define DEBUG_LOGGING _unlikely_(log_get_max_level() >= LOG_DEBUG) |
375 | | |
376 | | void log_setup(void); |
377 | | |
378 | | const char* _log_set_prefix(const char *prefix, bool force); |
379 | 0 | static inline const char* _log_unset_prefixp(const char **p) { |
380 | 0 | assert(p); |
381 | 0 | _log_set_prefix(*p, true); |
382 | 0 | return NULL; |
383 | 0 | } Unexecuted instantiation: systemctl-compat-halt.c:_log_unset_prefixp Unexecuted instantiation: systemctl-compat-runlevel.c:_log_unset_prefixp Unexecuted instantiation: systemctl-compat-shutdown.c:_log_unset_prefixp Unexecuted instantiation: systemctl-compat-telinit.c:_log_unset_prefixp Unexecuted instantiation: systemctl-daemon-reload.c:_log_unset_prefixp Unexecuted instantiation: systemctl-logind.c:_log_unset_prefixp Unexecuted instantiation: systemctl-start-unit.c:_log_unset_prefixp Unexecuted instantiation: systemctl-sysv-compat.c:_log_unset_prefixp Unexecuted instantiation: systemctl-util.c:_log_unset_prefixp Unexecuted instantiation: systemctl.c:_log_unset_prefixp Unexecuted instantiation: fuzz-systemctl-parse-argv.c:_log_unset_prefixp |
384 | | |
385 | | #define LOG_SET_PREFIX(prefix) \ |
386 | | _cleanup_(_log_unset_prefixp) _unused_ const char *CONCATENATE(_cleanup_log_unset_prefix_, UNIQ) = _log_set_prefix(prefix, false); |