2 * watchfrr CLI functions.
4 * Copyright (C) 2016 David Lamparter for NetDEF, Inc.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
32 pid_t integrated_write_pid
;
33 static int integrated_result_fd
;
35 DEFUN(config_write_integrated
,
36 config_write_integrated_cmd
,
38 "Write running configuration to memory, network, or terminal\n"
39 "Write integrated all-daemon frr.conf file\n")
42 sigset_t oldmask
, sigmask
;
44 const char *e_inprog
= "Configuration write already in progress.";
45 const char *e_dmn
= "Not all daemons are up, cannot write config.";
47 if (integrated_write_pid
!= -1) {
48 vty_out(vty
, "%% %s\n", e_inprog
);
52 /* check that all daemons are up before clobbering config */
53 if (!check_all_up()) {
54 vty_out(vty
, "%% %s\n", e_dmn
);
56 * vtysh interprets this return value to mean that it should
57 * not try to write the config itself
59 return CMD_WARNING_CONFIG_FAILED
;
65 /* need to temporarily block SIGCHLD because it could arrive between
66 * fork() call and setting the integrated_write_pid variable. This
67 * would mean the completion call gets lost and this hangs forever.
69 sigemptyset(&oldmask
);
70 sigemptyset(&sigmask
);
71 sigaddset(&sigmask
, SIGCHLD
);
72 sigprocmask(SIG_BLOCK
, &sigmask
, &oldmask
);
76 vty_out(vty
, "%% configuration write fork() failed: %s.\n",
77 safe_strerror(errno
));
78 sigprocmask(SIG_SETMASK
, &oldmask
, NULL
);
82 /* note: the VTY won't write a command return value to vtysh;
84 * session temporarily enters an intentional "hang" state. This
86 * to make sure latency in vtysh doing the config write (several
87 * seconds is not rare to see) does not interfere with
91 * The fd is duplicated here so we don't need to hold a vty
93 * (which could become invalid in the meantime).
95 integrated_write_pid
= child
;
96 integrated_result_fd
= dup(vty
->wfd
);
97 sigprocmask(SIG_SETMASK
, &oldmask
, NULL
);
101 /* redirect stdout/stderr to vty session. Note vty->wfd is marked
102 * CLOEXEC, but dup2 will clear that flag. */
106 /* don't allow the user to pass parameters, we're root here!
107 * should probably harden vtysh at some point too... */
109 execl(VTYSH_BIN_PATH
, "vtysh", "-N", pathspace
, "-w", NULL
);
111 execl(VTYSH_BIN_PATH
, "vtysh", "-w", NULL
);
113 /* unbuffered write; we just messed with stdout... */
115 snprintf(msg
, sizeof(msg
), "error executing %s: %s\n", VTYSH_BIN_PATH
,
116 safe_strerror(errno
));
117 write(1, msg
, strlen(msg
));
121 DEFUN_NOSH (show_debugging_watchfrr
,
122 show_debugging_watchfrr_cmd
,
123 "show debugging [watchfrr]",
131 DEFUN (show_watchfrr
,
137 watchfrr_status(vty
);
141 /* we don't have the other logging commands since watchfrr only accepts
142 * log config through command line options
144 DEFUN_NOSH (show_logging
,
148 "Show current logging configuration\n")
150 log_show_syslog(vty
);
154 #ifndef VTYSH_EXTRACT_PL
155 #include "watchfrr/watchfrr_vty_clippy.c"
158 DEFPY (watchfrr_ignore_daemon
,
159 watchfrr_ignore_daemon_cmd
,
160 "[no] watchfrr ignore DAEMON$dname",
162 "Watchfrr Specific sub-command\n"
163 "Ignore a specified daemon when it does not respond to echo request\n"
164 "The daemon to ignore\n")
166 watchfrr_set_ignore_daemon(vty
, dname
, no
? false : true );
171 void integrated_write_sigchld(int status
)
173 uint8_t reply
[4] = {0, 0, 0, CMD_WARNING
};
175 if (WIFEXITED(status
)) {
176 zlog_info("configuration write completed with exit code %d",
177 WEXITSTATUS(status
));
178 reply
[3] = WEXITSTATUS(status
);
179 } else if (WIFSIGNALED(status
)) {
180 zlog_warn("configuration write terminated by signal %d",
183 zlog_warn("configuration write terminated");
186 if (reply
[3] != CMD_SUCCESS
) {
187 /* failure might be silent in vtysh without this */
188 static const char msg
[] = "% Configuration write failed.\n";
189 write(integrated_result_fd
, msg
, strlen(msg
));
192 /* don't care about failures here, if the connection is broken the
193 * return value will just be lost. */
194 write(integrated_result_fd
, reply
, sizeof(reply
));
195 close(integrated_result_fd
);
197 integrated_write_pid
= -1;
200 void watchfrr_vty_init(void)
202 integrated_write_pid
= -1;
203 install_element(ENABLE_NODE
, &config_write_integrated_cmd
);
204 install_element(ENABLE_NODE
, &show_debugging_watchfrr_cmd
);
206 install_element(ENABLE_NODE
, &watchfrr_ignore_daemon_cmd
);
208 install_element(CONFIG_NODE
, &show_debugging_watchfrr_cmd
);
209 install_element(VIEW_NODE
, &show_watchfrr_cmd
);
210 install_element(VIEW_NODE
, &show_logging_cmd
);