back to topotato report
topotato coverage report
Current view: top level - lib - zlog_5424_cli.c (source / functions) Hit Total Coverage
Test: test_ospf6_vlink.py::VirtualLinkBasic Lines: 35 437 8.0 %
Date: 2023-02-16 02:06:43 Functions: 9 34 26.5 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (C) 2021  David Lamparter for NetDEF, Inc.
       3             :  *
       4             :  * This program is free software; you can redistribute it and/or modify it
       5             :  * under the terms of the GNU General Public License as published by the Free
       6             :  * Software Foundation; either version 2 of the License, or (at your option)
       7             :  * any later version.
       8             :  *
       9             :  * This program is distributed in the hope that it will be useful, but WITHOUT
      10             :  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      11             :  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
      12             :  * more details.
      13             :  *
      14             :  * You should have received a copy of the GNU General Public License along
      15             :  * with this program; see the file COPYING; if not, write to the Free Software
      16             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      17             :  */
      18             : 
      19             : #include "zebra.h"
      20             : #include "zlog_5424.h"
      21             : 
      22             : #include <sys/types.h>
      23             : #include <pwd.h>
      24             : #include <grp.h>
      25             : 
      26             : #include "lib/command.h"
      27             : #include "lib/libfrr.h"
      28             : #include "lib/log_vty.h"
      29             : 
      30          48 : DEFINE_MTYPE_STATIC(LOG, LOG_5424_CONFIG, "extended syslog config");
      31          48 : DEFINE_MTYPE_STATIC(LOG, LOG_5424_DATA, "extended syslog config items");
      32             : 
      33           0 : static int target_cmp(const struct zlog_cfg_5424_user *a,
      34             :                       const struct zlog_cfg_5424_user *b)
      35             : {
      36           0 :         return strcmp(a->name, b->name);
      37             : }
      38             : 
      39          16 : DECLARE_RBTREE_UNIQ(targets, struct zlog_cfg_5424_user, targets_item,
      40             :                     target_cmp);
      41             : DEFINE_QOBJ_TYPE(zlog_cfg_5424_user);
      42             : 
      43             : static struct targets_head targets = INIT_RBTREE_UNIQ(targets);
      44             : static struct thread_master *log_5424_master;
      45             : 
      46             : static void clear_dst(struct zlog_cfg_5424_user *cfg);
      47             : 
      48             : struct log_option {
      49             :         const char *name;
      50             :         ptrdiff_t offs;
      51             :         bool dflt;
      52             : };
      53             : 
      54             : /* clang-format off */
      55             : static struct log_option log_opts[] = {
      56             :         { "code-location",    offsetof(struct zlog_cfg_5424, kw_location) },
      57             :         { "version",          offsetof(struct zlog_cfg_5424, kw_version) },
      58             :         { "unique-id",                offsetof(struct zlog_cfg_5424, kw_uid), true },
      59             :         { "error-category",   offsetof(struct zlog_cfg_5424, kw_ec), true },
      60             :         { "format-args",      offsetof(struct zlog_cfg_5424, kw_args) },
      61             :         {},
      62             : };
      63             : 
      64             : #define DFLT_TS_FLAGS           (6 | ZLOG_TS_UTC)
      65             : #define DFLT_FACILITY           LOG_DAEMON
      66             : #define DFLT_PRIO_MIN           LOG_DEBUG
      67             : /* clang-format on */
      68             : 
      69             : enum unix_special {
      70             :         SPECIAL_NONE = 0,
      71             :         SPECIAL_SYSLOG,
      72             :         SPECIAL_JOURNALD,
      73             : };
      74             : 
      75           0 : static struct zlog_cfg_5424_user *log_5424_alloc(const char *name)
      76             : {
      77           0 :         struct zlog_cfg_5424_user *cfg;
      78             : 
      79           0 :         cfg = XCALLOC(MTYPE_LOG_5424_CONFIG, sizeof(*cfg));
      80           0 :         cfg->name = XSTRDUP(MTYPE_LOG_5424_DATA, name);
      81             : 
      82           0 :         cfg->cfg.master = log_5424_master;
      83           0 :         cfg->cfg.kw_location = true;
      84           0 :         cfg->cfg.kw_version = false;
      85           0 :         cfg->cfg.facility = DFLT_FACILITY;
      86           0 :         cfg->cfg.prio_min = DFLT_PRIO_MIN;
      87           0 :         cfg->cfg.ts_flags = DFLT_TS_FLAGS;
      88           0 :         clear_dst(cfg);
      89             : 
      90           0 :         for (struct log_option *opt = log_opts; opt->name; opt++) {
      91           0 :                 bool *ptr = (bool *)(((char *)&cfg->cfg) + opt->offs);
      92           0 :                 *ptr = opt->dflt;
      93             :         }
      94             : 
      95           0 :         zlog_5424_init(&cfg->cfg);
      96             : 
      97           0 :         QOBJ_REG(cfg, zlog_cfg_5424_user);
      98           0 :         targets_add(&targets, cfg);
      99           0 :         return cfg;
     100             : }
     101             : 
     102           0 : static void log_5424_free(struct zlog_cfg_5424_user *cfg, bool keepopen)
     103             : {
     104           0 :         targets_del(&targets, cfg);
     105           0 :         QOBJ_UNREG(cfg);
     106             : 
     107           0 :         zlog_5424_fini(&cfg->cfg, keepopen);
     108           0 :         clear_dst(cfg);
     109             : 
     110           0 :         XFREE(MTYPE_LOG_5424_DATA, cfg->filename);
     111           0 :         XFREE(MTYPE_LOG_5424_DATA, cfg->name);
     112           0 :         XFREE(MTYPE_LOG_5424_CONFIG, cfg);
     113           0 : }
     114             : 
     115           0 : static void clear_dst(struct zlog_cfg_5424_user *cfg)
     116             : {
     117           0 :         XFREE(MTYPE_LOG_5424_DATA, cfg->filename);
     118           0 :         cfg->cfg.filename = cfg->filename;
     119             : 
     120           0 :         XFREE(MTYPE_LOG_5424_DATA, cfg->file_user);
     121           0 :         XFREE(MTYPE_LOG_5424_DATA, cfg->file_group);
     122           0 :         XFREE(MTYPE_LOG_5424_DATA, cfg->envvar);
     123             : 
     124           0 :         cfg->cfg.fd = -1;
     125           0 :         cfg->cfg.file_uid = -1;
     126           0 :         cfg->cfg.file_gid = -1;
     127           0 :         cfg->cfg.file_mode = LOGFILE_MASK & 0666;
     128           0 :         cfg->cfg.file_nocreate = false;
     129           0 :         cfg->cfg.dst = ZLOG_5424_DST_NONE;
     130           0 : }
     131             : 
     132           0 : static int reconf_dst(struct zlog_cfg_5424_user *cfg, struct vty *vty)
     133             : {
     134           0 :         if (!cfg->reconf_dst && !cfg->reconf_meta && vty->type != VTY_FILE)
     135           0 :                 vty_out(vty,
     136             :                         "%% Changes will be applied when exiting this config block\n");
     137             : 
     138           0 :         cfg->reconf_dst = true;
     139           0 :         return CMD_SUCCESS;
     140             : }
     141             : 
     142           0 : static int reconf_meta(struct zlog_cfg_5424_user *cfg, struct vty *vty)
     143             : {
     144           0 :         if (!cfg->reconf_dst && !cfg->reconf_meta && vty->type != VTY_FILE)
     145           0 :                 vty_out(vty,
     146             :                         "%% Changes will be applied when exiting this config block\n");
     147             : 
     148           0 :         cfg->reconf_meta = true;
     149           0 :         return CMD_SUCCESS;
     150             : }
     151             : 
     152           0 : static int reconf_clear_dst(struct zlog_cfg_5424_user *cfg, struct vty *vty)
     153             : {
     154           0 :         if (cfg->cfg.dst == ZLOG_5424_DST_NONE)
     155             :                 return CMD_SUCCESS;
     156             : 
     157           0 :         clear_dst(cfg);
     158           0 :         return reconf_dst(cfg, vty);
     159             : }
     160             : 
     161             : #include "lib/zlog_5424_cli_clippy.c"
     162             : 
     163           0 : DEFPY_NOSH(log_5424_target,
     164             :            log_5424_target_cmd,
     165             :            "log extended-syslog EXTLOGNAME",
     166             :            "Logging control\n"
     167             :            "Extended RFC5424 syslog (including file targets)\n"
     168             :            "Name identifying this syslog target\n")
     169             : {
     170           0 :         struct zlog_cfg_5424_user *cfg, ref;
     171             : 
     172           0 :         ref.name = (char *)extlogname;
     173           0 :         cfg = targets_find(&targets, &ref);
     174             : 
     175           0 :         if (!cfg)
     176           0 :                 cfg = log_5424_alloc(extlogname);
     177             : 
     178           0 :         VTY_PUSH_CONTEXT(EXTLOG_NODE, cfg);
     179           0 :         return CMD_SUCCESS;
     180             : }
     181             : 
     182           0 : DEFPY(no_log_5424_target,
     183             :       no_log_5424_target_cmd,
     184             :       "no log extended-syslog EXTLOGNAME",
     185             :       NO_STR
     186             :       "Logging control\n"
     187             :       "Extended RFC5424 syslog (including file targets)\n"
     188             :       "Name identifying this syslog target\n")
     189             : {
     190           0 :         struct zlog_cfg_5424_user *cfg, ref;
     191             : 
     192           0 :         ref.name = (char *)extlogname;
     193           0 :         cfg = targets_find(&targets, &ref);
     194             : 
     195           0 :         if (!cfg) {
     196           0 :                 vty_out(vty, "%% No extended syslog target named \"%s\"\n",
     197             :                         extlogname);
     198           0 :                 return CMD_WARNING;
     199             :         }
     200             : 
     201           0 :         log_5424_free(cfg, false);
     202           0 :         return CMD_SUCCESS;
     203             : }
     204             : 
     205             : /*    "format <rfc3164|rfc5424|local-syslogd|journald>$fmt" */
     206             : #define FORMAT_HELP                                                            \
     207             :         "Select log message formatting\n"                                      \
     208             :         "RFC3164 (legacy) syslog\n"                                            \
     209             :         "RFC5424 (modern) syslog, supports structured data (default)\n"        \
     210             :         "modified RFC3164 without hostname for local syslogd (/dev/log)\n"     \
     211             :         "journald (systemd log) native format\n"                               \
     212             :         /* end */
     213             : 
     214           0 : static enum zlog_5424_format log_5424_fmt(const char *fmt,
     215             :                                           enum zlog_5424_format dflt)
     216             : {
     217           0 :         if (!fmt)
     218             :                 return dflt;
     219           0 :         else if (!strcmp(fmt, "rfc5424"))
     220             :                 return ZLOG_FMT_5424;
     221           0 :         else if (!strcmp(fmt, "rfc3164"))
     222             :                 return ZLOG_FMT_3164;
     223           0 :         else if (!strcmp(fmt, "local-syslogd"))
     224             :                 return ZLOG_FMT_LOCAL;
     225           0 :         else if (!strcmp(fmt, "journald"))
     226           0 :                 return ZLOG_FMT_JOURNALD;
     227             : 
     228             :         return dflt;
     229             : }
     230             : 
     231           0 : DEFPY(log_5424_destination_file,
     232             :       log_5424_destination_file_cmd,
     233             :       "[no] destination file$type PATH "
     234             :                 "[create$create [{user WORD|group WORD|mode PERMS}]"
     235             :                 "|no-create$nocreate] "
     236             :                 "[format <rfc3164|rfc5424|local-syslogd|journald>$fmt]",
     237             :       NO_STR
     238             :       "Log destination setup\n"
     239             :       "Log to file\n"
     240             :       "Path to destination\n"
     241             :       "Create file if it does not exist\n"
     242             :       "Set file owner\n"
     243             :       "User name\n"
     244             :       "Set file group\n"
     245             :       "Group name\n"
     246             :       "Set permissions\n"
     247             :       "File permissions (octal)\n"
     248             :       "Do not create file if it does not exist\n"
     249             :       FORMAT_HELP)
     250             : {
     251           0 :         VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user, cfg);
     252           0 :         enum zlog_5424_dst dst;
     253           0 :         bool reconf = true, warn_perm = false;
     254           0 :         char *prev_user, *prev_group;
     255           0 :         mode_t perm_val = LOGFILE_MASK & 0666;
     256           0 :         enum zlog_5424_format fmtv;
     257             : 
     258           0 :         if (no)
     259           0 :                 return reconf_clear_dst(cfg, vty);
     260             : 
     261           0 :         fmtv = log_5424_fmt(fmt, ZLOG_FMT_5424);
     262             : 
     263           0 :         if (perms) {
     264           0 :                 char *errp = (char *)perms;
     265             : 
     266           0 :                 perm_val = strtoul(perms, &errp, 8);
     267           0 :                 if (*errp || errp == perms || perm_val == 0 ||
     268           0 :                     (perm_val & ~0666)) {
     269           0 :                         vty_out(vty, "%% Invalid permissions value \"%s\"\n",
     270             :                                 perms);
     271           0 :                         return CMD_WARNING;
     272             :                 }
     273             :         }
     274             : 
     275           0 :         dst = (strcmp(type, "fifo") == 0) ? ZLOG_5424_DST_FIFO
     276           0 :                                           : ZLOG_5424_DST_FILE;
     277             : 
     278           0 :         if (cfg->filename && !strcmp(path, cfg->filename) &&
     279           0 :             dst == cfg->cfg.dst && cfg->cfg.active && cfg->cfg.fmt == fmtv)
     280           0 :                 reconf = false;
     281             : 
     282             :         /* keep for compare below */
     283           0 :         prev_user = cfg->file_user;
     284           0 :         prev_group = cfg->file_group;
     285           0 :         cfg->file_user = NULL;
     286           0 :         cfg->file_group = NULL;
     287             : 
     288           0 :         clear_dst(cfg);
     289             : 
     290           0 :         cfg->filename = XSTRDUP(MTYPE_LOG_5424_DATA, path);
     291           0 :         cfg->cfg.dst = dst;
     292           0 :         cfg->cfg.filename = cfg->filename;
     293           0 :         cfg->cfg.fmt = fmtv;
     294             : 
     295           0 :         if (nocreate)
     296           0 :                 cfg->cfg.file_nocreate = true;
     297             :         else {
     298           0 :                 if (user) {
     299           0 :                         struct passwd *pwent;
     300             : 
     301           0 :                         warn_perm |= (prev_user && strcmp(user, prev_user));
     302           0 :                         cfg->file_user = XSTRDUP(MTYPE_LOG_5424_DATA, user);
     303             : 
     304           0 :                         errno = 0;
     305           0 :                         pwent = getpwnam(user);
     306           0 :                         if (!pwent)
     307           0 :                                 vty_out(vty,
     308             :                                         "%% Could not look up user \"%s\" (%s), file owner will be left untouched!\n",
     309             :                                         user,
     310           0 :                                         errno ? safe_strerror(errno)
     311             :                                               : "No entry by this user name");
     312             :                         else
     313           0 :                                 cfg->cfg.file_uid = pwent->pw_uid;
     314             :                 }
     315           0 :                 if (group) {
     316           0 :                         struct group *grent;
     317             : 
     318           0 :                         warn_perm |= (prev_group && strcmp(group, prev_group));
     319           0 :                         cfg->file_group = XSTRDUP(MTYPE_LOG_5424_DATA, group);
     320             : 
     321           0 :                         errno = 0;
     322           0 :                         grent = getgrnam(group);
     323           0 :                         if (!grent)
     324           0 :                                 vty_out(vty,
     325             :                                         "%% Could not look up group \"%s\" (%s), file group will be left untouched!\n",
     326             :                                         group,
     327           0 :                                         errno ? safe_strerror(errno)
     328             :                                               : "No entry by this group name");
     329             :                         else
     330           0 :                                 cfg->cfg.file_gid = grent->gr_gid;
     331             :                 }
     332             :         }
     333           0 :         XFREE(MTYPE_LOG_5424_DATA, prev_user);
     334           0 :         XFREE(MTYPE_LOG_5424_DATA, prev_group);
     335             : 
     336           0 :         if (cfg->cfg.file_uid != (uid_t)-1 || cfg->cfg.file_gid != (gid_t)-1) {
     337           0 :                 struct stat st;
     338             : 
     339           0 :                 if (stat(cfg->filename, &st) == 0) {
     340           0 :                         warn_perm |= (st.st_uid != cfg->cfg.file_uid);
     341           0 :                         warn_perm |= (st.st_gid != cfg->cfg.file_gid);
     342             :                 }
     343             :         }
     344           0 :         if (warn_perm)
     345           0 :                 vty_out(vty,
     346             :                         "%% Warning: ownership and permission bits are only applied when creating\n"
     347             :                         "%%          log files.  Use system tools to change existing files.\n"
     348             :                         "%%          FRR may also be missing necessary privileges to set these.\n");
     349             : 
     350           0 :         if (reconf)
     351           0 :                 return reconf_dst(cfg, vty);
     352             : 
     353             :         return CMD_SUCCESS;
     354             : }
     355             : 
     356             : /* FIFOs are for legacy /dev/log implementations;  using this is very much not
     357             :  * recommended since it can unexpectedly block in logging calls.  Also the fd
     358             :  * would need to be reopened when the process at the other end restarts.  None
     359             :  * of this is handled - use at your own caution.  It's _HIDDEN for a purpose.
     360             :  */
     361             : ALIAS_HIDDEN(log_5424_destination_file,
     362             :              log_5424_destination_fifo_cmd,
     363             :       "[no] destination fifo$type PATH "
     364             :                 "[create$create [{owner WORD|group WORD|permissions PERMS}]"
     365             :                 "|no-create$nocreate] "
     366             :                 "[format <rfc3164|rfc5424|local-syslogd|journald>$fmt]",
     367             :       NO_STR
     368             :       "Log destination setup\n"
     369             :       "Log to filesystem FIFO\n"
     370             :       "Path to destination\n"
     371             :       "Create file if it does not exist\n"
     372             :       "Set file owner\n"
     373             :       "User name\n"
     374             :       "Set file group\n"
     375             :       "Group name\n"
     376             :       "Set permissions\n"
     377             :       "File permissions (octal)\n"
     378             :       "Do not create file if it does not exist\n"
     379             :       FORMAT_HELP)
     380             : 
     381           0 : static int dst_unix(struct vty *vty, const char *no, const char *path,
     382             :                     enum zlog_5424_format fmt, enum unix_special special)
     383             : {
     384           0 :         VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user, cfg);
     385             : 
     386           0 :         if (no)
     387           0 :                 return reconf_clear_dst(cfg, vty);
     388             : 
     389           0 :         cfg->unix_special = special;
     390             : 
     391           0 :         if (cfg->cfg.dst == ZLOG_5424_DST_UNIX && cfg->filename &&
     392           0 :             !strcmp(path, cfg->filename) && cfg->cfg.active &&
     393           0 :             cfg->cfg.fmt == fmt)
     394             :                 return CMD_SUCCESS;
     395             : 
     396           0 :         clear_dst(cfg);
     397             : 
     398           0 :         cfg->filename = XSTRDUP(MTYPE_LOG_5424_DATA, path);
     399           0 :         cfg->cfg.dst = ZLOG_5424_DST_UNIX;
     400           0 :         cfg->cfg.filename = cfg->filename;
     401           0 :         cfg->cfg.fmt = fmt;
     402             : 
     403           0 :         cfg->cfg.reconn_backoff = 25;
     404           0 :         cfg->cfg.reconn_backoff_cur = 25;
     405           0 :         cfg->cfg.reconn_backoff_max = 10000;
     406           0 :         return reconf_dst(cfg, vty);
     407             : }
     408             : 
     409           0 : DEFPY(log_5424_destination_unix,
     410             :       log_5424_destination_unix_cmd,
     411             :       "[no] destination unix PATH "
     412             :                  "[format <rfc3164|rfc5424|local-syslogd|journald>$fmt]",
     413             :       NO_STR
     414             :       "Log destination setup\n"
     415             :       "Log to unix socket\n"
     416             :       "Unix socket path\n"
     417             :       FORMAT_HELP)
     418             : {
     419           0 :         VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user, cfg);
     420           0 :         enum zlog_5424_format fmtv = log_5424_fmt(fmt, ZLOG_FMT_5424);
     421             : 
     422           0 :         return dst_unix(vty, no, path, fmtv, SPECIAL_NONE);
     423             : }
     424             : 
     425           0 : DEFPY(log_5424_destination_journald,
     426             :       log_5424_destination_journald_cmd,
     427             :       "[no] destination journald",
     428             :       NO_STR
     429             :       "Log destination setup\n"
     430             :       "Log directly to systemd's journald\n")
     431             : {
     432           0 :         return dst_unix(vty, no, "/run/systemd/journal/socket",
     433             :                         ZLOG_FMT_JOURNALD, SPECIAL_JOURNALD);
     434             : }
     435             : 
     436             : #if defined(__FreeBSD_version) && (__FreeBSD_version >= 1200061)
     437             : #define ZLOG_FMT_DEV_LOG        ZLOG_FMT_5424
     438             : #elif defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 500000000)
     439             : #define ZLOG_FMT_DEV_LOG        ZLOG_FMT_5424
     440             : #else
     441             : #define ZLOG_FMT_DEV_LOG        ZLOG_FMT_LOCAL
     442             : #endif
     443             : 
     444           0 : DEFPY(log_5424_destination_syslog,
     445             :       log_5424_destination_syslog_cmd,
     446             :       "[no] destination syslog [supports-rfc5424]$supp5424",
     447             :       NO_STR
     448             :       "Log destination setup\n"
     449             :       "Log directly to syslog\n"
     450             :       "Use RFC5424 format (please refer to documentation)\n")
     451             : {
     452           0 :         int format = supp5424 ? ZLOG_FMT_5424 : ZLOG_FMT_DEV_LOG;
     453             : 
     454             :         /* unfortunately, there is no way to detect 5424 support */
     455           0 :         return dst_unix(vty, no, "/dev/log", format, SPECIAL_SYSLOG);
     456             : }
     457             : 
     458             : /* could add something like
     459             :  *   "destination <udp|tcp>$proto <A.B.C.D|X:X::X:X> (1-65535)$port"
     460             :  * here, but there are 2 reasons not to do that:
     461             :  *
     462             :  *  - each FRR daemon would open its own connection, there's no system level
     463             :  *    aggregation.  That's the system's syslogd's job.  It likely also
     464             :  *    supports directing & filtering log messages with configurable rules.
     465             :  *  - we're likely not going to support DTLS or TLS for more secure logging;
     466             :  *    adding this would require a considerable amount of additional config
     467             :  *    and an entire TLS library to begin with.  A proper syslogd implements
     468             :  *    all of this, why reinvent the wheel?
     469             :  */
     470             : 
     471           0 : DEFPY(log_5424_destination_fd,
     472             :       log_5424_destination_fd_cmd,
     473             :       "[no] destination <fd <(0-63)$fd|envvar WORD>|stdout$fd1|stderr$fd2>"
     474             :                  "[format <rfc3164|rfc5424|local-syslogd|journald>$fmt]",
     475             :       NO_STR
     476             :       "Log destination setup\n"
     477             :       "Log to pre-opened file descriptor\n"
     478             :       "File descriptor number (must be open at startup)\n"
     479             :       "Read file descriptor number from environment variable\n"
     480             :       "Environment variable name\n"
     481             :       "Log to standard output\n"
     482             :       "Log to standard error output\n"
     483             :       FORMAT_HELP)
     484             : {
     485           0 :         VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user, cfg);
     486           0 :         bool envvar_problem = false;
     487           0 :         enum zlog_5424_format fmtv;
     488             : 
     489           0 :         if (no)
     490           0 :                 return reconf_clear_dst(cfg, vty);
     491             : 
     492           0 :         fmtv = log_5424_fmt(fmt, ZLOG_FMT_5424);
     493             : 
     494           0 :         if (envvar) {
     495           0 :                 char *envval;
     496             : 
     497           0 :                 envval = getenv(envvar);
     498           0 :                 if (!envval)
     499             :                         envvar_problem = true;
     500             :                 else {
     501           0 :                         char *errp = envval;
     502             : 
     503           0 :                         fd = strtoul(envval, &errp, 0);
     504           0 :                         if (errp == envval || *errp)
     505           0 :                                 envvar_problem = true;
     506             :                 }
     507             : 
     508           0 :                 if (envvar_problem)
     509             :                         fd = -1;
     510           0 :         } else if (fd1)
     511             :                 fd = 1;
     512           0 :         else if (fd2)
     513           0 :                 fd = 2;
     514             : 
     515           0 :         if (cfg->cfg.dst == ZLOG_5424_DST_FD && cfg->cfg.fd == fd &&
     516           0 :             cfg->cfg.active && cfg->cfg.fmt == fmtv)
     517             :                 return CMD_SUCCESS;
     518             : 
     519           0 :         clear_dst(cfg);
     520             : 
     521           0 :         cfg->cfg.dst = ZLOG_5424_DST_FD;
     522           0 :         cfg->cfg.fd = fd;
     523           0 :         cfg->cfg.fmt = fmtv;
     524           0 :         if (envvar)
     525           0 :                 cfg->envvar = XSTRDUP(MTYPE_LOG_5424_DATA, envvar);
     526             : 
     527           0 :         if (envvar_problem)
     528           0 :                 vty_out(vty,
     529             :                         "%% environment variable \"%s\" not present or invalid.\n",
     530             :                         envvar);
     531           0 :         if (!frr_is_startup_fd(fd))
     532           0 :                 vty_out(vty,
     533             :                         "%% file descriptor %d was not open when this process was started\n",
     534             :                         (int)fd);
     535           0 :         if (envvar_problem || !frr_is_startup_fd(fd))
     536           0 :                 vty_out(vty,
     537             :                         "%% configuration will be saved but has no effect currently\n");
     538             : 
     539           0 :         return reconf_dst(cfg, vty);
     540             : }
     541             : 
     542           0 : DEFPY(log_5424_destination_none,
     543             :       log_5424_destination_none_cmd,
     544             :       "[no] destination [none]",
     545             :       NO_STR
     546             :       "Log destination setup\n"
     547             :       "Deconfigure destination\n")
     548             : {
     549           0 :         VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user, cfg);
     550             : 
     551           0 :         return reconf_clear_dst(cfg, vty);
     552             : }
     553             : 
     554             : /* end of destinations */
     555             : 
     556           0 : DEFPY(log_5424_prio,
     557             :       log_5424_prio_cmd,
     558             :       "[no] priority <emergencies|alerts|critical|errors|warnings|notifications|informational|debugging>$levelarg",
     559             :       NO_STR
     560             :       "Set minimum message priority to include for this target\n"
     561             :       LOG_LEVEL_DESC)
     562             : {
     563           0 :         VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user, cfg);
     564           0 :         int prio_min = log_level_match(levelarg);
     565             : 
     566           0 :         if (prio_min == cfg->cfg.prio_min)
     567             :                 return CMD_SUCCESS;
     568             : 
     569           0 :         cfg->cfg.prio_min = prio_min;
     570           0 :         return reconf_meta(cfg, vty);
     571             : }
     572             : 
     573           0 : DEFPY(log_5424_facility,
     574             :       log_5424_facility_cmd,
     575             :       "[no] facility <kern|user|mail|daemon|auth|syslog|lpr|news|uucp|cron|local0|local1|local2|local3|local4|local5|local6|local7>$facilityarg",
     576             :       NO_STR
     577             :       "Set syslog facility to use\n"
     578             :       LOG_FACILITY_DESC)
     579             : {
     580           0 :         VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user, cfg);
     581           0 :         int facility = facility_match(facilityarg);
     582             : 
     583           0 :         if (cfg->cfg.facility == facility)
     584             :                 return CMD_SUCCESS;
     585             : 
     586           0 :         cfg->cfg.facility = facility;
     587           0 :         return reconf_meta(cfg, vty);
     588             : }
     589             : 
     590           0 : DEFPY(log_5424_meta,
     591             :       log_5424_meta_cmd,
     592             :       "[no] structured-data <code-location|version|unique-id|error-category|format-args>$option",
     593             :       NO_STR
     594             :       "Select structured data (key/value pairs) to include in each message\n"
     595             :       "FRR source code location\n"
     596             :       "FRR version\n"
     597             :       "Unique message identifier (XXXXX-XXXXX)\n"
     598             :       "Error category (EC numeric)\n"
     599             :       "Individual formatted log message arguments\n")
     600             : {
     601           0 :         VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user, cfg);
     602           0 :         bool val = !no, *ptr;
     603           0 :         struct log_option *opt = log_opts;
     604             : 
     605           0 :         while (opt->name && strcmp(opt->name, option))
     606           0 :                 opt++;
     607           0 :         if (!opt->name)
     608             :                 return CMD_WARNING;
     609             : 
     610           0 :         ptr = (bool *)(((char *)&cfg->cfg) + opt->offs);
     611           0 :         if (*ptr == val)
     612             :                 return CMD_SUCCESS;
     613             : 
     614           0 :         *ptr = val;
     615           0 :         return reconf_meta(cfg, vty);
     616             : }
     617             : 
     618           0 : DEFPY(log_5424_ts_prec,
     619             :       log_5424_ts_prec_cmd,
     620             :       "[no] timestamp precision (0-9)",
     621             :       NO_STR
     622             :       "Timestamp options\n"
     623             :       "Number of sub-second digits to include\n"
     624             :       "Number of sub-second digits to include\n")
     625             : {
     626           0 :         VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user, cfg);
     627           0 :         uint32_t ts_flags = cfg->cfg.ts_flags;
     628             : 
     629           0 :         ts_flags &= ~ZLOG_TS_PREC;
     630           0 :         if (no)
     631           0 :                 ts_flags |= DFLT_TS_FLAGS & ZLOG_TS_PREC;
     632             :         else
     633           0 :                 ts_flags |= precision;
     634             : 
     635           0 :         if (ts_flags == cfg->cfg.ts_flags)
     636             :                 return CMD_SUCCESS;
     637             : 
     638           0 :         cfg->cfg.ts_flags = ts_flags;
     639           0 :         return reconf_meta(cfg, vty);
     640             : }
     641             : 
     642           0 : DEFPY(log_5424_ts_local,
     643             :       log_5424_ts_local_cmd,
     644             :       "[no] timestamp local-time",
     645             :       NO_STR
     646             :       "Timestamp options\n"
     647             :       "Use local system time zone rather than UTC\n")
     648             : {
     649           0 :         VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user, cfg);
     650           0 :         uint32_t ts_flags = cfg->cfg.ts_flags;
     651             : 
     652           0 :         ts_flags &= ~ZLOG_TS_UTC;
     653           0 :         if (no)
     654           0 :                 ts_flags |= DFLT_TS_FLAGS & ZLOG_TS_UTC;
     655             :         else
     656             :                 ts_flags |= (~DFLT_TS_FLAGS) & ZLOG_TS_UTC;
     657             : 
     658           0 :         if (ts_flags == cfg->cfg.ts_flags)
     659             :                 return CMD_SUCCESS;
     660             : 
     661           0 :         cfg->cfg.ts_flags = ts_flags;
     662           0 :         return reconf_meta(cfg, vty);
     663             : }
     664             : 
     665           0 : static int log_5424_node_exit(struct vty *vty)
     666             : {
     667           0 :         VTY_DECLVAR_CONTEXT(zlog_cfg_5424_user, cfg);
     668             : 
     669           0 :         if ((cfg->reconf_dst || cfg->reconf_meta) && vty->type != VTY_FILE)
     670           0 :                 vty_out(vty, "%% applying changes.\n");
     671             : 
     672           0 :         if (cfg->reconf_dst)
     673           0 :                 zlog_5424_apply_dst(&cfg->cfg);
     674           0 :         else if (cfg->reconf_meta)
     675           0 :                 zlog_5424_apply_meta(&cfg->cfg);
     676             : 
     677           0 :         cfg->reconf_dst = cfg->reconf_meta = false;
     678           0 :         return 1;
     679             : }
     680             : 
     681           0 : static int log_5424_config_write(struct vty *vty)
     682             : {
     683           0 :         struct zlog_cfg_5424_user *cfg;
     684             : 
     685           0 :         frr_each (targets, &targets, cfg) {
     686           0 :                 const char *fmt_str = "";
     687             : 
     688           0 :                 vty_out(vty, "log extended %s\n", cfg->name);
     689             : 
     690           0 :                 switch (cfg->cfg.fmt) {
     691           0 :                 case ZLOG_FMT_5424:
     692           0 :                         fmt_str = " format rfc5424";
     693           0 :                         break;
     694           0 :                 case ZLOG_FMT_3164:
     695           0 :                         fmt_str = " format rfc3164";
     696           0 :                         break;
     697           0 :                 case ZLOG_FMT_LOCAL:
     698           0 :                         fmt_str = " format local-syslogd";
     699           0 :                         break;
     700           0 :                 case ZLOG_FMT_JOURNALD:
     701           0 :                         fmt_str = " format journald";
     702           0 :                         break;
     703             :                 }
     704             : 
     705           0 :                 switch (cfg->cfg.dst) {
     706           0 :                 case ZLOG_5424_DST_NONE:
     707           0 :                         vty_out(vty, " ! no destination configured\n");
     708           0 :                         break;
     709             : 
     710           0 :                 case ZLOG_5424_DST_FD:
     711           0 :                         if (cfg->cfg.fmt == ZLOG_FMT_5424)
     712           0 :                                 fmt_str = "";
     713             : 
     714           0 :                         if (cfg->envvar)
     715           0 :                                 vty_out(vty, " destination fd envvar %s%s\n",
     716             :                                         cfg->envvar, fmt_str);
     717           0 :                         else if (cfg->cfg.fd == 1)
     718           0 :                                 vty_out(vty, " destination stdout%s\n",
     719             :                                         fmt_str);
     720           0 :                         else if (cfg->cfg.fd == 2)
     721           0 :                                 vty_out(vty, " destination stderr%s\n",
     722             :                                         fmt_str);
     723             :                         else
     724           0 :                                 vty_out(vty, " destination fd %d%s\n",
     725             :                                         cfg->cfg.fd, fmt_str);
     726             :                         break;
     727             : 
     728           0 :                 case ZLOG_5424_DST_FILE:
     729             :                 case ZLOG_5424_DST_FIFO:
     730           0 :                         if (cfg->cfg.fmt == ZLOG_FMT_5424)
     731           0 :                                 fmt_str = "";
     732             : 
     733           0 :                         vty_out(vty, " destination %s %s",
     734             :                                 (cfg->cfg.dst == ZLOG_5424_DST_FIFO) ? "fifo"
     735             :                                                                      : "file",
     736             :                                 cfg->filename);
     737             : 
     738           0 :                         if (cfg->cfg.file_nocreate)
     739           0 :                                 vty_out(vty, " no-create");
     740           0 :                         else if (cfg->file_user || cfg->file_group ||
     741           0 :                                  cfg->cfg.file_mode != (LOGFILE_MASK & 0666)) {
     742           0 :                                 vty_out(vty, " create");
     743             : 
     744           0 :                                 if (cfg->file_user)
     745           0 :                                         vty_out(vty, " user %s",
     746             :                                                 cfg->file_user);
     747           0 :                                 if (cfg->file_group)
     748           0 :                                         vty_out(vty, " group %s",
     749             :                                                 cfg->file_group);
     750           0 :                                 if (cfg->cfg.file_mode != (LOGFILE_MASK & 0666))
     751           0 :                                         vty_out(vty, " mode %04o",
     752             :                                                 cfg->cfg.file_mode);
     753             :                         }
     754           0 :                         vty_out(vty, "%s\n", fmt_str);
     755           0 :                         break;
     756             : 
     757           0 :                 case ZLOG_5424_DST_UNIX:
     758           0 :                         switch (cfg->unix_special) {
     759           0 :                         case SPECIAL_NONE:
     760           0 :                                 vty_out(vty, " destination unix %s%s\n",
     761             :                                         cfg->filename, fmt_str);
     762           0 :                                 break;
     763           0 :                         case SPECIAL_SYSLOG:
     764           0 :                                 if (cfg->cfg.fmt == ZLOG_FMT_DEV_LOG)
     765           0 :                                         vty_out(vty, " destination syslog\n");
     766             :                                 else
     767           0 :                                         vty_out(vty,
     768             :                                                 " destination syslog supports-rfc5424\n");
     769             :                                 break;
     770           0 :                         case SPECIAL_JOURNALD:
     771           0 :                                 vty_out(vty, " destination journald\n");
     772           0 :                                 break;
     773             :                         }
     774             :                         break;
     775             :                 }
     776             : 
     777           0 :                 if (cfg->cfg.prio_min != LOG_DEBUG)
     778           0 :                         vty_out(vty, " priority %s\n",
     779             :                                 zlog_priority_str(cfg->cfg.prio_min));
     780           0 :                 if (cfg->cfg.facility != DFLT_FACILITY)
     781           0 :                         vty_out(vty, " facility %s\n",
     782             :                                 facility_name(cfg->cfg.facility));
     783             : 
     784           0 :                 for (struct log_option *opt = log_opts; opt->name; opt++) {
     785           0 :                         bool *ptr = (bool *)(((char *)&cfg->cfg) + opt->offs);
     786             : 
     787           0 :                         if (*ptr != opt->dflt)
     788           0 :                                 vty_out(vty, " %sstructured-data %s\n",
     789             :                                         *ptr ? "" : "no ", opt->name);
     790             :                 }
     791             : 
     792           0 :                 if ((cfg->cfg.ts_flags ^ DFLT_TS_FLAGS) & ZLOG_TS_PREC)
     793           0 :                         vty_out(vty, " timestamp precision %u\n",
     794             :                                 cfg->cfg.ts_flags & ZLOG_TS_PREC);
     795             : 
     796           0 :                 if ((cfg->cfg.ts_flags ^ DFLT_TS_FLAGS) & ZLOG_TS_UTC) {
     797           0 :                         if (cfg->cfg.ts_flags & ZLOG_TS_UTC)
     798           0 :                                 vty_out(vty, " no timestamp local-time\n");
     799             :                         else
     800           0 :                                 vty_out(vty, " timestamp local-time\n");
     801             :                 }
     802             : 
     803           0 :                 vty_out(vty, "!\n");
     804             :         }
     805           0 :         return 0;
     806             : }
     807             : 
     808           0 : static int log_5424_show(struct vty *vty)
     809             : {
     810           0 :         struct zlog_cfg_5424_user *cfg;
     811             : 
     812           0 :         frr_each (targets, &targets, cfg) {
     813           0 :                 vty_out(vty, "\nExtended log target %pSQq\n", cfg->name);
     814             : 
     815           0 :                 switch (cfg->cfg.dst) {
     816           0 :                 case ZLOG_5424_DST_NONE:
     817           0 :                         vty_out(vty,
     818             :                                 "  Inactive (no destination configured)\n");
     819           0 :                         break;
     820             : 
     821           0 :                 case ZLOG_5424_DST_FD:
     822           0 :                         if (cfg->envvar)
     823           0 :                                 vty_out(vty,
     824             :                                         "  logging to fd %d from environment variable %pSE\n",
     825             :                                         cfg->cfg.fd, cfg->envvar);
     826           0 :                         else if (cfg->cfg.fd == 1)
     827           0 :                                 vty_out(vty, "  logging to stdout\n");
     828           0 :                         else if (cfg->cfg.fd == 2)
     829           0 :                                 vty_out(vty, "  logging to stderr\n");
     830             :                         else
     831           0 :                                 vty_out(vty, "  logging to fd %d\n",
     832             :                                         cfg->cfg.fd);
     833             :                         break;
     834             : 
     835           0 :                 case ZLOG_5424_DST_FILE:
     836             :                 case ZLOG_5424_DST_FIFO:
     837             :                 case ZLOG_5424_DST_UNIX:
     838           0 :                         vty_out(vty, "  logging to %s: %pSE\n",
     839             :                                 (cfg->cfg.dst == ZLOG_5424_DST_FIFO) ? "fifo"
     840             :                                 : (cfg->cfg.dst == ZLOG_5424_DST_UNIX)
     841             :                                         ? "unix socket"
     842           0 :                                         : "file",
     843             :                                 cfg->filename);
     844           0 :                         break;
     845             :                 }
     846             : 
     847           0 :                 vty_out(vty, "  log level: %s, facility: %s\n",
     848             :                         zlog_priority_str(cfg->cfg.prio_min),
     849             :                         facility_name(cfg->cfg.facility));
     850             : 
     851           0 :                 bool any_meta = false, first = true;
     852             : 
     853           0 :                 for (struct log_option *opt = log_opts; opt->name; opt++) {
     854           0 :                         bool *ptr = (bool *)(((char *)&cfg->cfg) + opt->offs);
     855             : 
     856           0 :                         any_meta |= *ptr;
     857             :                 }
     858             : 
     859           0 :                 if (!any_meta)
     860           0 :                         continue;
     861             : 
     862           0 :                 switch (cfg->cfg.fmt) {
     863           0 :                 case ZLOG_FMT_5424:
     864             :                 case ZLOG_FMT_JOURNALD:
     865           0 :                         vty_out(vty, "  structured data: ");
     866             : 
     867           0 :                         for (struct log_option *opt = log_opts; opt->name;
     868           0 :                              opt++) {
     869           0 :                                 bool *ptr = (bool *)(((char *)&cfg->cfg) +
     870           0 :                                                      opt->offs);
     871             : 
     872           0 :                                 if (*ptr) {
     873           0 :                                         vty_out(vty, "%s%s", first ? "" : ", ",
     874             :                                                 opt->name);
     875           0 :                                         first = false;
     876             :                                 }
     877             :                         }
     878             :                         break;
     879             : 
     880           0 :                 case ZLOG_FMT_3164:
     881             :                 case ZLOG_FMT_LOCAL:
     882           0 :                         vty_out(vty,
     883             :                                 "  structured data is not supported by the selected format\n");
     884           0 :                         break;
     885             :                 }
     886             : 
     887           0 :                 vty_out(vty, "\n");
     888             : 
     889           0 :                 size_t lost_msgs;
     890           0 :                 int last_errno;
     891           0 :                 bool stale_errno;
     892           0 :                 struct timeval err_ts;
     893           0 :                 int64_t since;
     894             : 
     895           0 :                 zlog_5424_state(&cfg->cfg, &lost_msgs, &last_errno,
     896             :                                 &stale_errno, &err_ts);
     897           0 :                 vty_out(vty, "  number of lost messages: %zu\n", lost_msgs);
     898             : 
     899           0 :                 if (last_errno == 0)
     900             :                         since = 0;
     901             :                 else
     902           0 :                         since = monotime_since(&err_ts, NULL);
     903           0 :                 vty_out(vty,
     904             :                         "  last error: %s (%lld.%06llds ago, currently %s)\n",
     905           0 :                         last_errno ? safe_strerror(last_errno) : "none",
     906             :                         since / 1000000LL, since % 1000000LL,
     907           0 :                         stale_errno ? "OK" : "erroring");
     908             :         }
     909           0 :         return 0;
     910             : }
     911             : 
     912             : static struct cmd_node extlog_node = {
     913             :         .name = "extended",
     914             :         .node = EXTLOG_NODE,
     915             :         .parent_node = CONFIG_NODE,
     916             :         .prompt = "%s(config-ext-log)# ",
     917             : 
     918             :         .config_write = log_5424_config_write,
     919             :         .node_exit = log_5424_node_exit,
     920             : };
     921             : 
     922           0 : static void log_5424_autocomplete(vector comps, struct cmd_token *token)
     923             : {
     924           0 :         struct zlog_cfg_5424_user *cfg;
     925             : 
     926           0 :         frr_each (targets, &targets, cfg)
     927           0 :                 vector_set(comps, XSTRDUP(MTYPE_COMPLETION, cfg->name));
     928           0 : }
     929             : 
     930             : static const struct cmd_variable_handler log_5424_var_handlers[] = {
     931             :         {.tokenname = "EXTLOGNAME", .completions = log_5424_autocomplete},
     932             :         {.completions = NULL},
     933             : };
     934             : 
     935          16 : void log_5424_cmd_init(void)
     936             : {
     937          16 :         hook_register(zlog_cli_show, log_5424_show);
     938             : 
     939          16 :         cmd_variable_handler_register(log_5424_var_handlers);
     940             : 
     941             :         /* CLI commands. */
     942          16 :         install_node(&extlog_node);
     943          16 :         install_default(EXTLOG_NODE);
     944             : 
     945          16 :         install_element(CONFIG_NODE, &log_5424_target_cmd);
     946          16 :         install_element(CONFIG_NODE, &no_log_5424_target_cmd);
     947             : 
     948          16 :         install_element(EXTLOG_NODE, &log_5424_destination_file_cmd);
     949          16 :         install_element(EXTLOG_NODE, &log_5424_destination_fifo_cmd);
     950          16 :         install_element(EXTLOG_NODE, &log_5424_destination_unix_cmd);
     951          16 :         install_element(EXTLOG_NODE, &log_5424_destination_journald_cmd);
     952          16 :         install_element(EXTLOG_NODE, &log_5424_destination_syslog_cmd);
     953          16 :         install_element(EXTLOG_NODE, &log_5424_destination_fd_cmd);
     954             : 
     955          16 :         install_element(EXTLOG_NODE, &log_5424_meta_cmd);
     956          16 :         install_element(EXTLOG_NODE, &log_5424_prio_cmd);
     957          16 :         install_element(EXTLOG_NODE, &log_5424_facility_cmd);
     958          16 :         install_element(EXTLOG_NODE, &log_5424_ts_prec_cmd);
     959          16 :         install_element(EXTLOG_NODE, &log_5424_ts_local_cmd);
     960          16 : }
     961             : 
     962             : /* hooks */
     963             : 
     964             : static int log_5424_early_init(struct thread_master *master);
     965             : static int log_5424_rotate(void);
     966             : static int log_5424_fini(void);
     967             : 
     968          16 : __attribute__((_CONSTRUCTOR(475))) static void zlog_5424_startup_init(void)
     969             : {
     970          16 :         hook_register(frr_early_init, log_5424_early_init);
     971          16 :         hook_register(zlog_rotate, log_5424_rotate);
     972          16 :         hook_register(frr_fini, log_5424_fini);
     973          16 : }
     974             : 
     975          16 : static int log_5424_early_init(struct thread_master *master)
     976             : {
     977          16 :         log_5424_master = master;
     978             : 
     979          16 :         return 0;
     980             : }
     981             : 
     982           0 : static int log_5424_rotate(void)
     983             : {
     984           0 :         struct zlog_cfg_5424_user *cfg;
     985             : 
     986           0 :         frr_each (targets, &targets, cfg)
     987           0 :                 if (!zlog_5424_rotate(&cfg->cfg))
     988           0 :                         zlog_err(
     989             :                                 "log rotation on extended log target %s failed",
     990             :                                 cfg->name);
     991             : 
     992           0 :         return 0;
     993             : }
     994             : 
     995          16 : static int log_5424_fini(void)
     996             : {
     997          16 :         struct zlog_cfg_5424_user *cfg;
     998             : 
     999          16 :         while ((cfg = targets_pop(&targets)))
    1000           0 :                 log_5424_free(cfg, true);
    1001             : 
    1002          16 :         log_5424_master = NULL;
    1003             : 
    1004          16 :         return 0;
    1005             : }

Generated by: LCOV version v1.16-topotato