/src/frr/lib/zlog_targets.c
Line | Count | Source (jump to first uncovered line) |
1 | | // SPDX-License-Identifier: ISC |
2 | | /* |
3 | | * Copyright (c) 2015-19 David Lamparter, for NetDEF, Inc. |
4 | | */ |
5 | | |
6 | | #include "zebra.h" |
7 | | |
8 | | #include <sys/un.h> |
9 | | #include <syslog.h> |
10 | | |
11 | | #include "memory.h" |
12 | | #include "frrcu.h" |
13 | | #include "frr_pthread.h" |
14 | | #include "printfrr.h" |
15 | | #include "zlog.h" |
16 | | #include "zlog_targets.h" |
17 | | |
18 | | /* these allocations are intentionally left active even when doing full exit |
19 | | * cleanup, in order to keep the logging subsystem fully functional until the |
20 | | * absolute end. |
21 | | */ |
22 | | |
23 | | DEFINE_MGROUP_ACTIVEATEXIT(LOG, "logging subsystem"); |
24 | | |
25 | | DEFINE_MTYPE_STATIC(LOG, LOG_FD, "log file target"); |
26 | | DEFINE_MTYPE_STATIC(LOG, LOG_FD_NAME, "log file name"); |
27 | | DEFINE_MTYPE_STATIC(LOG, LOG_FD_ROTATE, "log file rotate helper"); |
28 | | DEFINE_MTYPE_STATIC(LOG, LOG_SYSL, "syslog target"); |
29 | | |
30 | | struct zlt_fd { |
31 | | struct zlog_target zt; |
32 | | |
33 | | atomic_uint_fast32_t fd; |
34 | | |
35 | | char ts_subsec; |
36 | | bool record_priority; |
37 | | |
38 | | struct rcu_head_close head_close; |
39 | | }; |
40 | | |
41 | | static const char * const prionames[] = { |
42 | | [LOG_EMERG] = "emergencies: ", |
43 | | [LOG_ALERT] = "alerts: ", |
44 | | [LOG_CRIT] = "critical: ", |
45 | | [LOG_ERR] = "errors: ", |
46 | | [LOG_WARNING] = "warnings: ", |
47 | | [LOG_NOTICE] = "notifications: ", |
48 | | [LOG_INFO] = "informational: ", |
49 | | [LOG_DEBUG] = "debugging: ", |
50 | | }; |
51 | | |
52 | | void zlog_fd(struct zlog_target *zt, struct zlog_msg *msgs[], size_t nmsgs) |
53 | 0 | { |
54 | 0 | struct zlt_fd *zte = container_of(zt, struct zlt_fd, zt); |
55 | 0 | int fd; |
56 | 0 | size_t i, textlen, iovpos = 0; |
57 | 0 | size_t niov = MIN(4 * nmsgs + 1, IOV_MAX); |
58 | 0 | struct iovec iov[niov]; |
59 | | /* "\nYYYY-MM-DD HH:MM:SS.NNNNNNNNN+ZZ:ZZ " = 37 chars */ |
60 | 0 | #define TS_LEN 40 |
61 | 0 | char ts_buf[TS_LEN * nmsgs], *ts_pos = ts_buf; |
62 | |
|
63 | 0 | fd = atomic_load_explicit(&zte->fd, memory_order_relaxed); |
64 | |
|
65 | 0 | for (i = 0; i < nmsgs; i++) { |
66 | 0 | struct zlog_msg *msg = msgs[i]; |
67 | 0 | int prio = zlog_msg_prio(msg); |
68 | |
|
69 | 0 | if (prio <= zt->prio_min) { |
70 | 0 | struct fbuf fbuf = { |
71 | 0 | .buf = ts_buf, |
72 | 0 | .pos = ts_pos, |
73 | 0 | .len = sizeof(ts_buf), |
74 | 0 | }; |
75 | |
|
76 | 0 | iov[iovpos].iov_base = ts_pos; |
77 | 0 | zlog_msg_ts(msg, &fbuf, |
78 | 0 | ZLOG_TS_LEGACY | zte->ts_subsec); |
79 | 0 | ts_pos = fbuf.pos; |
80 | |
|
81 | 0 | *ts_pos++ = ' '; |
82 | 0 | iov[iovpos].iov_len = |
83 | 0 | ts_pos - (char *)iov[iovpos].iov_base; |
84 | |
|
85 | 0 | iovpos++; |
86 | |
|
87 | 0 | if (zte->record_priority) { |
88 | 0 | iov[iovpos].iov_base = (char *)prionames[prio]; |
89 | 0 | iov[iovpos].iov_len = |
90 | 0 | strlen(iov[iovpos].iov_base); |
91 | |
|
92 | 0 | iovpos++; |
93 | 0 | } |
94 | |
|
95 | 0 | iov[iovpos].iov_base = zlog_prefix; |
96 | 0 | iov[iovpos].iov_len = zlog_prefixsz; |
97 | |
|
98 | 0 | iovpos++; |
99 | |
|
100 | 0 | iov[iovpos].iov_base = |
101 | 0 | (char *)zlog_msg_text(msg, &textlen); |
102 | 0 | iov[iovpos].iov_len = textlen + 1; |
103 | |
|
104 | 0 | iovpos++; |
105 | 0 | } |
106 | | |
107 | | /* conditions that trigger writing: |
108 | | * - out of space for more timestamps/headers |
109 | | * - this being the last message in the batch |
110 | | * - not enough remaining iov entries |
111 | | */ |
112 | 0 | if (iovpos > 0 && (ts_buf + sizeof(ts_buf) - ts_pos < TS_LEN |
113 | 0 | || i + 1 == nmsgs |
114 | 0 | || array_size(iov) - iovpos < 5)) { |
115 | 0 | writev(fd, iov, iovpos); |
116 | |
|
117 | 0 | iovpos = 0; |
118 | 0 | ts_pos = ts_buf; |
119 | 0 | } |
120 | 0 | } |
121 | |
|
122 | 0 | assert(iovpos == 0); |
123 | 0 | } |
124 | | |
125 | | static void zlog_fd_sigsafe(struct zlog_target *zt, const char *text, |
126 | | size_t len) |
127 | 0 | { |
128 | 0 | struct zlt_fd *zte = container_of(zt, struct zlt_fd, zt); |
129 | 0 | struct iovec iov[4]; |
130 | 0 | int fd; |
131 | |
|
132 | 0 | iov[0].iov_base = (char *)prionames[LOG_CRIT]; |
133 | 0 | iov[0].iov_len = zte->record_priority ? strlen(iov[0].iov_base) : 0; |
134 | |
|
135 | 0 | iov[1].iov_base = zlog_prefix; |
136 | 0 | iov[1].iov_len = zlog_prefixsz; |
137 | |
|
138 | 0 | iov[2].iov_base = (char *)text; |
139 | 0 | iov[2].iov_len = len; |
140 | |
|
141 | 0 | iov[3].iov_base = (char *)"\n"; |
142 | 0 | iov[3].iov_len = 1; |
143 | |
|
144 | 0 | fd = atomic_load_explicit(&zte->fd, memory_order_relaxed); |
145 | |
|
146 | 0 | writev(fd, iov, array_size(iov)); |
147 | 0 | } |
148 | | |
149 | | /* |
150 | | * (re-)configuration |
151 | | */ |
152 | | |
153 | | void zlog_file_init(struct zlog_cfg_file *zcf) |
154 | 2 | { |
155 | 2 | memset(zcf, 0, sizeof(*zcf)); |
156 | 2 | zcf->prio_min = ZLOG_DISABLED; |
157 | 2 | zcf->fd = -1; |
158 | 2 | pthread_mutex_init(&zcf->cfg_mtx, NULL); |
159 | 2 | } |
160 | | |
161 | | static void zlog_file_target_free(struct zlt_fd *zlt) |
162 | 2 | { |
163 | 2 | if (!zlt) |
164 | 2 | return; |
165 | | |
166 | 0 | rcu_close(&zlt->head_close, zlt->fd); |
167 | 0 | rcu_free(MTYPE_LOG_FD, zlt, zt.rcu_head); |
168 | 0 | } |
169 | | |
170 | | void zlog_file_fini(struct zlog_cfg_file *zcf) |
171 | 0 | { |
172 | 0 | if (zcf->active) { |
173 | 0 | struct zlt_fd *ztf; |
174 | 0 | struct zlog_target *zt; |
175 | |
|
176 | 0 | zt = zlog_target_replace(&zcf->active->zt, NULL); |
177 | 0 | ztf = container_of(zt, struct zlt_fd, zt); |
178 | 0 | zlog_file_target_free(ztf); |
179 | 0 | } |
180 | 0 | XFREE(MTYPE_LOG_FD_NAME, zcf->filename); |
181 | 0 | pthread_mutex_destroy(&zcf->cfg_mtx); |
182 | 0 | } |
183 | | |
184 | | static bool zlog_file_cycle(struct zlog_cfg_file *zcf) |
185 | 2 | { |
186 | 2 | struct zlog_target *zt, *old; |
187 | 2 | struct zlt_fd *zlt = NULL; |
188 | 2 | int fd; |
189 | 2 | bool rv = true; |
190 | | |
191 | 2 | do { |
192 | 2 | if (zcf->prio_min == ZLOG_DISABLED) |
193 | 2 | break; |
194 | | |
195 | 0 | if (zcf->fd != -1) |
196 | 0 | fd = dup(zcf->fd); |
197 | 0 | else if (zcf->filename) |
198 | 0 | fd = open(zcf->filename, |
199 | 0 | O_WRONLY | O_APPEND | O_CREAT | O_CLOEXEC |
200 | 0 | | O_NOCTTY, |
201 | 0 | LOGFILE_MASK); |
202 | 0 | else |
203 | 0 | fd = -1; |
204 | |
|
205 | 0 | if (fd < 0) { |
206 | 0 | rv = false; |
207 | 0 | break; |
208 | 0 | } |
209 | | |
210 | 0 | zt = zlog_target_clone(MTYPE_LOG_FD, &zcf->active->zt, |
211 | 0 | sizeof(*zlt)); |
212 | 0 | zlt = container_of(zt, struct zlt_fd, zt); |
213 | |
|
214 | 0 | zlt->fd = fd; |
215 | 0 | zlt->record_priority = zcf->record_priority; |
216 | 0 | zlt->ts_subsec = zcf->ts_subsec; |
217 | |
|
218 | 0 | zlt->zt.prio_min = zcf->prio_min; |
219 | 0 | zlt->zt.logfn = zcf->zlog_wrap ? zcf->zlog_wrap : zlog_fd; |
220 | 0 | zlt->zt.logfn_sigsafe = zlog_fd_sigsafe; |
221 | 0 | } while (0); |
222 | | |
223 | 2 | old = zlog_target_replace(zcf->active ? &zcf->active->zt : NULL, |
224 | 2 | zlt ? &zlt->zt : NULL); |
225 | 2 | zcf->active = zlt; |
226 | | |
227 | 2 | zlog_file_target_free(container_of_null(old, struct zlt_fd, zt)); |
228 | | |
229 | 2 | return rv; |
230 | 2 | } |
231 | | |
232 | | void zlog_file_set_other(struct zlog_cfg_file *zcf) |
233 | 0 | { |
234 | 0 | frr_with_mutex (&zcf->cfg_mtx) { |
235 | 0 | zlog_file_cycle(zcf); |
236 | 0 | } |
237 | 0 | } |
238 | | |
239 | | bool zlog_file_set_filename(struct zlog_cfg_file *zcf, const char *filename) |
240 | 0 | { |
241 | 0 | frr_with_mutex (&zcf->cfg_mtx) { |
242 | 0 | XFREE(MTYPE_LOG_FD_NAME, zcf->filename); |
243 | 0 | zcf->filename = XSTRDUP(MTYPE_LOG_FD_NAME, filename); |
244 | 0 | zcf->fd = -1; |
245 | |
|
246 | 0 | return zlog_file_cycle(zcf); |
247 | 0 | } |
248 | 0 | assert(0); |
249 | 0 | return false; |
250 | 0 | } |
251 | | |
252 | | bool zlog_file_set_fd(struct zlog_cfg_file *zcf, int fd) |
253 | 2 | { |
254 | 2 | frr_with_mutex (&zcf->cfg_mtx) { |
255 | 2 | if (zcf->fd == fd) |
256 | 0 | return true; |
257 | | |
258 | 2 | XFREE(MTYPE_LOG_FD_NAME, zcf->filename); |
259 | 2 | zcf->fd = fd; |
260 | | |
261 | 2 | return zlog_file_cycle(zcf); |
262 | 2 | } |
263 | 0 | assert(0); |
264 | 0 | return false; |
265 | 0 | } |
266 | | |
267 | | struct rcu_close_rotate { |
268 | | struct rcu_head_close head_close; |
269 | | struct rcu_head head_self; |
270 | | }; |
271 | | |
272 | | bool zlog_file_rotate(struct zlog_cfg_file *zcf) |
273 | 0 | { |
274 | 0 | struct rcu_close_rotate *rcr; |
275 | 0 | int fd; |
276 | |
|
277 | 0 | frr_with_mutex (&zcf->cfg_mtx) { |
278 | 0 | if (!zcf->active || !zcf->filename) |
279 | 0 | return true; |
280 | | |
281 | 0 | fd = open(zcf->filename, |
282 | 0 | O_WRONLY | O_APPEND | O_CREAT | O_CLOEXEC | O_NOCTTY, |
283 | 0 | LOGFILE_MASK); |
284 | 0 | if (fd < 0) |
285 | 0 | return false; |
286 | | |
287 | 0 | fd = atomic_exchange_explicit(&zcf->active->fd, |
288 | 0 | (uint_fast32_t)fd, |
289 | 0 | memory_order_relaxed); |
290 | 0 | } |
291 | | |
292 | 0 | rcr = XCALLOC(MTYPE_LOG_FD_ROTATE, sizeof(*rcr)); |
293 | 0 | rcu_close(&rcr->head_close, fd); |
294 | 0 | rcu_free(MTYPE_LOG_FD_ROTATE, rcr, head_self); |
295 | | |
296 | 0 | return true; |
297 | 0 | } |
298 | | |
299 | | /* fixed crash logging */ |
300 | | |
301 | | static struct zlt_fd zlog_crashlog; |
302 | | |
303 | | static void zlog_crashlog_sigsafe(struct zlog_target *zt, const char *text, |
304 | | size_t len) |
305 | 0 | { |
306 | 0 | static int crashlog_fd = -1; |
307 | |
|
308 | 0 | if (crashlog_fd == -1) { |
309 | 0 | #ifdef HAVE_OPENAT |
310 | 0 | crashlog_fd = openat(zlog_tmpdirfd, "crashlog", |
311 | 0 | O_WRONLY | O_APPEND | O_CREAT, |
312 | 0 | LOGFILE_MASK); |
313 | 0 | #endif |
314 | 0 | if (crashlog_fd < 0) |
315 | 0 | crashlog_fd = -2; |
316 | 0 | } |
317 | |
|
318 | 0 | if (crashlog_fd == -2) |
319 | 0 | return; |
320 | | |
321 | 0 | zlog_crashlog.fd = crashlog_fd; |
322 | 0 | zlog_fd_sigsafe(&zlog_crashlog.zt, text, len); |
323 | 0 | } |
324 | | |
325 | | /* this is used for assert failures (they don't need AS-Safe logging) */ |
326 | | static void zlog_crashlog_plain(struct zlog_target *zt, struct zlog_msg *msgs[], |
327 | | size_t nmsgs) |
328 | 0 | { |
329 | 0 | size_t i, len; |
330 | 0 | const char *text; |
331 | |
|
332 | 0 | for (i = 0; i < nmsgs; i++) { |
333 | 0 | if (zlog_msg_prio(msgs[i]) > zt->prio_min) |
334 | 0 | continue; |
335 | | |
336 | 0 | text = zlog_msg_text(msgs[i], &len); |
337 | 0 | zlog_crashlog_sigsafe(zt, text, len); |
338 | 0 | } |
339 | 0 | } |
340 | | |
341 | | static void zlog_crashlog_init(void) |
342 | 0 | { |
343 | 0 | zlog_crashlog.zt.prio_min = LOG_CRIT; |
344 | 0 | zlog_crashlog.zt.logfn = zlog_crashlog_plain; |
345 | 0 | zlog_crashlog.zt.logfn_sigsafe = zlog_crashlog_sigsafe; |
346 | 0 | zlog_crashlog.fd = -1; |
347 | |
|
348 | 0 | zlog_target_replace(NULL, &zlog_crashlog.zt); |
349 | 0 | } |
350 | | |
351 | | /* fixed logging for test/auxiliary programs */ |
352 | | |
353 | | static struct zlt_fd zlog_aux_stdout; |
354 | | static bool zlog_is_aux; |
355 | | |
356 | | static int zlt_aux_init(const char *prefix, int prio_min) |
357 | 0 | { |
358 | 0 | zlog_is_aux = true; |
359 | |
|
360 | 0 | zlog_aux_stdout.zt.prio_min = prio_min; |
361 | 0 | zlog_aux_stdout.zt.logfn = zlog_fd; |
362 | 0 | zlog_aux_stdout.zt.logfn_sigsafe = zlog_fd_sigsafe; |
363 | 0 | zlog_aux_stdout.fd = STDOUT_FILENO; |
364 | |
|
365 | 0 | zlog_target_replace(NULL, &zlog_aux_stdout.zt); |
366 | 0 | zlog_startup_end(); |
367 | 0 | return 0; |
368 | 0 | } |
369 | | |
370 | | static int zlt_init(const char *progname, const char *protoname, |
371 | | unsigned short instance, uid_t uid, gid_t gid) |
372 | 2 | { |
373 | 2 | openlog(progname, LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON); |
374 | 2 | return 0; |
375 | 2 | } |
376 | | |
377 | | static int zlt_fini(void) |
378 | 0 | { |
379 | 0 | closelog(); |
380 | 0 | return 0; |
381 | 0 | } |
382 | | |
383 | | /* fixed startup logging to stderr */ |
384 | | |
385 | | static struct zlt_fd zlog_startup_stderr; |
386 | | |
387 | | __attribute__((_CONSTRUCTOR(450))) static void zlog_startup_init(void) |
388 | 6 | { |
389 | 6 | zlog_startup_stderr.zt.prio_min = LOG_WARNING; |
390 | 6 | zlog_startup_stderr.zt.logfn = zlog_fd; |
391 | 6 | zlog_startup_stderr.zt.logfn_sigsafe = zlog_fd_sigsafe; |
392 | 6 | zlog_startup_stderr.fd = STDERR_FILENO; |
393 | | |
394 | 6 | zlog_target_replace(NULL, &zlog_startup_stderr.zt); |
395 | | |
396 | 6 | hook_register(zlog_aux_init, zlt_aux_init); |
397 | 6 | hook_register(zlog_init, zlt_init); |
398 | 6 | hook_register(zlog_fini, zlt_fini); |
399 | 6 | } |
400 | | |
401 | | void zlog_startup_end(void) |
402 | 0 | { |
403 | 0 | static bool startup_ended = false; |
404 | |
|
405 | 0 | if (startup_ended) |
406 | 0 | return; |
407 | 0 | startup_ended = true; |
408 | |
|
409 | 0 | zlog_target_replace(&zlog_startup_stderr.zt, NULL); |
410 | |
|
411 | 0 | if (zlog_is_aux) |
412 | 0 | return; |
413 | | |
414 | | /* until here, crashlogs go to stderr */ |
415 | 0 | zlog_crashlog_init(); |
416 | 0 | } |
417 | | |
418 | | /* syslog */ |
419 | | |
420 | | struct zlt_syslog { |
421 | | struct zlog_target zt; |
422 | | |
423 | | int syslog_facility; |
424 | | }; |
425 | | |
426 | | static void zlog_syslog(struct zlog_target *zt, struct zlog_msg *msgs[], |
427 | | size_t nmsgs) |
428 | 0 | { |
429 | 0 | size_t i; |
430 | 0 | struct zlt_syslog *zte = container_of(zt, struct zlt_syslog, zt); |
431 | 0 | const char *text; |
432 | 0 | size_t text_len; |
433 | |
|
434 | 0 | for (i = 0; i < nmsgs; i++) { |
435 | 0 | if (zlog_msg_prio(msgs[i]) > zt->prio_min) |
436 | 0 | continue; |
437 | | |
438 | 0 | text = zlog_msg_text(msgs[i], &text_len); |
439 | 0 | syslog(zlog_msg_prio(msgs[i]) | zte->syslog_facility, "%.*s", |
440 | 0 | (int)text_len, text); |
441 | 0 | } |
442 | 0 | } |
443 | | |
444 | | #ifndef _PATH_LOG |
445 | | #define _PATH_LOG "/dev/log" |
446 | | #endif |
447 | | |
448 | | static void zlog_syslog_sigsafe(struct zlog_target *zt, const char *text, |
449 | | size_t len) |
450 | 0 | { |
451 | 0 | static int syslog_fd = -1; |
452 | |
|
453 | 0 | char hdr[192]; |
454 | 0 | size_t hdrlen; |
455 | 0 | struct iovec iov[2]; |
456 | |
|
457 | 0 | if (syslog_fd == -1) { |
458 | 0 | syslog_fd = socket(AF_UNIX, SOCK_DGRAM, 0); |
459 | 0 | if (syslog_fd >= 0) { |
460 | 0 | struct sockaddr_un sa; |
461 | 0 | socklen_t salen = sizeof(sa); |
462 | |
|
463 | 0 | sa.sun_family = AF_UNIX; |
464 | 0 | strlcpy(sa.sun_path, _PATH_LOG, sizeof(sa.sun_path)); |
465 | | #ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN |
466 | | salen = sa.sun_len = SUN_LEN(&sa); |
467 | | #endif |
468 | 0 | if (connect(syslog_fd, (struct sockaddr *)&sa, salen)) { |
469 | 0 | close(syslog_fd); |
470 | 0 | syslog_fd = -1; |
471 | 0 | } |
472 | 0 | } |
473 | | |
474 | | /* /dev/log could be a fifo instead of a socket */ |
475 | 0 | if (syslog_fd == -1) { |
476 | 0 | syslog_fd = open(_PATH_LOG, O_WRONLY | O_NOCTTY); |
477 | 0 | if (syslog_fd < 0) |
478 | | /* give up ... */ |
479 | 0 | syslog_fd = -2; |
480 | 0 | } |
481 | 0 | } |
482 | |
|
483 | 0 | if (syslog_fd == -2) |
484 | 0 | return; |
485 | | |
486 | | /* note zlog_prefix includes trailing ": ", need to cut off 2 chars */ |
487 | 0 | hdrlen = snprintfrr(hdr, sizeof(hdr), "<%d>%.*s[%ld]: ", LOG_CRIT, |
488 | 0 | zlog_prefixsz > 2 ? (int)(zlog_prefixsz - 2) : 0, |
489 | 0 | zlog_prefix, (long)getpid()); |
490 | |
|
491 | 0 | iov[0].iov_base = hdr; |
492 | 0 | iov[0].iov_len = hdrlen; |
493 | |
|
494 | 0 | iov[1].iov_base = (char *)text; |
495 | 0 | iov[1].iov_len = len; |
496 | |
|
497 | 0 | writev(syslog_fd, iov, array_size(iov)); |
498 | 0 | } |
499 | | |
500 | | |
501 | | static pthread_mutex_t syslog_cfg_mutex = PTHREAD_MUTEX_INITIALIZER; |
502 | | static struct zlt_syslog *zlt_syslog; |
503 | | static int syslog_facility = LOG_DAEMON; |
504 | | static int syslog_prio_min = ZLOG_DISABLED; |
505 | | |
506 | | void zlog_syslog_set_facility(int facility) |
507 | 0 | { |
508 | 0 | struct zlog_target *newztc; |
509 | 0 | struct zlt_syslog *newzt; |
510 | |
|
511 | 0 | frr_with_mutex (&syslog_cfg_mutex) { |
512 | 0 | if (facility == syslog_facility) |
513 | 0 | return; |
514 | 0 | syslog_facility = facility; |
515 | |
|
516 | 0 | if (syslog_prio_min == ZLOG_DISABLED) |
517 | 0 | return; |
518 | | |
519 | 0 | newztc = zlog_target_clone(MTYPE_LOG_SYSL, &zlt_syslog->zt, |
520 | 0 | sizeof(*newzt)); |
521 | 0 | newzt = container_of(newztc, struct zlt_syslog, zt); |
522 | 0 | newzt->syslog_facility = syslog_facility; |
523 | |
|
524 | 0 | zlog_target_free(MTYPE_LOG_SYSL, |
525 | 0 | zlog_target_replace(&zlt_syslog->zt, |
526 | 0 | &newzt->zt)); |
527 | | |
528 | 0 | zlt_syslog = newzt; |
529 | 0 | } |
530 | 0 | } |
531 | | |
532 | | int zlog_syslog_get_facility(void) |
533 | 0 | { |
534 | 0 | frr_with_mutex (&syslog_cfg_mutex) { |
535 | 0 | return syslog_facility; |
536 | 0 | } |
537 | 0 | assert(0); |
538 | 0 | return 0; |
539 | 0 | } |
540 | | |
541 | | void zlog_syslog_set_prio_min(int prio_min) |
542 | 0 | { |
543 | 0 | struct zlog_target *newztc; |
544 | 0 | struct zlt_syslog *newzt = NULL; |
545 | |
|
546 | 0 | frr_with_mutex (&syslog_cfg_mutex) { |
547 | 0 | if (prio_min == syslog_prio_min) |
548 | 0 | return; |
549 | 0 | syslog_prio_min = prio_min; |
550 | |
|
551 | 0 | if (syslog_prio_min != ZLOG_DISABLED) { |
552 | 0 | newztc = zlog_target_clone(MTYPE_LOG_SYSL, |
553 | 0 | &zlt_syslog->zt, |
554 | 0 | sizeof(*newzt)); |
555 | 0 | newzt = container_of(newztc, struct zlt_syslog, zt); |
556 | 0 | newzt->zt.prio_min = prio_min; |
557 | 0 | newzt->zt.logfn = zlog_syslog; |
558 | 0 | newzt->zt.logfn_sigsafe = zlog_syslog_sigsafe; |
559 | 0 | newzt->syslog_facility = syslog_facility; |
560 | 0 | } |
561 | |
|
562 | 0 | zlog_target_free(MTYPE_LOG_SYSL, |
563 | 0 | zlog_target_replace(&zlt_syslog->zt, |
564 | 0 | &newzt->zt)); |
565 | | |
566 | 0 | zlt_syslog = newzt; |
567 | 0 | } |
568 | 0 | } |
569 | | |
570 | | int zlog_syslog_get_prio_min(void) |
571 | 0 | { |
572 | 0 | frr_with_mutex (&syslog_cfg_mutex) { |
573 | 0 | return syslog_prio_min; |
574 | 0 | } |
575 | 0 | assert(0); |
576 | 0 | return 0; |
577 | 0 | } |