]> git.proxmox.com Git - mirror_frr.git/blob - lib/zlog.c
Merge pull request #8505 from mobash-rasool/ospfv3-max-path
[mirror_frr.git] / lib / zlog.c
1 /*
2 * Copyright (c) 2015-19 David Lamparter, for NetDEF, Inc.
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include "zebra.h"
18
19 #include <unistd.h>
20 #include <sys/time.h>
21 #include <sys/mman.h>
22 #include <sys/types.h>
23 #include <time.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <stdarg.h>
28 #include <pthread.h>
29
30 /* gettid() & co. */
31 #ifdef HAVE_PTHREAD_NP_H
32 #include <pthread_np.h>
33 #endif
34 #ifdef linux
35 #include <sys/syscall.h>
36 #endif
37 #ifdef __FreeBSD__
38 #include <sys/thr.h>
39 #endif
40 #ifdef __NetBSD__
41 #include <lwp.h>
42 #endif
43 #ifdef __DragonFly__
44 #include <sys/lwp.h>
45 #endif
46 #ifdef __APPLE__
47 #include <mach/mach_traps.h>
48 #endif
49
50 #include "memory.h"
51 #include "atomlist.h"
52 #include "printfrr.h"
53 #include "frrcu.h"
54 #include "zlog.h"
55 #include "libfrr_trace.h"
56
57 DEFINE_MTYPE_STATIC(LIB, LOG_MESSAGE, "log message");
58 DEFINE_MTYPE_STATIC(LIB, LOG_TLSBUF, "log thread-local buffer");
59
60 DEFINE_HOOK(zlog_init, (const char *progname, const char *protoname,
61 unsigned short instance, uid_t uid, gid_t gid),
62 (progname, protoname, instance, uid, gid));
63 DEFINE_KOOH(zlog_fini, (), ());
64 DEFINE_HOOK(zlog_aux_init, (const char *prefix, int prio_min),
65 (prefix, prio_min));
66
67 char zlog_prefix[128];
68 size_t zlog_prefixsz;
69 int zlog_tmpdirfd = -1;
70
71 static atomic_bool zlog_ec = true, zlog_xid = true;
72
73 /* these are kept around because logging is initialized (and directories
74 * & files created) before zprivs code switches to the FRR user; therefore
75 * we need to chown() things so we don't get permission errors later when
76 * trying to delete things on shutdown
77 */
78 static uid_t zlog_uid = -1;
79 static gid_t zlog_gid = -1;
80
81 DECLARE_ATOMLIST(zlog_targets, struct zlog_target, head);
82 static struct zlog_targets_head zlog_targets;
83
84 /* cf. zlog.h for additional comments on this struct.
85 *
86 * Note: you MUST NOT pass the format string + va_list to non-FRR format
87 * string functions (e.g. vsyslog, sd_journal_printv, ...) since FRR uses an
88 * extended prinf() with additional formats (%pI4 and the like).
89 *
90 * Also remember to use va_copy() on args.
91 */
92
93 struct zlog_msg {
94 struct timespec ts;
95 int prio;
96
97 const char *fmt;
98 va_list args;
99 const struct xref_logmsg *xref;
100
101 char *stackbuf;
102 size_t stackbufsz;
103 char *text;
104 size_t textlen;
105
106 /* This is always ISO8601 with sub-second precision 9 here, it's
107 * converted for callers as needed. ts_dot points to the "."
108 * separating sub-seconds. ts_zonetail is "Z" or "+00:00" for the
109 * local time offset.
110 *
111 * Valid if ZLOG_TS_ISO8601 is set.
112 * (0 if timestamp has not been formatted yet)
113 */
114 uint32_t ts_flags;
115 char ts_str[32], *ts_dot, ts_zonetail[8];
116 };
117
118 /* thread-local log message buffering
119 *
120 * This is strictly optional and set up by calling zlog_tls_buffer_init()
121 * on a particular thread.
122 *
123 * If in use, this will create a temporary file in /var/tmp which is used as
124 * memory-mapped MAP_SHARED log message buffer. The idea there is that buffer
125 * access doesn't require any syscalls, but in case of a crash the kernel
126 * knows to sync the memory back to disk. This way the user can still get the
127 * last log messages if there were any left unwritten in the buffer.
128 *
129 * Sizing this dynamically isn't particularly useful, so here's an 8k buffer
130 * with a message limit of 64 messages. Message metadata (e.g. priority,
131 * timestamp) aren't in the mmap region, so they're lost on crash, but we can
132 * live with that.
133 */
134
135 #if defined(HAVE_OPENAT) && defined(HAVE_UNLINKAT)
136 #define CAN_DO_TLS 1
137 #endif
138
139 #define TLS_LOG_BUF_SIZE 8192
140 #define TLS_LOG_MAXMSG 64
141
142 struct zlog_tls {
143 char *mmbuf;
144 size_t bufpos;
145 bool do_unlink;
146
147 size_t nmsgs;
148 struct zlog_msg msgs[TLS_LOG_MAXMSG];
149 struct zlog_msg *msgp[TLS_LOG_MAXMSG];
150 };
151
152 static inline void zlog_tls_free(void *arg);
153
154 /* proper ELF TLS is a bit faster than pthread_[gs]etspecific, so if it's
155 * available we'll use it here
156 */
157
158 #ifdef __OpenBSD__
159 static pthread_key_t zlog_tls_key;
160
161 static void zlog_tls_key_init(void) __attribute__((_CONSTRUCTOR(500)));
162 static void zlog_tls_key_init(void)
163 {
164 pthread_key_create(&zlog_tls_key, zlog_tls_free);
165 }
166
167 static void zlog_tls_key_fini(void) __attribute__((_DESTRUCTOR(500)));
168 static void zlog_tls_key_fini(void)
169 {
170 pthread_key_delete(zlog_tls_key);
171 }
172
173 static inline struct zlog_tls *zlog_tls_get(void)
174 {
175 return pthread_getspecific(zlog_tls_key);
176 }
177
178 static inline void zlog_tls_set(struct zlog_tls *val)
179 {
180 pthread_setspecific(zlog_tls_key, val);
181 }
182 #else
183 # ifndef thread_local
184 # define thread_local __thread
185 # endif
186
187 static thread_local struct zlog_tls *zlog_tls_var
188 __attribute__((tls_model("initial-exec")));
189
190 static inline struct zlog_tls *zlog_tls_get(void)
191 {
192 return zlog_tls_var;
193 }
194
195 static inline void zlog_tls_set(struct zlog_tls *val)
196 {
197 zlog_tls_var = val;
198 }
199 #endif
200
201 #ifdef CAN_DO_TLS
202 static long zlog_gettid(void)
203 {
204 long rv = -1;
205 #ifdef HAVE_PTHREAD_GETTHREADID_NP
206 rv = pthread_getthreadid_np();
207 #elif defined(linux)
208 rv = syscall(__NR_gettid);
209 #elif defined(__NetBSD__)
210 rv = _lwp_self();
211 #elif defined(__FreeBSD__)
212 thr_self(&rv);
213 #elif defined(__DragonFly__)
214 rv = lwp_gettid();
215 #elif defined(__OpenBSD__)
216 rv = getthrid();
217 #elif defined(__sun)
218 rv = pthread_self();
219 #elif defined(__APPLE__)
220 rv = mach_thread_self();
221 mach_port_deallocate(mach_task_self(), rv);
222 #endif
223 return rv;
224 }
225
226 void zlog_tls_buffer_init(void)
227 {
228 struct zlog_tls *zlog_tls;
229 char mmpath[MAXPATHLEN];
230 int mmfd;
231 size_t i;
232
233 zlog_tls = zlog_tls_get();
234
235 if (zlog_tls || zlog_tmpdirfd < 0)
236 return;
237
238 zlog_tls = XCALLOC(MTYPE_LOG_TLSBUF, sizeof(*zlog_tls));
239 for (i = 0; i < array_size(zlog_tls->msgp); i++)
240 zlog_tls->msgp[i] = &zlog_tls->msgs[i];
241
242 snprintfrr(mmpath, sizeof(mmpath), "logbuf.%ld", zlog_gettid());
243
244 mmfd = openat(zlog_tmpdirfd, mmpath,
245 O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, 0600);
246 if (mmfd < 0) {
247 zlog_err("failed to open thread log buffer \"%s\": %s",
248 mmpath, strerror(errno));
249 goto out_anon;
250 }
251 fchown(mmfd, zlog_uid, zlog_gid);
252
253 #ifdef HAVE_POSIX_FALLOCATE
254 if (posix_fallocate(mmfd, 0, TLS_LOG_BUF_SIZE) != 0)
255 /* note next statement is under above if() */
256 #endif
257 if (ftruncate(mmfd, TLS_LOG_BUF_SIZE) < 0) {
258 zlog_err("failed to allocate thread log buffer \"%s\": %s",
259 mmpath, strerror(errno));
260 goto out_anon_unlink;
261 }
262
263 zlog_tls->mmbuf = mmap(NULL, TLS_LOG_BUF_SIZE, PROT_READ | PROT_WRITE,
264 MAP_SHARED, mmfd, 0);
265 if (zlog_tls->mmbuf == MAP_FAILED) {
266 zlog_err("failed to mmap thread log buffer \"%s\": %s",
267 mmpath, strerror(errno));
268 goto out_anon_unlink;
269 }
270 zlog_tls->do_unlink = true;
271
272 close(mmfd);
273 zlog_tls_set(zlog_tls);
274 return;
275
276 out_anon_unlink:
277 unlinkat(zlog_tmpdirfd, mmpath, 0);
278 close(mmfd);
279 out_anon:
280
281 #ifndef MAP_ANONYMOUS
282 #define MAP_ANONYMOUS MAP_ANON
283 #endif
284 zlog_tls->mmbuf = mmap(NULL, TLS_LOG_BUF_SIZE, PROT_READ | PROT_WRITE,
285 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
286
287 if (!zlog_tls->mmbuf) {
288 zlog_err("failed to anonymous-mmap thread log buffer: %s",
289 strerror(errno));
290 XFREE(MTYPE_LOG_TLSBUF, zlog_tls);
291 zlog_tls_set(NULL);
292 return;
293 }
294
295 zlog_tls_set(zlog_tls);
296 }
297
298 void zlog_tls_buffer_fini(void)
299 {
300 char mmpath[MAXPATHLEN];
301 struct zlog_tls *zlog_tls = zlog_tls_get();
302 bool do_unlink = zlog_tls ? zlog_tls->do_unlink : false;
303
304 zlog_tls_buffer_flush();
305
306 zlog_tls_free(zlog_tls);
307 zlog_tls_set(NULL);
308
309 snprintfrr(mmpath, sizeof(mmpath), "logbuf.%ld", zlog_gettid());
310 if (do_unlink && unlinkat(zlog_tmpdirfd, mmpath, 0))
311 zlog_err("unlink logbuf: %s (%d)", strerror(errno), errno);
312 }
313
314 #else /* !CAN_DO_TLS */
315 void zlog_tls_buffer_init(void)
316 {
317 }
318
319 void zlog_tls_buffer_fini(void)
320 {
321 }
322 #endif
323
324 static inline void zlog_tls_free(void *arg)
325 {
326 struct zlog_tls *zlog_tls = arg;
327
328 if (!zlog_tls)
329 return;
330
331 munmap(zlog_tls->mmbuf, TLS_LOG_BUF_SIZE);
332 XFREE(MTYPE_LOG_TLSBUF, zlog_tls);
333 }
334
335 void zlog_tls_buffer_flush(void)
336 {
337 struct zlog_target *zt;
338 struct zlog_tls *zlog_tls = zlog_tls_get();
339
340 if (!zlog_tls)
341 return;
342 if (!zlog_tls->nmsgs)
343 return;
344
345 rcu_read_lock();
346 frr_each (zlog_targets, &zlog_targets, zt) {
347 if (!zt->logfn)
348 continue;
349
350 zt->logfn(zt, zlog_tls->msgp, zlog_tls->nmsgs);
351 }
352 rcu_read_unlock();
353
354 zlog_tls->bufpos = 0;
355 zlog_tls->nmsgs = 0;
356 }
357
358
359 static void vzlog_notls(const struct xref_logmsg *xref, int prio,
360 const char *fmt, va_list ap)
361 {
362 struct zlog_target *zt;
363 struct zlog_msg stackmsg = {
364 .prio = prio & LOG_PRIMASK,
365 .fmt = fmt,
366 .xref = xref,
367 }, *msg = &stackmsg;
368 char stackbuf[512];
369
370 clock_gettime(CLOCK_REALTIME, &msg->ts);
371 va_copy(msg->args, ap);
372 msg->stackbuf = stackbuf;
373 msg->stackbufsz = sizeof(stackbuf);
374
375 rcu_read_lock();
376 frr_each (zlog_targets, &zlog_targets, zt) {
377 if (prio > zt->prio_min)
378 continue;
379 if (!zt->logfn)
380 continue;
381
382 zt->logfn(zt, &msg, 1);
383 }
384 rcu_read_unlock();
385
386 va_end(msg->args);
387 if (msg->text && msg->text != stackbuf)
388 XFREE(MTYPE_LOG_MESSAGE, msg->text);
389 }
390
391 static void vzlog_tls(struct zlog_tls *zlog_tls, const struct xref_logmsg *xref,
392 int prio, const char *fmt, va_list ap)
393 {
394 struct zlog_target *zt;
395 struct zlog_msg *msg;
396 char *buf;
397 bool ignoremsg = true;
398 bool immediate = false;
399
400 /* avoid further processing cost if no target wants this message */
401 rcu_read_lock();
402 frr_each (zlog_targets, &zlog_targets, zt) {
403 if (prio > zt->prio_min)
404 continue;
405 ignoremsg = false;
406 break;
407 }
408 rcu_read_unlock();
409
410 if (ignoremsg)
411 return;
412
413 msg = &zlog_tls->msgs[zlog_tls->nmsgs];
414 zlog_tls->nmsgs++;
415 if (zlog_tls->nmsgs == array_size(zlog_tls->msgs))
416 immediate = true;
417
418 memset(msg, 0, sizeof(*msg));
419 clock_gettime(CLOCK_REALTIME, &msg->ts);
420 va_copy(msg->args, ap);
421 msg->stackbuf = buf = zlog_tls->mmbuf + zlog_tls->bufpos;
422 msg->stackbufsz = TLS_LOG_BUF_SIZE - zlog_tls->bufpos - 1;
423 msg->fmt = fmt;
424 msg->prio = prio & LOG_PRIMASK;
425 msg->xref = xref;
426 if (msg->prio < LOG_INFO)
427 immediate = true;
428
429 if (!immediate) {
430 /* messages written later need to take the formatting cost
431 * immediately since we can't hold a reference on varargs
432 */
433 zlog_msg_text(msg, NULL);
434
435 if (msg->text != buf)
436 /* zlog_msg_text called malloc() on us :( */
437 immediate = true;
438 else {
439 zlog_tls->bufpos += msg->textlen + 1;
440 /* write a second \0 to mark current end position
441 * (in case of crash this signals end of unwritten log
442 * messages in mmap'd logbuf file)
443 */
444 zlog_tls->mmbuf[zlog_tls->bufpos] = '\0';
445
446 /* avoid malloc() for next message */
447 if (TLS_LOG_BUF_SIZE - zlog_tls->bufpos < 256)
448 immediate = true;
449 }
450 }
451
452 if (immediate)
453 zlog_tls_buffer_flush();
454
455 va_end(msg->args);
456 if (msg->text && msg->text != buf)
457 XFREE(MTYPE_LOG_MESSAGE, msg->text);
458 }
459
460 void vzlogx(const struct xref_logmsg *xref, int prio,
461 const char *fmt, va_list ap)
462 {
463 struct zlog_tls *zlog_tls = zlog_tls_get();
464
465 #ifdef HAVE_LTTNG
466 va_list copy;
467 va_copy(copy, ap);
468 char *msg = vasprintfrr(MTYPE_LOG_MESSAGE, fmt, copy);
469
470 switch (prio) {
471 case LOG_ERR:
472 frrtracelog(TRACE_ERR, msg);
473 break;
474 case LOG_WARNING:
475 frrtracelog(TRACE_WARNING, msg);
476 break;
477 case LOG_DEBUG:
478 frrtracelog(TRACE_DEBUG, msg);
479 break;
480 case LOG_NOTICE:
481 frrtracelog(TRACE_DEBUG, msg);
482 break;
483 case LOG_INFO:
484 default:
485 frrtracelog(TRACE_INFO, msg);
486 break;
487 }
488
489 va_end(copy);
490 XFREE(MTYPE_LOG_MESSAGE, msg);
491 #endif
492
493 if (zlog_tls)
494 vzlog_tls(zlog_tls, xref, prio, fmt, ap);
495 else
496 vzlog_notls(xref, prio, fmt, ap);
497 }
498
499 void zlog_sigsafe(const char *text, size_t len)
500 {
501 struct zlog_target *zt;
502 const char *end = text + len, *nlpos;
503
504 while (text < end) {
505 nlpos = memchr(text, '\n', end - text);
506 if (!nlpos)
507 nlpos = end;
508
509 frr_each (zlog_targets, &zlog_targets, zt) {
510 if (LOG_CRIT > zt->prio_min)
511 continue;
512 if (!zt->logfn_sigsafe)
513 continue;
514
515 zt->logfn_sigsafe(zt, text, nlpos - text);
516 }
517
518 if (nlpos == end)
519 break;
520 text = nlpos + 1;
521 }
522 }
523
524
525 int zlog_msg_prio(struct zlog_msg *msg)
526 {
527 return msg->prio;
528 }
529
530 const struct xref_logmsg *zlog_msg_xref(struct zlog_msg *msg)
531 {
532 return msg->xref;
533 }
534
535 const char *zlog_msg_text(struct zlog_msg *msg, size_t *textlen)
536 {
537 if (!msg->text) {
538 va_list args;
539 bool do_xid, do_ec;
540 size_t need = 0, hdrlen;
541 struct fbuf fb = {
542 .buf = msg->stackbuf,
543 .pos = msg->stackbuf,
544 .len = msg->stackbufsz,
545 };
546
547 do_ec = atomic_load_explicit(&zlog_ec, memory_order_relaxed);
548 do_xid = atomic_load_explicit(&zlog_xid, memory_order_relaxed);
549
550 if (msg->xref && do_xid && msg->xref->xref.xrefdata->uid[0]) {
551 need += bputch(&fb, '[');
552 need += bputs(&fb, msg->xref->xref.xrefdata->uid);
553 need += bputch(&fb, ']');
554 }
555 if (msg->xref && do_ec && msg->xref->ec)
556 need += bprintfrr(&fb, "[EC %u]", msg->xref->ec);
557 if (need)
558 need += bputch(&fb, ' ');
559
560 hdrlen = need;
561 assert(hdrlen < msg->stackbufsz);
562
563 va_copy(args, msg->args);
564 need += vbprintfrr(&fb, msg->fmt, args);
565 va_end(args);
566
567 msg->textlen = need;
568 need += bputch(&fb, '\0');
569
570 if (need <= msg->stackbufsz)
571 msg->text = msg->stackbuf;
572 else {
573 msg->text = XMALLOC(MTYPE_LOG_MESSAGE, need);
574
575 memcpy(msg->text, msg->stackbuf, hdrlen);
576
577 fb.buf = msg->text;
578 fb.len = need;
579 fb.pos = msg->text + hdrlen;
580
581 va_copy(args, msg->args);
582 vbprintfrr(&fb, msg->fmt, args);
583 va_end(args);
584
585 bputch(&fb, '\0');
586 }
587 }
588 if (textlen)
589 *textlen = msg->textlen;
590 return msg->text;
591 }
592
593 #define ZLOG_TS_FORMAT (ZLOG_TS_ISO8601 | ZLOG_TS_LEGACY)
594 #define ZLOG_TS_FLAGS ~ZLOG_TS_PREC
595
596 size_t zlog_msg_ts(struct zlog_msg *msg, char *out, size_t outsz,
597 uint32_t flags)
598 {
599 size_t len1;
600
601 if (!(flags & ZLOG_TS_FORMAT))
602 return 0;
603
604 if (!(msg->ts_flags & ZLOG_TS_FORMAT) ||
605 ((msg->ts_flags ^ flags) & ZLOG_TS_UTC)) {
606 struct tm tm;
607
608 if (flags & ZLOG_TS_UTC)
609 gmtime_r(&msg->ts.tv_sec, &tm);
610 else
611 localtime_r(&msg->ts.tv_sec, &tm);
612
613 strftime(msg->ts_str, sizeof(msg->ts_str),
614 "%Y-%m-%dT%H:%M:%S", &tm);
615
616 if (flags & ZLOG_TS_UTC) {
617 msg->ts_zonetail[0] = 'Z';
618 msg->ts_zonetail[1] = '\0';
619 } else
620 snprintfrr(msg->ts_zonetail, sizeof(msg->ts_zonetail),
621 "%+03d:%02d",
622 (int)(tm.tm_gmtoff / 3600),
623 (int)(labs(tm.tm_gmtoff) / 60) % 60);
624
625 msg->ts_dot = msg->ts_str + strlen(msg->ts_str);
626 snprintfrr(msg->ts_dot,
627 msg->ts_str + sizeof(msg->ts_str) - msg->ts_dot,
628 ".%09lu", (unsigned long)msg->ts.tv_nsec);
629
630 msg->ts_flags = ZLOG_TS_ISO8601 | (flags & ZLOG_TS_UTC);
631 }
632
633 len1 = flags & ZLOG_TS_PREC;
634 len1 = (msg->ts_dot - msg->ts_str) + (len1 ? len1 + 1 : 0);
635
636 if (len1 > strlen(msg->ts_str))
637 len1 = strlen(msg->ts_str);
638
639 if (flags & ZLOG_TS_LEGACY) {
640 if (len1 + 1 > outsz)
641 return 0;
642
643 /* just swap out the formatting, faster than redoing it */
644 for (char *p = msg->ts_str; p < msg->ts_str + len1; p++) {
645 switch (*p) {
646 case '-':
647 *out++ = '/';
648 break;
649 case 'T':
650 *out++ = ' ';
651 break;
652 default:
653 *out++ = *p;
654 }
655 }
656 *out = '\0';
657 return len1;
658 } else {
659 size_t len2 = strlen(msg->ts_zonetail);
660
661 if (len1 + len2 + 1 > outsz)
662 return 0;
663 memcpy(out, msg->ts_str, len1);
664 memcpy(out + len1, msg->ts_zonetail, len2);
665 out[len1 + len2] = '\0';
666 return len1 + len2;
667 }
668 }
669
670 void zlog_set_prefix_ec(bool enable)
671 {
672 atomic_store_explicit(&zlog_ec, enable, memory_order_relaxed);
673 }
674
675 bool zlog_get_prefix_ec(void)
676 {
677 return atomic_load_explicit(&zlog_ec, memory_order_relaxed);
678 }
679
680 void zlog_set_prefix_xid(bool enable)
681 {
682 atomic_store_explicit(&zlog_xid, enable, memory_order_relaxed);
683 }
684
685 bool zlog_get_prefix_xid(void)
686 {
687 return atomic_load_explicit(&zlog_xid, memory_order_relaxed);
688 }
689
690 /* setup functions */
691
692 struct zlog_target *zlog_target_clone(struct memtype *mt,
693 struct zlog_target *oldzt, size_t size)
694 {
695 struct zlog_target *newzt;
696
697 newzt = XCALLOC(mt, size);
698 if (oldzt) {
699 newzt->prio_min = oldzt->prio_min;
700 newzt->logfn = oldzt->logfn;
701 newzt->logfn_sigsafe = oldzt->logfn_sigsafe;
702 }
703
704 return newzt;
705 }
706
707 struct zlog_target *zlog_target_replace(struct zlog_target *oldzt,
708 struct zlog_target *newzt)
709 {
710 if (newzt)
711 zlog_targets_add_tail(&zlog_targets, newzt);
712 if (oldzt)
713 zlog_targets_del(&zlog_targets, oldzt);
714 return oldzt;
715 }
716
717
718 /* common init */
719
720 #define TMPBASEDIR "/var/tmp/frr"
721
722 static char zlog_tmpdir[MAXPATHLEN];
723
724 void zlog_aux_init(const char *prefix, int prio_min)
725 {
726 if (prefix)
727 strlcpy(zlog_prefix, prefix, sizeof(zlog_prefix));
728
729 hook_call(zlog_aux_init, prefix, prio_min);
730 }
731
732 void zlog_init(const char *progname, const char *protoname,
733 unsigned short instance, uid_t uid, gid_t gid)
734 {
735 zlog_uid = uid;
736 zlog_gid = gid;
737
738 if (instance) {
739 snprintfrr(zlog_tmpdir, sizeof(zlog_tmpdir),
740 "/var/tmp/frr/%s-%d.%ld",
741 progname, instance, (long)getpid());
742
743 zlog_prefixsz = snprintfrr(zlog_prefix, sizeof(zlog_prefix),
744 "%s[%d]: ", protoname, instance);
745 } else {
746 snprintfrr(zlog_tmpdir, sizeof(zlog_tmpdir),
747 "/var/tmp/frr/%s.%ld",
748 progname, (long)getpid());
749
750 zlog_prefixsz = snprintfrr(zlog_prefix, sizeof(zlog_prefix),
751 "%s: ", protoname);
752 }
753
754 if (mkdir(TMPBASEDIR, 0700) != 0) {
755 if (errno != EEXIST) {
756 zlog_err("failed to mkdir \"%s\": %s",
757 TMPBASEDIR, strerror(errno));
758 goto out_warn;
759 }
760 }
761 chown(TMPBASEDIR, zlog_uid, zlog_gid);
762
763 if (mkdir(zlog_tmpdir, 0700) != 0) {
764 zlog_err("failed to mkdir \"%s\": %s",
765 zlog_tmpdir, strerror(errno));
766 goto out_warn;
767 }
768
769 #ifdef O_PATH
770 zlog_tmpdirfd = open(zlog_tmpdir,
771 O_PATH | O_RDONLY | O_CLOEXEC);
772 #else
773 zlog_tmpdirfd = open(zlog_tmpdir,
774 O_DIRECTORY | O_RDONLY | O_CLOEXEC);
775 #endif
776 if (zlog_tmpdirfd < 0) {
777 zlog_err("failed to open \"%s\": %s",
778 zlog_tmpdir, strerror(errno));
779 goto out_warn;
780 }
781
782 #ifdef AT_EMPTY_PATH
783 fchownat(zlog_tmpdirfd, "", zlog_uid, zlog_gid, AT_EMPTY_PATH);
784 #else
785 chown(zlog_tmpdir, zlog_uid, zlog_gid);
786 #endif
787
788 hook_call(zlog_init, progname, protoname, instance, uid, gid);
789 return;
790
791 out_warn:
792 zlog_err("crashlog and per-thread log buffering unavailable!");
793 hook_call(zlog_init, progname, protoname, instance, uid, gid);
794 }
795
796 void zlog_fini(void)
797 {
798 hook_call(zlog_fini);
799
800 if (zlog_tmpdirfd >= 0) {
801 close(zlog_tmpdirfd);
802 zlog_tmpdirfd = -1;
803
804 if (rmdir(zlog_tmpdir))
805 zlog_err("failed to rmdir \"%s\": %s",
806 zlog_tmpdir, strerror(errno));
807 }
808 }