back to topotato report
topotato coverage report
Current view: top level - lib - zlog_5424.c (source / functions) Hit Total Coverage
Test: test_rip.py::RIPBasic Lines: 2 518 0.4 %
Date: 2023-02-24 18:39:46 Functions: 4 23 17.4 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2015-21  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             : /* when you work on this code, please install a fuzzer (e.g. AFL) and run
      18             :  * tests/lib/fuzz_zlog.c
      19             :  *
      20             :  * The most likely type of bug in this code is an off-by-one error in the
      21             :  * buffer management pieces, and this isn't easily covered by an unit test
      22             :  * or topotests.  Fuzzing is the best tool here, but the CI can't do that
      23             :  * since it's quite resource intensive.
      24             :  */
      25             : 
      26             : #include "zebra.h"
      27             : 
      28             : #include "zlog_5424.h"
      29             : 
      30             : #include <sys/un.h>
      31             : #include <syslog.h>
      32             : 
      33             : #include "memory.h"
      34             : #include "frrcu.h"
      35             : #include "printfrr.h"
      36             : #include "typerb.h"
      37             : #include "frr_pthread.h"
      38             : #include "command.h"
      39             : #include "monotime.h"
      40             : #include "thread.h"
      41             : 
      42             : #include "lib/version.h"
      43             : #include "lib/lib_errors.h"
      44             : 
      45          36 : DEFINE_MTYPE_STATIC(LOG, LOG_5424, "extended log target");
      46          36 : DEFINE_MTYPE_STATIC(LOG, LOG_5424_ROTATE, "extended log rotate helper");
      47             : 
      48             : /* the actual log target data structure
      49             :  *
      50             :  * remember this is RCU'd by the core zlog functions.  Changing anything
      51             :  * works by allocating a new struct, filling it, adding it, and removing the
      52             :  * old one.
      53             :  */
      54             : struct zlt_5424 {
      55             :         struct zlog_target zt;
      56             : 
      57             :         atomic_uint_fast32_t fd;
      58             : 
      59             :         enum zlog_5424_format fmt;
      60             :         uint32_t ts_flags;
      61             :         int facility;
      62             : 
      63             :         /* the various extra pieces to add... */
      64             :         bool kw_version : 1;
      65             :         bool kw_location : 1;
      66             :         bool kw_uid : 1;
      67             :         bool kw_ec : 1;
      68             :         bool kw_args : 1;
      69             : 
      70             :         /* some formats may or may not include the trailing \n */
      71             :         bool use_nl : 1;
      72             : 
      73             :         /* for DGRAM & SEQPACKET sockets, send 1 log message per packet, since
      74             :          * the socket preserves packet boundaries.  On Linux, this uses
      75             :          * sendmmsg() for efficiency, on other systems we need a syscall each.
      76             :          */
      77             :         bool packets : 1;
      78             : 
      79             :         /* for DGRAM, in order to not have to reconnect, we need to use
      80             :          * sendto()/sendmsg() with the destination given; otherwise we'll get
      81             :          * ENOTCONN.  (We do a connect(), which serves to verify the type of
      82             :          * socket, but if the receiver goes away, the kernel disconnects the
      83             :          * socket so writev() no longer works since the destination is now
      84             :          * unspecified.)
      85             :          */
      86             :         struct sockaddr_storage sa;
      87             :         socklen_t sa_len;
      88             : 
      89             :         /* these are both getting set, but current_err is cleared on success,
      90             :          * so we know whether the error is current or past.
      91             :          */
      92             :         int last_err, current_err;
      93             :         atomic_size_t lost_msgs;
      94             :         struct timeval last_err_ts;
      95             : 
      96             :         struct rcu_head_close head_close;
      97             : };
      98             : 
      99             : static int zlog_5424_open(struct zlog_cfg_5424 *zcf, int sock_type);
     100             : 
     101             : /* rough header length estimate
     102             :  * ============================
     103             :  *
     104             :  *   ^ = might grow
     105             :  *
     106             :  *  49^ longest filename (pceplib/test/pcep_utils_double_linked_list_test.h)
     107             :  *   5^ highest line number (48530, bgpd/bgp_nb_config.c)
     108             :  *  65^ longest function name
     109             :  *      (lib_prefix_list_entry_ipv6_prefix_length_greater_or_equal_destroy)
     110             :  *  11  unique id ("XXXXX-XXXXX")
     111             :  *  10  EC ("4294967295" or "0xffffffff")
     112             :  *  35  ISO8601 TS at full length ("YYYY-MM-DD HH:MM:SS.NNNNNNNNN+ZZ:ZZ")
     113             :  * ---
     114             :  * 175
     115             :  *
     116             :  * rarely used (hopefully...):
     117             :  *  26^ FRR_VERSION ("10.10.10-dev-gffffffffffff")
     118             :  * ---
     119             :  * 201
     120             :  *
     121             :  * x16  highest number of format parameters currently
     122             :  *  40  estimate for hostname + 2*daemon + pid
     123             :  *
     124             :  * specific format overhead:
     125             :  *
     126             :  * RFC3164 - shorter than the others
     127             :  * RFC5424 - 175 + "<999>1 "=7 + 52 (location@50145) + 40 (host/...)
     128             :  *      rarely: + 65 + 26 (for [origin])
     129             :  *      args:  16 * (8 + per-arg (20?)) = ~448
     130             :  *
     131             :  * so without "args@", origin or (future) keywords, around 256 seems OK
     132             :  * with args@ and/or origin and/or keywords, 512 seems more reasonable
     133             :  *
     134             :  * but - note the code allocates this amount multiplied by the number of
     135             :  * messages in the incoming batch (minimum 3), this means short messages and
     136             :  * long messages smooth each other out.
     137             :  *
     138             :  * Since the code handles space-exceeded by grabbing a bunch of stack memory,
     139             :  * a reasonable middle ground estimate is desirable here, so ...
     140             :  * *drumroll*
     141             :  * let's go with 128 + args?128.  (remember the minimum 3 multiplier)
     142             :  *
     143             :  * low_space is the point where we don't try to fit another message in & just
     144             :  * submit what we have to the kernel.
     145             :  *
     146             :  * The zlog code only buffers debug & informational messages, so in production
     147             :  * usage most of the calls will be writing out only 1 message.  This makes
     148             :  * the min *3 multiplier quite useful.
     149             :  */
     150             : 
     151           0 : static inline size_t zlog_5424_bufsz(struct zlt_5424 *zte, size_t nmsgs,
     152             :                                      size_t *low_space)
     153             : {
     154           0 :         size_t ret = 128;
     155             : 
     156           0 :         if (zte->kw_args)
     157           0 :                 ret += 128;
     158           0 :         *low_space = ret;
     159           0 :         return ret * MAX(nmsgs, 3);
     160             : }
     161             : 
     162             : struct state {
     163             :         struct fbuf *fbuf;
     164             :         struct iovec *iov;
     165             : };
     166             : 
     167             : /* stack-based keyword support is likely to bump this to 3 or 4 */
     168             : #define IOV_PER_MSG 2
     169             : _Static_assert(IOV_MAX >= IOV_PER_MSG,
     170             :                "this code won't work with IOV_MAX < IOV_PER_MSG");
     171             : 
     172             : /* the following functions are quite similar, but trying to merge them just
     173             :  * makes a big mess.  check the others when touching one.
     174             :  *
     175             :  *              timestamp       keywords        hostname
     176             :  * RFC5424      ISO8601         yes             yes
     177             :  * RFC3164      RFC3164         no              yes
     178             :  * local        RFC3164         no              no
     179             :  * journald     ISO8601(unused) yes             (unused)
     180             :  */
     181             : 
     182           0 : static size_t zlog_5424_one(struct zlt_5424 *zte, struct zlog_msg *msg,
     183             :                             struct state *state)
     184             : {
     185           0 :         size_t textlen;
     186           0 :         struct fbuf *fbuf = state->fbuf;
     187           0 :         char *orig_pos = fbuf->pos;
     188           0 :         size_t need = 0;
     189           0 :         int prio = zlog_msg_prio(msg);
     190           0 :         intmax_t pid, tid;
     191             : 
     192           0 :         zlog_msg_pid(msg, &pid, &tid);
     193             : 
     194           0 :         need += bprintfrr(fbuf, "<%d>1 ", prio | zte->facility);
     195           0 :         need += zlog_msg_ts(msg, fbuf, zte->ts_flags);
     196           0 :         need += bprintfrr(fbuf, " %s %s %jd %.*s ", cmd_hostname_get() ?: "-",
     197           0 :                           zlog_progname, pid, (int)(zlog_prefixsz - 2),
     198             :                           zlog_prefix);
     199             : 
     200           0 :         if (zte->kw_version)
     201           0 :                 need += bprintfrr(
     202             :                         fbuf,
     203             :                         "[origin enterpriseId=\"50145\" software=\"FRRouting\" swVersion=\"%s\"]",
     204             :                         FRR_VERSION);
     205             : 
     206           0 :         const struct xref_logmsg *xref;
     207           0 :         struct xrefdata *xrefdata;
     208             : 
     209           0 :         need += bprintfrr(fbuf, "[location@50145 tid=\"%jd\"", tid);
     210           0 :         if (zlog_instance > 0)
     211           0 :                 need += bprintfrr(fbuf, " instance=\"%d\"", zlog_instance);
     212             : 
     213           0 :         xref = zlog_msg_xref(msg);
     214           0 :         xrefdata = xref ? xref->xref.xrefdata : NULL;
     215           0 :         if (xrefdata) {
     216           0 :                 if (zte->kw_uid)
     217           0 :                         need += bprintfrr(fbuf, " id=\"%s\"", xrefdata->uid);
     218           0 :                 if (zte->kw_ec && prio <= LOG_WARNING)
     219           0 :                         need += bprintfrr(fbuf, " ec=\"%u\"", xref->ec);
     220           0 :                 if (zte->kw_location)
     221           0 :                         need += bprintfrr(
     222             :                                 fbuf, " file=\"%s\" line=\"%d\" func=\"%s\"",
     223           0 :                                 xref->xref.file, xref->xref.line,
     224           0 :                                 xref->xref.func);
     225             :         }
     226           0 :         need += bputch(fbuf, ']');
     227             : 
     228           0 :         size_t hdrlen, n_argpos;
     229           0 :         const struct fmt_outpos *argpos;
     230           0 :         const char *text;
     231             : 
     232           0 :         text = zlog_msg_text(msg, &textlen);
     233           0 :         zlog_msg_args(msg, &hdrlen, &n_argpos, &argpos);
     234             : 
     235           0 :         if (zte->kw_args && n_argpos) {
     236           0 :                 need += bputs(fbuf, "[args@50145");
     237             : 
     238           0 :                 for (size_t i = 0; i < n_argpos; i++) {
     239           0 :                         int len = argpos[i].off_end - argpos[i].off_start;
     240             : 
     241           0 :                         need += bprintfrr(fbuf, " arg%zu=%*pSQsq", i + 1, len,
     242           0 :                                           text + argpos[i].off_start);
     243             :                 }
     244             : 
     245           0 :                 need += bputch(fbuf, ']');
     246             :         }
     247             : 
     248           0 :         need += bputch(fbuf, ' ');
     249             : 
     250           0 :         if (orig_pos + need > fbuf->buf + fbuf->len) {
     251             :                 /* not enough space in the buffer for headers.  the loop in
     252             :                  * zlog_5424() will flush other messages that are already in
     253             :                  * the buffer, grab a bigger buffer if needed, and try again.
     254             :                  */
     255           0 :                 fbuf->pos = orig_pos;
     256           0 :                 return need;
     257             :         }
     258             : 
     259             :         /* NB: zlog_5424 below assumes we use max. IOV_PER_MSG iovs here */
     260           0 :         state->iov->iov_base = orig_pos;
     261           0 :         state->iov->iov_len = fbuf->pos - orig_pos;
     262           0 :         state->iov++;
     263             : 
     264           0 :         state->iov->iov_base = (char *)text + hdrlen;
     265           0 :         state->iov->iov_len = textlen - hdrlen + zte->use_nl;
     266           0 :         state->iov++;
     267           0 :         return 0;
     268             : }
     269             : 
     270           0 : static size_t zlog_3164_one(struct zlt_5424 *zte, struct zlog_msg *msg,
     271             :                             struct state *state)
     272             : {
     273           0 :         size_t textlen;
     274           0 :         struct fbuf *fbuf = state->fbuf;
     275           0 :         char *orig_pos = fbuf->pos;
     276           0 :         size_t need = 0;
     277           0 :         int prio = zlog_msg_prio(msg);
     278           0 :         intmax_t pid, tid;
     279             : 
     280           0 :         zlog_msg_pid(msg, &pid, &tid);
     281             : 
     282           0 :         need += bprintfrr(fbuf, "<%d>", prio | zte->facility);
     283           0 :         need += zlog_msg_ts_3164(msg, fbuf, zte->ts_flags);
     284           0 :         if (zte->fmt != ZLOG_FMT_LOCAL) {
     285           0 :                 need += bputch(fbuf, ' ');
     286           0 :                 need += bputs(fbuf, cmd_hostname_get() ?: "-");
     287             :         }
     288           0 :         need += bprintfrr(fbuf, " %s[%jd]: ", zlog_progname, pid);
     289             : 
     290           0 :         if (orig_pos + need > fbuf->buf + fbuf->len) {
     291             :                 /* not enough space in the buffer for headers.  loop in
     292             :                  * zlog_5424() will flush other messages that are already in
     293             :                  * the buffer, grab a bigger buffer if needed, and try again.
     294             :                  */
     295           0 :                 fbuf->pos = orig_pos;
     296           0 :                 return need;
     297             :         }
     298             : 
     299             :         /* NB: zlog_5424 below assumes we use max. IOV_PER_MSG iovs here */
     300           0 :         state->iov->iov_base = orig_pos;
     301           0 :         state->iov->iov_len = fbuf->pos - orig_pos;
     302           0 :         state->iov++;
     303             : 
     304           0 :         state->iov->iov_base = (char *)zlog_msg_text(msg, &textlen);
     305           0 :         state->iov->iov_len = textlen + zte->use_nl;
     306           0 :         state->iov++;
     307           0 :         return 0;
     308             : }
     309             : 
     310           0 : static size_t zlog_journald_one(struct zlt_5424 *zte, struct zlog_msg *msg,
     311             :                                 struct state *state)
     312             : {
     313           0 :         size_t textlen;
     314           0 :         struct fbuf *fbuf = state->fbuf;
     315           0 :         char *orig_pos = fbuf->pos;
     316           0 :         size_t need = 0;
     317           0 :         int prio = zlog_msg_prio(msg);
     318           0 :         intmax_t pid, tid;
     319             : 
     320           0 :         zlog_msg_pid(msg, &pid, &tid);
     321             : 
     322           0 :         need += bprintfrr(fbuf,
     323             :                           "PRIORITY=%d\n"
     324             :                           "SYSLOG_FACILITY=%d\n"
     325             :                           "TID=%jd\n"
     326             :                           "FRR_DAEMON=%s\n"
     327             :                           "SYSLOG_TIMESTAMP=",
     328             :                           prio, zte->facility, tid, zlog_progname);
     329           0 :         need += zlog_msg_ts(msg, fbuf, zte->ts_flags);
     330           0 :         need += bputch(fbuf, '\n');
     331           0 :         if (zlog_instance > 0)
     332           0 :                 need += bprintfrr(fbuf, "FRR_INSTANCE=%d\n", zlog_instance);
     333             : 
     334           0 :         const struct xref_logmsg *xref;
     335           0 :         struct xrefdata *xrefdata;
     336             : 
     337           0 :         xref = zlog_msg_xref(msg);
     338           0 :         xrefdata = xref ? xref->xref.xrefdata : NULL;
     339           0 :         if (xrefdata) {
     340           0 :                 if (zte->kw_uid && xrefdata->uid[0])
     341           0 :                         need += bprintfrr(fbuf, "FRR_ID=%s\n", xrefdata->uid);
     342           0 :                 if (zte->kw_ec && prio <= LOG_WARNING)
     343           0 :                         need += bprintfrr(fbuf, "FRR_EC=%d\n", xref->ec);
     344           0 :                 if (zte->kw_location)
     345           0 :                         need += bprintfrr(fbuf,
     346             :                                           "CODE_FILE=%s\n"
     347             :                                           "CODE_LINE=%d\n"
     348             :                                           "CODE_FUNC=%s\n",
     349           0 :                                           xref->xref.file, xref->xref.line,
     350           0 :                                           xref->xref.func);
     351             :         }
     352             : 
     353           0 :         size_t hdrlen, n_argpos;
     354           0 :         const struct fmt_outpos *argpos;
     355           0 :         const char *text;
     356             : 
     357           0 :         text = zlog_msg_text(msg, &textlen);
     358           0 :         zlog_msg_args(msg, &hdrlen, &n_argpos, &argpos);
     359             : 
     360           0 :         if (zte->kw_args && n_argpos) {
     361           0 :                 for (size_t i = 0; i < n_argpos; i++) {
     362           0 :                         int len = argpos[i].off_end - argpos[i].off_start;
     363             : 
     364             :                         /* rather than escape the value, we could use
     365             :                          * journald's binary encoding, but that seems a bit
     366             :                          * excessive/unnecessary.  99% of things we print here
     367             :                          * will just output 1:1 with %pSE.
     368             :                          */
     369           0 :                         need += bprintfrr(fbuf, "FRR_ARG%zu=%*pSE\n", i + 1,
     370           0 :                                           len, text + argpos[i].off_start);
     371             :                 }
     372             :         }
     373             : 
     374           0 :         need += bputs(fbuf, "MESSAGE=");
     375             : 
     376           0 :         if (orig_pos + need > fbuf->buf + fbuf->len) {
     377             :                 /* not enough space in the buffer for headers.  loop in
     378             :                  * zlog_5424() will flush other messages that are already in
     379             :                  * the buffer, grab a bigger buffer if needed, and try again.
     380             :                  */
     381           0 :                 fbuf->pos = orig_pos;
     382           0 :                 return need;
     383             :         }
     384             : 
     385             :         /* NB: zlog_5424 below assumes we use max. IOV_PER_MSG iovs here */
     386           0 :         state->iov->iov_base = orig_pos;
     387           0 :         state->iov->iov_len = fbuf->pos - orig_pos;
     388           0 :         state->iov++;
     389             : 
     390           0 :         state->iov->iov_base = (char *)text + hdrlen;
     391           0 :         state->iov->iov_len = textlen - hdrlen + 1;
     392           0 :         state->iov++;
     393           0 :         return 0;
     394             : }
     395             : 
     396           0 : static size_t zlog_one(struct zlt_5424 *zte, struct zlog_msg *msg,
     397             :                        struct state *state)
     398             : {
     399           0 :         switch (zte->fmt) {
     400           0 :         case ZLOG_FMT_5424:
     401           0 :                 return zlog_5424_one(zte, msg, state);
     402           0 :         case ZLOG_FMT_3164:
     403             :         case ZLOG_FMT_LOCAL:
     404           0 :                 return zlog_3164_one(zte, msg, state);
     405           0 :         case ZLOG_FMT_JOURNALD:
     406           0 :                 return zlog_journald_one(zte, msg, state);
     407             :         }
     408             :         return 0;
     409             : }
     410             : 
     411           0 : static void zlog_5424_err(struct zlt_5424 *zte, size_t count)
     412             : {
     413           0 :         if (!count) {
     414           0 :                 zte->current_err = 0;
     415           0 :                 return;
     416             :         }
     417             : 
     418             :         /* only the counter is atomic because otherwise it'd be meaningless */
     419           0 :         atomic_fetch_add_explicit(&zte->lost_msgs, count, memory_order_relaxed);
     420             : 
     421             :         /* these are non-atomic and can provide wrong results when read, but
     422             :          * since they're only for debugging / display, that's OK.
     423             :          */
     424           0 :         zte->current_err = zte->last_err = errno;
     425           0 :         monotime(&zte->last_err_ts);
     426             : }
     427             : 
     428           0 : static void zlog_5424(struct zlog_target *zt, struct zlog_msg *msgs[],
     429             :                       size_t nmsgs)
     430           0 : {
     431           0 :         size_t i;
     432           0 :         struct zlt_5424 *zte = container_of(zt, struct zlt_5424, zt);
     433           0 :         int fd, ret;
     434           0 :         size_t niov = MIN(IOV_PER_MSG * nmsgs, IOV_MAX);
     435           0 :         struct iovec iov[niov], *iov_last = iov + niov;
     436           0 :         struct mmsghdr mmsg[zte->packets ? nmsgs : 1], *mpos = mmsg;
     437           0 :         size_t count = 0;
     438             : 
     439             :         /* refer to size estimate at top of file */
     440           0 :         size_t low_space;
     441           0 :         char hdr_buf[zlog_5424_bufsz(zte, nmsgs, &low_space)];
     442           0 :         struct fbuf hdr_pos = {
     443             :                 .buf = hdr_buf,
     444             :                 .pos = hdr_buf,
     445             :                 .len = sizeof(hdr_buf),
     446             :         };
     447           0 :         struct state state = {
     448             :                 .fbuf = &hdr_pos,
     449             :                 .iov = iov,
     450             :         };
     451             : 
     452           0 :         fd = atomic_load_explicit(&zte->fd, memory_order_relaxed);
     453             : 
     454           0 :         memset(mmsg, 0, sizeof(mmsg));
     455           0 :         if (zte->sa_len) {
     456           0 :                 for (i = 0; i < array_size(mmsg); i++) {
     457           0 :                         mmsg[i].msg_hdr.msg_name = (struct sockaddr *)&zte->sa;
     458           0 :                         mmsg[i].msg_hdr.msg_namelen = zte->sa_len;
     459             :                 }
     460             :         }
     461           0 :         mmsg[0].msg_hdr.msg_iov = iov;
     462             : 
     463           0 :         for (i = 0; i < nmsgs; i++) {
     464           0 :                 int prio = zlog_msg_prio(msgs[i]);
     465           0 :                 size_t need = 0;
     466             : 
     467           0 :                 if (prio <= zte->zt.prio_min) {
     468           0 :                         if (zte->packets)
     469           0 :                                 mpos->msg_hdr.msg_iov = state.iov;
     470             : 
     471           0 :                         need = zlog_one(zte, msgs[i], &state);
     472             : 
     473           0 :                         if (zte->packets) {
     474           0 :                                 mpos->msg_hdr.msg_iovlen =
     475           0 :                                         state.iov - mpos->msg_hdr.msg_iov;
     476           0 :                                 mpos++;
     477             :                         }
     478           0 :                         count++;
     479             :                 }
     480             : 
     481             :                 /* clang-format off */
     482           0 :                 if ((need
     483           0 :                      || (size_t)(hdr_pos.buf + hdr_pos.len - hdr_pos.pos)
     484             :                                 < low_space
     485           0 :                      || i + 1 == nmsgs
     486           0 :                      || state.iov + IOV_PER_MSG > iov_last)
     487           0 :                     && state.iov > iov) {
     488             :                         /* clang-format on */
     489             : 
     490           0 :                         if (zte->packets) {
     491             :                                 struct mmsghdr *sendpos;
     492             : 
     493           0 :                                 for (sendpos = mmsg; sendpos < mpos;) {
     494           0 :                                         ret = sendmmsg(fd, sendpos,
     495           0 :                                                        mpos - sendpos, 0);
     496           0 :                                         if (ret <= 0)
     497             :                                                 break;
     498           0 :                                         sendpos += ret;
     499             :                                 }
     500           0 :                                 zlog_5424_err(zte, mpos - sendpos);
     501           0 :                                 mpos = mmsg;
     502             :                         } else {
     503           0 :                                 if (!zte->sa_len)
     504           0 :                                         ret = writev(fd, iov, state.iov - iov);
     505             :                                 else {
     506           0 :                                         mpos->msg_hdr.msg_iovlen =
     507           0 :                                                 state.iov - iov;
     508           0 :                                         ret = sendmsg(fd, &mpos->msg_hdr, 0);
     509             :                                 }
     510             : 
     511           0 :                                 if (ret < 0)
     512           0 :                                         zlog_5424_err(zte, count);
     513             :                                 else
     514           0 :                                         zlog_5424_err(zte, 0);
     515             :                         }
     516             : 
     517           0 :                         count = 0;
     518           0 :                         hdr_pos.pos = hdr_buf;
     519           0 :                         state.iov = iov;
     520             :                 }
     521             : 
     522             :                 /* if need == 0, we just put a message (or nothing) in the
     523             :                  * buffer and are continuing for more to batch in a single
     524             :                  * writev()
     525             :                  */
     526           0 :                 if (need == 0)
     527           0 :                         continue;
     528             : 
     529           0 :                 if (need && need <= sizeof(hdr_buf)) {
     530             :                         /* don't need to allocate, just try this msg
     531             :                          * again without other msgs already using up
     532             :                          * buffer space
     533             :                          */
     534           0 :                         i--;
     535           0 :                         continue;
     536             :                 }
     537             : 
     538             :                 /* need > sizeof(hdr_buf), need to grab some memory.  Taking
     539             :                  * it off the stack is fine here.
     540             :                  */
     541           0 :                 char buf2[need];
     542           0 :                 struct fbuf fbuf2 = {
     543             :                         .buf = buf2,
     544             :                         .pos = buf2,
     545             :                         .len = sizeof(buf2),
     546             :                 };
     547             : 
     548           0 :                 state.fbuf = &fbuf2;
     549           0 :                 need = zlog_one(zte, msgs[i], &state);
     550           0 :                 assert(need == 0);
     551             : 
     552           0 :                 if (!zte->sa_len)
     553           0 :                         ret = writev(fd, iov, state.iov - iov);
     554             :                 else {
     555           0 :                         mpos->msg_hdr.msg_iovlen = state.iov - iov;
     556           0 :                         ret = sendmsg(fd, &mpos->msg_hdr, 0);
     557             :                 }
     558             : 
     559           0 :                 if (ret < 0)
     560           0 :                         zlog_5424_err(zte, 1);
     561             :                 else
     562           0 :                         zlog_5424_err(zte, 0);
     563             : 
     564           0 :                 count = 0;
     565           0 :                 state.fbuf = &hdr_pos;
     566           0 :                 state.iov = iov;
     567           0 :                 mpos = mmsg;
     568             :         }
     569             : 
     570           0 :         assert(state.iov == iov);
     571           0 : }
     572             : 
     573             : /* strftime(), gmtime_r() and localtime_r() aren't AS-Safe (they access locale
     574             :  * data), but we need an AS-Safe timestamp below :(
     575             :  */
     576           0 : static void gmtime_assafe(time_t ts, struct tm *res)
     577             : {
     578           0 :         res->tm_sec = ts % 60;
     579           0 :         ts /= 60;
     580           0 :         res->tm_min = ts % 60;
     581           0 :         ts /= 60;
     582           0 :         res->tm_hour = ts % 24;
     583           0 :         ts /= 24;
     584             : 
     585           0 :         ts -= 11017; /* start on 2020-03-01, 11017 days since 1970-01-01 */
     586             : 
     587             :         /* 1461 days = 3 regular years + 1 leap year
     588             :          * this works until 2100, which isn't a leap year
     589             :          *
     590             :          * struct tm.tm_year starts at 1900.
     591             :          */
     592           0 :         res->tm_year = 2000 - 1900 + 4 * (ts / 1461);
     593           0 :         ts = ts % 1461;
     594             : 
     595           0 :         if (ts == 1460) {
     596           0 :                 res->tm_year += 4;
     597           0 :                 res->tm_mon = 1;
     598           0 :                 res->tm_mday = 29;
     599           0 :                 return;
     600             :         }
     601           0 :         res->tm_year += ts / 365;
     602           0 :         ts %= 365;
     603             : 
     604             :         /* note we're starting in march like the romans did... */
     605           0 :         if (ts >= 306) /* Jan 1 of next year */
     606           0 :                 res->tm_year++;
     607             : 
     608           0 :         static time_t months[13] = {
     609             :                 0, 31, 61, 92, 122, 153, 184, 214, 245, 275, 306, 337, 365,
     610             :         };
     611           0 :         const size_t month_max = array_size(months) - 1;
     612             : 
     613           0 :         for (size_t i = 0; i < month_max; i++) {
     614           0 :                 if (ts < months[i + 1]) {
     615           0 :                         res->tm_mon = ((i + 2) % 12);
     616           0 :                         res->tm_mday = 1 + ts - months[i];
     617           0 :                         break;
     618             :                 }
     619             :         }
     620             : }
     621             : 
     622             : /* one of the greatest advantages of this logging target:  unlike syslog(),
     623             :  * which is not AS-Safe, we can send crashlogs to syslog here.
     624             :  */
     625           0 : static void zlog_5424_sigsafe(struct zlog_target *zt, const char *text,
     626             :                               size_t len)
     627             : {
     628           0 :         static const char *const months_3164[12] = {
     629             :                 "Jan", "Feb", "Mar", "Apr", "May", "Jun",
     630             :                 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
     631             :         };
     632             : 
     633           0 :         struct zlt_5424 *zte = container_of(zt, struct zlt_5424, zt);
     634           0 :         struct iovec iov[3], *iovp = iov;
     635           0 :         char buf[256];
     636           0 :         struct fbuf fbuf = {
     637             :                 .buf = buf,
     638             :                 .pos = buf,
     639             :                 .len = sizeof(buf),
     640             :         };
     641           0 :         int fd;
     642           0 :         intmax_t pid = (intmax_t)getpid();
     643           0 :         struct tm tm;
     644             : 
     645           0 :         switch (zte->fmt) {
     646           0 :         case ZLOG_FMT_5424:
     647           0 :                 gmtime_assafe(time(NULL), &tm);
     648           0 :                 bprintfrr(
     649             :                         &fbuf,
     650             :                         "<%d>1 %04u-%02u-%02uT%02u:%02u:%02uZ - %s %jd %.*s  ",
     651           0 :                         zte->facility | LOG_CRIT, tm.tm_year + 1900,
     652           0 :                         tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min,
     653           0 :                         tm.tm_sec, zlog_progname, pid, (int)(zlog_prefixsz - 2),
     654             :                         zlog_prefix);
     655           0 :                 break;
     656             : 
     657           0 :         case ZLOG_FMT_3164:
     658             :         case ZLOG_FMT_LOCAL:
     659             :                 /* this will unfortuantely be wrong by the timezone offset
     660             :                  * if the user selected non-UTC.  But not much we can do
     661             :                  * about that...
     662             :                  */
     663           0 :                 gmtime_assafe(time(NULL), &tm);
     664           0 :                 bprintfrr(&fbuf, "<%d>%3s %2u %02u:%02u:%02u %s%s[%jd]: ",
     665           0 :                           zte->facility | LOG_CRIT, months_3164[tm.tm_mon],
     666             :                           tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
     667           0 :                           (zte->fmt == ZLOG_FMT_LOCAL) ? "" : "- ",
     668             :                           zlog_progname, pid);
     669           0 :                 break;
     670             : 
     671           0 :         case ZLOG_FMT_JOURNALD:
     672           0 :                 bprintfrr(&fbuf,
     673             :                           "PRIORITY=%d\n"
     674             :                           "SYSLOG_FACILITY=%d\n"
     675             :                           "FRR_DAEMON=%s\n"
     676             :                           "MESSAGE=",
     677             :                           LOG_CRIT, zte->facility, zlog_progname);
     678           0 :                 break;
     679             :         }
     680             : 
     681           0 :         iovp->iov_base = fbuf.buf;
     682           0 :         iovp->iov_len = fbuf.pos - fbuf.buf;
     683           0 :         iovp++;
     684             : 
     685           0 :         iovp->iov_base = (char *)text;
     686           0 :         iovp->iov_len = len;
     687           0 :         iovp++;
     688             : 
     689           0 :         if (zte->use_nl) {
     690           0 :                 iovp->iov_base = (char *)"\n";
     691           0 :                 iovp->iov_len = 1;
     692           0 :                 iovp++;
     693             :         }
     694             : 
     695           0 :         fd = atomic_load_explicit(&zte->fd, memory_order_relaxed);
     696             : 
     697           0 :         if (!zte->sa_len)
     698           0 :                 writev(fd, iov, iovp - iov);
     699             :         else {
     700           0 :                 struct msghdr mh = {};
     701             : 
     702           0 :                 mh.msg_name = (struct sockaddr *)&zte->sa;
     703           0 :                 mh.msg_namelen = zte->sa_len;
     704           0 :                 mh.msg_iov = iov;
     705           0 :                 mh.msg_iovlen = iovp - iov;
     706           0 :                 sendmsg(fd, &mh, 0);
     707             :         }
     708           0 : }
     709             : 
     710             : /* housekeeping & configuration */
     711             : 
     712           0 : void zlog_5424_init(struct zlog_cfg_5424 *zcf)
     713             : {
     714           0 :         pthread_mutex_init(&zcf->cfg_mtx, NULL);
     715           0 : }
     716             : 
     717           0 : static void zlog_5424_target_free(struct zlt_5424 *zlt)
     718             : {
     719           0 :         if (!zlt)
     720             :                 return;
     721             : 
     722           0 :         rcu_close(&zlt->head_close, zlt->fd);
     723           0 :         rcu_free(MTYPE_LOG_5424, zlt, zt.rcu_head);
     724             : }
     725             : 
     726           0 : void zlog_5424_fini(struct zlog_cfg_5424 *zcf, bool keepopen)
     727             : {
     728           0 :         if (keepopen)
     729           0 :                 zcf->active = NULL;
     730             : 
     731           0 :         if (zcf->active) {
     732           0 :                 struct zlt_5424 *ztf;
     733           0 :                 struct zlog_target *zt;
     734             : 
     735           0 :                 zt = zlog_target_replace(&zcf->active->zt, NULL);
     736           0 :                 ztf = container_of(zt, struct zlt_5424, zt);
     737           0 :                 zlog_5424_target_free(ztf);
     738             :         }
     739           0 :         pthread_mutex_destroy(&zcf->cfg_mtx);
     740           0 : }
     741             : 
     742           0 : static void zlog_5424_cycle(struct zlog_cfg_5424 *zcf, int fd)
     743             : {
     744           0 :         struct zlog_target *old;
     745           0 :         struct zlt_5424 *zlt = NULL, *oldt;
     746             : 
     747           0 :         if (fd >= 0) {
     748           0 :                 struct zlog_target *zt;
     749             : 
     750             :                 /* all of this is swapped in by zlog_target_replace() below,
     751             :                  * the old target is RCU-freed afterwards.
     752             :                  */
     753           0 :                 zt = zlog_target_clone(MTYPE_LOG_5424, &zcf->active->zt,
     754             :                                        sizeof(*zlt));
     755           0 :                 zlt = container_of(zt, struct zlt_5424, zt);
     756             : 
     757           0 :                 zlt->fd = fd;
     758           0 :                 zlt->kw_version = zcf->kw_version;
     759           0 :                 zlt->kw_location = zcf->kw_location;
     760           0 :                 zlt->kw_uid = zcf->kw_uid;
     761           0 :                 zlt->kw_ec = zcf->kw_ec;
     762           0 :                 zlt->kw_args = zcf->kw_args;
     763           0 :                 zlt->use_nl = true;
     764           0 :                 zlt->facility = zcf->facility;
     765             : 
     766             :                 /* DGRAM & SEQPACKET = 1 log message per packet */
     767           0 :                 zlt->packets = (zcf->sock_type == SOCK_DGRAM) ||
     768             :                                (zcf->sock_type == SOCK_SEQPACKET);
     769           0 :                 zlt->sa = zcf->sa;
     770           0 :                 zlt->sa_len = zcf->sa_len;
     771           0 :                 zlt->fmt = zcf->fmt;
     772           0 :                 zlt->zt.prio_min = zcf->prio_min;
     773           0 :                 zlt->zt.logfn = zlog_5424;
     774           0 :                 zlt->zt.logfn_sigsafe = zlog_5424_sigsafe;
     775             : 
     776           0 :                 switch (zcf->fmt) {
     777           0 :                 case ZLOG_FMT_5424:
     778             :                 case ZLOG_FMT_JOURNALD:
     779           0 :                         zlt->ts_flags = zcf->ts_flags;
     780           0 :                         zlt->ts_flags &= ZLOG_TS_PREC | ZLOG_TS_UTC;
     781           0 :                         zlt->ts_flags |= ZLOG_TS_ISO8601;
     782           0 :                         break;
     783           0 :                 case ZLOG_FMT_3164:
     784             :                 case ZLOG_FMT_LOCAL:
     785           0 :                         zlt->ts_flags = zcf->ts_flags & ZLOG_TS_UTC;
     786           0 :                         if (zlt->packets)
     787           0 :                                 zlt->use_nl = false;
     788             :                         break;
     789             :                 }
     790             :         }
     791             : 
     792           0 :         old = zcf->active ? &zcf->active->zt : NULL;
     793           0 :         old = zlog_target_replace(old, &zlt->zt);
     794           0 :         zcf->active = zlt;
     795             : 
     796             :         /* oldt->fd == fd happens for zlog_5424_apply_meta() */
     797           0 :         oldt = container_of(old, struct zlt_5424, zt);
     798           0 :         if (oldt && oldt->fd != (unsigned int)fd)
     799           0 :                 rcu_close(&oldt->head_close, oldt->fd);
     800           0 :         rcu_free(MTYPE_LOG_5424, oldt, zt.rcu_head);
     801           0 : }
     802             : 
     803           0 : static void zlog_5424_reconnect(struct thread *t)
     804             : {
     805           0 :         struct zlog_cfg_5424 *zcf = THREAD_ARG(t);
     806           0 :         int fd = THREAD_FD(t);
     807           0 :         char dummy[256];
     808           0 :         ssize_t ret;
     809             : 
     810           0 :         if (zcf->active) {
     811           0 :                 ret = read(fd, dummy, sizeof(dummy));
     812           0 :                 if (ret > 0) {
     813             :                         /* logger is sending us something?!?! */
     814           0 :                         thread_add_read(t->master, zlog_5424_reconnect, zcf, fd,
     815             :                                         &zcf->t_reconnect);
     816           0 :                         return;
     817             :                 }
     818             : 
     819           0 :                 if (ret == 0)
     820           0 :                         zlog_warn("logging socket %pSE closed by peer",
     821             :                                   zcf->filename);
     822             :                 else
     823           0 :                         zlog_warn("logging socket %pSE error: %m",
     824             :                                   zcf->filename);
     825             :         }
     826             : 
     827             :         /* do NOT close() anything here;  other threads may still be writing
     828             :          * and their messages need to be lost rather than end up on a random
     829             :          * other fd that got reassigned the same number, like a BGP session!
     830             :          */
     831           0 :         fd = zlog_5424_open(zcf, -1);
     832             : 
     833           0 :         frr_with_mutex (&zcf->cfg_mtx) {
     834           0 :                 zlog_5424_cycle(zcf, fd);
     835             :         }
     836             : }
     837             : 
     838           0 : static int zlog_5424_unix(struct sockaddr_un *suna, int sock_type)
     839             : {
     840           0 :         int fd;
     841           0 :         int size = 1 * 1024 * 1024, prev_size;
     842           0 :         socklen_t opt_size;
     843           0 :         int save_errno;
     844             : 
     845           0 :         fd = socket(AF_UNIX, sock_type, 0);
     846           0 :         if (fd < 0)
     847             :                 return -1;
     848             : 
     849           0 :         if (connect(fd, (struct sockaddr *)suna, sizeof(*suna))) {
     850             :                 /* zlog_5424_open() will print the error for connect() */
     851           0 :                 save_errno = errno;
     852           0 :                 close(fd);
     853           0 :                 errno = save_errno;
     854           0 :                 return -1;
     855             :         }
     856             : 
     857           0 :         opt_size = sizeof(prev_size);
     858           0 :         if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &prev_size, &opt_size))
     859             :                 return fd;
     860             : 
     861             :         /* setsockopt_so_sendbuf() logs on error; we don't really care that
     862             :          * much here.  Also, never shrink the buffer below the initial size.
     863             :          */
     864           0 :         while (size > prev_size &&
     865           0 :                setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)) == -1)
     866           0 :                 size /= 2;
     867             : 
     868             :         return fd;
     869             : }
     870             : 
     871           0 : static int zlog_5424_open(struct zlog_cfg_5424 *zcf, int sock_type)
     872             : {
     873           0 :         int fd = -1;
     874           0 :         int flags = 0;
     875           0 :         int err;
     876           0 :         socklen_t optlen;
     877           0 :         bool do_chown = false;
     878           0 :         bool need_reconnect = false;
     879           0 :         static const int unix_types[] = {
     880             :                 SOCK_STREAM,
     881             :                 SOCK_SEQPACKET,
     882             :                 SOCK_DGRAM,
     883             :         };
     884           0 :         struct sockaddr_un sa;
     885             : 
     886           0 :         zcf->sock_type = -1;
     887           0 :         zcf->sa_len = 0;
     888             : 
     889           0 :         switch (zcf->dst) {
     890             :         case ZLOG_5424_DST_NONE:
     891             :                 break;
     892             : 
     893           0 :         case ZLOG_5424_DST_FD:
     894           0 :                 fd = dup(zcf->fd);
     895             : 
     896           0 :                 optlen = sizeof(sock_type);
     897           0 :                 if (!getsockopt(fd, SOL_SOCKET, SO_TYPE, &sock_type, &optlen)) {
     898           0 :                         zcf->sock_type = sock_type;
     899           0 :                         need_reconnect = (zcf->sock_type != SOCK_DGRAM);
     900             :                 }
     901             :                 break;
     902             : 
     903           0 :         case ZLOG_5424_DST_FIFO:
     904           0 :                 if (!zcf->filename)
     905             :                         break;
     906             : 
     907           0 :                 if (!zcf->file_nocreate) {
     908           0 :                         frr_with_privs (lib_privs) {
     909           0 :                                 mode_t prevmask;
     910             : 
     911           0 :                                 prevmask = umask(0777 ^ zcf->file_mode);
     912           0 :                                 err = mkfifo(zcf->filename, 0666);
     913           0 :                                 umask(prevmask);
     914             :                         }
     915           0 :                         if (err == 0)
     916             :                                 do_chown = true;
     917           0 :                         else if (errno != EEXIST)
     918             :                                 break;
     919             :                 }
     920             : 
     921             :                 flags = O_NONBLOCK;
     922             :                 /* fallthru */
     923             : 
     924           0 :         case ZLOG_5424_DST_FILE:
     925           0 :                 if (!zcf->filename)
     926             :                         break;
     927             : 
     928           0 :                 frr_with_privs (lib_privs) {
     929           0 :                         fd = open(zcf->filename, flags | O_WRONLY | O_APPEND |
     930             :                                                          O_CLOEXEC | O_NOCTTY);
     931             :                 }
     932           0 :                 if (fd >= 0)
     933             :                         break;
     934           0 :                 if (zcf->file_nocreate || flags) {
     935           0 :                         flog_err_sys(EC_LIB_SYSTEM_CALL,
     936             :                                      "could not open log file %pSE: %m",
     937             :                                      zcf->filename);
     938           0 :                         break;
     939             :                 }
     940             : 
     941           0 :                 frr_with_privs (lib_privs) {
     942           0 :                         mode_t prevmask;
     943             : 
     944           0 :                         prevmask = umask(0777 ^ zcf->file_mode);
     945           0 :                         fd = open(zcf->filename,
     946             :                                   O_WRONLY | O_APPEND | O_CLOEXEC | O_NOCTTY |
     947             :                                           O_CREAT | O_EXCL,
     948             :                                   zcf->file_mode);
     949           0 :                         umask(prevmask);
     950             :                 }
     951           0 :                 if (fd >= 0) {
     952             :                         do_chown = true;
     953             :                         break;
     954             :                 }
     955             : 
     956           0 :                 frr_with_privs (lib_privs) {
     957           0 :                         fd = open(zcf->filename,
     958             :                                   O_WRONLY | O_APPEND | O_CLOEXEC | O_NOCTTY);
     959             :                 }
     960           0 :                 if (fd >= 0)
     961             :                         break;
     962             : 
     963           0 :                 flog_err_sys(EC_LIB_SYSTEM_CALL,
     964             :                              "could not open or create log file %pSE: %m",
     965             :                              zcf->filename);
     966           0 :                 break;
     967             : 
     968           0 :         case ZLOG_5424_DST_UNIX:
     969           0 :                 if (!zcf->filename)
     970             :                         break;
     971             : 
     972           0 :                 memset(&sa, 0, sizeof(sa));
     973           0 :                 sa.sun_family = AF_UNIX;
     974           0 :                 strlcpy(sa.sun_path, zcf->filename, sizeof(sa.sun_path));
     975             : 
     976             :                 /* check if ZLOG_5424_DST_FD needs a touch when changing
     977             :                  * something here.  the user can pass in a pre-opened unix
     978             :                  * socket through a fd at startup.
     979             :                  */
     980           0 :                 frr_with_privs (lib_privs) {
     981           0 :                         if (sock_type != -1)
     982           0 :                                 fd = zlog_5424_unix(&sa, sock_type);
     983             :                         else {
     984           0 :                                 for (size_t i = 0; i < array_size(unix_types);
     985           0 :                                      i++) {
     986           0 :                                         fd = zlog_5424_unix(&sa, unix_types[i]);
     987           0 :                                         if (fd != -1) {
     988           0 :                                                 zcf->sock_type = unix_types[i];
     989           0 :                                                 break;
     990             :                                         }
     991             :                                 }
     992             :                         }
     993             :                 }
     994           0 :                 if (fd == -1) {
     995           0 :                         zcf->sock_type = -1;
     996             : 
     997           0 :                         flog_err_sys(
     998             :                                 EC_LIB_SYSTEM_CALL,
     999             :                                 "could not connect to log unix path %pSE: %m",
    1000             :                                 zcf->filename);
    1001           0 :                         need_reconnect = true;
    1002             :                 } else {
    1003             :                         /* datagram sockets are connectionless, restarting
    1004             :                          * the receiver may lose some packets but will resume
    1005             :                          * working afterwards without any action from us.
    1006             :                          */
    1007           0 :                         need_reconnect = (zcf->sock_type != SOCK_DGRAM);
    1008             :                 }
    1009             :                 break;
    1010             :         }
    1011             : 
    1012             :         /* viable on both DST_FD and DST_UNIX path */
    1013           0 :         if (zcf->sock_type == SOCK_DGRAM) {
    1014           0 :                 zcf->sa_len = sizeof(zcf->sa);
    1015           0 :                 if (getpeername(fd, (struct sockaddr *)&zcf->sa,
    1016             :                                 &zcf->sa_len)) {
    1017           0 :                         flog_err_sys(
    1018             :                                 EC_LIB_SYSTEM_CALL,
    1019             :                                 "could not get remote address for log socket.  logging may break if log receiver restarts.");
    1020           0 :                         zcf->sa_len = 0;
    1021             :                 }
    1022             :         }
    1023             : 
    1024           0 :         if (do_chown) {
    1025           0 :                 uid_t uid = zcf->file_uid;
    1026           0 :                 gid_t gid = zcf->file_gid;
    1027             : 
    1028           0 :                 if (uid != (uid_t)-1 || gid != (gid_t)-1) {
    1029           0 :                         frr_with_privs (lib_privs) {
    1030           0 :                                 err = fchown(fd, uid, gid);
    1031             :                         }
    1032           0 :                         if (err)
    1033           0 :                                 flog_err_sys(
    1034             :                                         EC_LIB_SYSTEM_CALL,
    1035             :                                         "failed to chown() log file %pSE: %m",
    1036             :                                         zcf->filename);
    1037             :                 }
    1038             :         }
    1039             : 
    1040           0 :         if (need_reconnect) {
    1041           0 :                 assert(zcf->master);
    1042             : 
    1043           0 :                 if (fd != -1) {
    1044           0 :                         thread_add_read(zcf->master, zlog_5424_reconnect, zcf,
    1045             :                                         fd, &zcf->t_reconnect);
    1046           0 :                         zcf->reconn_backoff_cur = zcf->reconn_backoff;
    1047             : 
    1048             :                 } else {
    1049           0 :                         thread_add_timer_msec(zcf->master, zlog_5424_reconnect,
    1050             :                                               zcf, zcf->reconn_backoff_cur,
    1051             :                                               &zcf->t_reconnect);
    1052             : 
    1053           0 :                         zcf->reconn_backoff_cur += zcf->reconn_backoff_cur / 2;
    1054           0 :                         if (zcf->reconn_backoff_cur > zcf->reconn_backoff_max)
    1055           0 :                                 zcf->reconn_backoff_cur =
    1056             :                                         zcf->reconn_backoff_max;
    1057             :                 }
    1058             :         }
    1059             : 
    1060           0 :         return fd;
    1061             : }
    1062             : 
    1063           0 : bool zlog_5424_apply_dst(struct zlog_cfg_5424 *zcf)
    1064             : {
    1065           0 :         int fd = -1;
    1066             : 
    1067           0 :         thread_cancel(&zcf->t_reconnect);
    1068             : 
    1069           0 :         if (zcf->prio_min != ZLOG_DISABLED)
    1070           0 :                 fd = zlog_5424_open(zcf, -1);
    1071             : 
    1072           0 :         frr_with_mutex (&zcf->cfg_mtx) {
    1073           0 :                 zlog_5424_cycle(zcf, fd);
    1074             :         }
    1075           0 :         return fd != -1;
    1076             : }
    1077             : 
    1078             : 
    1079           0 : bool zlog_5424_apply_meta(struct zlog_cfg_5424 *zcf)
    1080             : {
    1081           0 :         frr_with_mutex (&zcf->cfg_mtx) {
    1082           0 :                 if (zcf->active)
    1083           0 :                         zlog_5424_cycle(zcf, zcf->active->fd);
    1084             :         }
    1085             : 
    1086           0 :         return true;
    1087             : }
    1088             : 
    1089           0 : void zlog_5424_state(struct zlog_cfg_5424 *zcf, size_t *lost_msgs,
    1090             :                      int *last_errno, bool *stale_errno, struct timeval *err_ts)
    1091             : {
    1092           0 :         if (lost_msgs)
    1093           0 :                 *lost_msgs =
    1094           0 :                         zcf->active
    1095           0 :                                 ? atomic_load_explicit(&zcf->active->lost_msgs,
    1096             :                                                        memory_order_relaxed)
    1097           0 :                                 : 0;
    1098           0 :         if (last_errno)
    1099           0 :                 *last_errno = zcf->active ? zcf->active->last_err : 0;
    1100           0 :         if (stale_errno)
    1101           0 :                 *stale_errno = zcf->active ? !zcf->active->current_err : 0;
    1102           0 :         if (err_ts && zcf->active)
    1103           0 :                 *err_ts = zcf->active->last_err_ts;
    1104           0 : }
    1105             : 
    1106             : struct rcu_close_rotate {
    1107             :         struct rcu_head_close head_close;
    1108             :         struct rcu_head head_self;
    1109             : };
    1110             : 
    1111           0 : bool zlog_5424_rotate(struct zlog_cfg_5424 *zcf)
    1112             : {
    1113           0 :         struct rcu_close_rotate *rcr;
    1114           0 :         int fd;
    1115             : 
    1116           0 :         frr_with_mutex (&zcf->cfg_mtx) {
    1117           0 :                 if (!zcf->active)
    1118             :                         return true;
    1119             : 
    1120           0 :                 thread_cancel(&zcf->t_reconnect);
    1121             : 
    1122             :                 /* need to retain the socket type because it also influences
    1123             :                  * other fields (packets) and we can't atomically swap these
    1124             :                  * out.  But we really want the atomic swap so we neither lose
    1125             :                  * nor duplicate log messages, particularly for file targets.
    1126             :                  *
    1127             :                  * (zlog_5424_apply_dst / zlog_target_replace will cause
    1128             :                  * duplicate log messages if another thread logs something
    1129             :                  * while we're right in the middle of swapping out the log
    1130             :                  * target)
    1131             :                  */
    1132           0 :                 fd = zlog_5424_open(zcf, zcf->sock_type);
    1133           0 :                 if (fd < 0)
    1134             :                         return false;
    1135             : 
    1136           0 :                 fd = atomic_exchange_explicit(&zcf->active->fd,
    1137             :                                               (uint_fast32_t)fd,
    1138             :                                               memory_order_relaxed);
    1139             :         }
    1140             : 
    1141           0 :         rcr = XCALLOC(MTYPE_LOG_5424_ROTATE, sizeof(*rcr));
    1142           0 :         rcu_close(&rcr->head_close, fd);
    1143           0 :         rcu_free(MTYPE_LOG_5424_ROTATE, rcr, head_self);
    1144             : 
    1145           0 :         return true;
    1146             : }

Generated by: LCOV version v1.16-topotato