]> git.proxmox.com Git - mirror_frr.git/blame - watchfrr/watchfrr_vty.c
lib: rewrite zlog lock-free & TLS-buffered
[mirror_frr.git] / watchfrr / watchfrr_vty.c
CommitLineData
95c4aff2 1/*
896014f4
DL
2 * watchfrr CLI functions.
3 *
4 * Copyright (C) 2016 David Lamparter for NetDEF, Inc.
5 *
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.
10 *
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.
15 *
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
95c4aff2
DL
19 */
20
21#include <zebra.h>
22#include <sys/wait.h>
23
24#include "memory.h"
25#include "log.h"
0bdeb5e5 26#include "log_vty.h"
95c4aff2
DL
27#include "vty.h"
28#include "command.h"
29
9473e340 30#include "watchfrr.h"
95c4aff2
DL
31
32pid_t integrated_write_pid;
33static int integrated_result_fd;
34
a6810074
DL
35DEFUN(config_write_integrated,
36 config_write_integrated_cmd,
37 "write integrated",
38 "Write running configuration to memory, network, or terminal\n"
e20dc2ba 39 "Write integrated all-daemon frr.conf file\n")
95c4aff2
DL
40{
41 pid_t child;
42 sigset_t oldmask, sigmask;
43
470bc619
QY
44 const char *e_inprog = "Configuration write already in progress.";
45 const char *e_dmn = "Not all daemons are up, cannot write config.";
46
95c4aff2 47 if (integrated_write_pid != -1) {
470bc619 48 vty_out(vty, "%% %s\n", e_inprog);
95c4aff2
DL
49 return CMD_WARNING;
50 }
51
470bc619
QY
52 /* check that all daemons are up before clobbering config */
53 if (!check_all_up()) {
54 vty_out(vty, "%% %s\n", e_dmn);
55 /*
56 * vtysh interprets this return value to mean that it should
57 * not try to write the config itself
58 */
59 return CMD_WARNING_CONFIG_FAILED;
60 }
61
95c4aff2
DL
62 fflush(stdout);
63 fflush(stderr);
64
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.
68 */
69 sigemptyset(&oldmask);
70 sigemptyset(&sigmask);
71 sigaddset(&sigmask, SIGCHLD);
72 sigprocmask(SIG_BLOCK, &sigmask, &oldmask);
73
74 child = fork();
75 if (child == -1) {
d62a17ae 76 vty_out(vty, "%% configuration write fork() failed: %s.\n",
96ade3ed 77 safe_strerror(errno));
95c4aff2
DL
78 sigprocmask(SIG_SETMASK, &oldmask, NULL);
79 return CMD_WARNING;
80 }
81 if (child != 0) {
d62a17ae 82 /* note: the VTY won't write a command return value to vtysh;
83 * the
84 * session temporarily enters an intentional "hang" state. This
85 * is
a6810074 86 * to make sure latency in vtysh doing the config write (several
d62a17ae 87 * seconds is not rare to see) does not interfere with
88 * watchfrr's
a6810074
DL
89 * supervisor job.
90 *
d62a17ae 91 * The fd is duplicated here so we don't need to hold a vty
92 * pointer
a6810074
DL
93 * (which could become invalid in the meantime).
94 */
95c4aff2
DL
95 integrated_write_pid = child;
96 integrated_result_fd = dup(vty->wfd);
97 sigprocmask(SIG_SETMASK, &oldmask, NULL);
98 return CMD_SUSPEND;
99 }
100
101 /* redirect stdout/stderr to vty session. Note vty->wfd is marked
102 * CLOEXEC, but dup2 will clear that flag. */
103 dup2(vty->wfd, 1);
104 dup2(vty->wfd, 2);
105
106 /* don't allow the user to pass parameters, we're root here!
107 * should probably harden vtysh at some point too... */
108 execl(VTYSH_BIN_PATH, "vtysh", "-w", NULL);
109
110 /* unbuffered write; we just messed with stdout... */
111 char msg[512];
d62a17ae 112 snprintf(msg, sizeof(msg), "error executing %s: %s\n", VTYSH_BIN_PATH,
113 safe_strerror(errno));
95c4aff2
DL
114 write(1, msg, strlen(msg));
115 exit(1);
116}
117
dff13b6f
DW
118DEFUN_NOSH (show_debugging_watchfrr,
119 show_debugging_watchfrr_cmd,
120 "show debugging [watchfrr]",
121 SHOW_STR
122 DEBUG_STR
123 WATCHFRR_STR)
124{
125 return CMD_SUCCESS;
126}
127
af568444
DL
128DEFUN (show_watchfrr,
129 show_watchfrr_cmd,
130 "show watchfrr",
131 SHOW_STR
132 WATCHFRR_STR)
133{
134 watchfrr_status(vty);
135 return CMD_SUCCESS;
136}
137
0bdeb5e5
DL
138/* we don't have the other logging commands since watchfrr only accepts
139 * log config through command line options
140 */
141DEFUN_NOSH (show_logging,
142 show_logging_cmd,
143 "show logging",
144 SHOW_STR
145 "Show current logging configuration\n")
146{
147 log_show_syslog(vty);
148 return CMD_SUCCESS;
149}
150
cc53b605
DS
151#ifndef VTYSH_EXTRACT_PL
152#include "watchfrr/watchfrr_vty_clippy.c"
153#endif
154
155DEFPY (watchfrr_ignore_daemon,
156 watchfrr_ignore_daemon_cmd,
157 "[no] watchfrr ignore DAEMON$dname",
158 NO_STR
159 "Watchfrr Specific sub-command\n"
160 "Ignore a specified daemon when it does not respond to echo request\n"
161 "The daemon to ignore\n")
162{
163 watchfrr_set_ignore_daemon(vty, dname, no ? false : true );
164
165 return CMD_SUCCESS;
166}
167
95c4aff2
DL
168void integrated_write_sigchld(int status)
169{
d62a17ae 170 uint8_t reply[4] = {0, 0, 0, CMD_WARNING};
95c4aff2
DL
171
172 if (WIFEXITED(status)) {
173 zlog_info("configuration write completed with exit code %d",
a6810074 174 WEXITSTATUS(status));
95c4aff2
DL
175 reply[3] = WEXITSTATUS(status);
176 } else if (WIFSIGNALED(status)) {
177 zlog_warn("configuration write terminated by signal %d",
a6810074 178 WTERMSIG(status));
95c4aff2
DL
179 } else {
180 zlog_warn("configuration write terminated");
181 }
182
c10c5926
DL
183 if (reply[3] != CMD_SUCCESS) {
184 /* failure might be silent in vtysh without this */
185 static const char msg[] = "% Configuration write failed.\n";
186 write(integrated_result_fd, msg, strlen(msg));
187 }
188
95c4aff2
DL
189 /* don't care about failures here, if the connection is broken the
190 * return value will just be lost. */
191 write(integrated_result_fd, reply, sizeof(reply));
192 close(integrated_result_fd);
193
194 integrated_write_pid = -1;
195}
196
9473e340 197void watchfrr_vty_init(void)
95c4aff2
DL
198{
199 integrated_write_pid = -1;
200 install_element(ENABLE_NODE, &config_write_integrated_cmd);
dff13b6f 201 install_element(ENABLE_NODE, &show_debugging_watchfrr_cmd);
cc53b605
DS
202
203 install_element(ENABLE_NODE, &watchfrr_ignore_daemon_cmd);
204
dff13b6f 205 install_element(CONFIG_NODE, &show_debugging_watchfrr_cmd);
af568444 206 install_element(VIEW_NODE, &show_watchfrr_cmd);
0bdeb5e5 207 install_element(VIEW_NODE, &show_logging_cmd);
95c4aff2 208}