]> git.proxmox.com Git - mirror_frr.git/blame - watchfrr/watchfrr_vty.c
zebra, lib: fix the ZEBRA_INTERFACE_VRF_UPDATE zapi message
[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"
26#include "vty.h"
27#include "command.h"
28
9473e340 29#include "watchfrr.h"
95c4aff2
DL
30
31pid_t integrated_write_pid;
32static int integrated_result_fd;
33
a6810074
DL
34DEFUN(config_write_integrated,
35 config_write_integrated_cmd,
36 "write integrated",
37 "Write running configuration to memory, network, or terminal\n"
e20dc2ba 38 "Write integrated all-daemon frr.conf file\n")
95c4aff2
DL
39{
40 pid_t child;
41 sigset_t oldmask, sigmask;
42
470bc619
QY
43 const char *e_inprog = "Configuration write already in progress.";
44 const char *e_dmn = "Not all daemons are up, cannot write config.";
45
95c4aff2 46 if (integrated_write_pid != -1) {
470bc619 47 vty_out(vty, "%% %s\n", e_inprog);
95c4aff2
DL
48 return CMD_WARNING;
49 }
50
470bc619
QY
51 /* check that all daemons are up before clobbering config */
52 if (!check_all_up()) {
53 vty_out(vty, "%% %s\n", e_dmn);
54 /*
55 * vtysh interprets this return value to mean that it should
56 * not try to write the config itself
57 */
58 return CMD_WARNING_CONFIG_FAILED;
59 }
60
95c4aff2
DL
61 fflush(stdout);
62 fflush(stderr);
63
64 /* need to temporarily block SIGCHLD because it could arrive between
65 * fork() call and setting the integrated_write_pid variable. This
66 * would mean the completion call gets lost and this hangs forever.
67 */
68 sigemptyset(&oldmask);
69 sigemptyset(&sigmask);
70 sigaddset(&sigmask, SIGCHLD);
71 sigprocmask(SIG_BLOCK, &sigmask, &oldmask);
72
73 child = fork();
74 if (child == -1) {
d62a17ae 75 vty_out(vty, "%% configuration write fork() failed: %s.\n",
96ade3ed 76 safe_strerror(errno));
95c4aff2
DL
77 sigprocmask(SIG_SETMASK, &oldmask, NULL);
78 return CMD_WARNING;
79 }
80 if (child != 0) {
d62a17ae 81 /* note: the VTY won't write a command return value to vtysh;
82 * the
83 * session temporarily enters an intentional "hang" state. This
84 * is
a6810074 85 * to make sure latency in vtysh doing the config write (several
d62a17ae 86 * seconds is not rare to see) does not interfere with
87 * watchfrr's
a6810074
DL
88 * supervisor job.
89 *
d62a17ae 90 * The fd is duplicated here so we don't need to hold a vty
91 * pointer
a6810074
DL
92 * (which could become invalid in the meantime).
93 */
95c4aff2
DL
94 integrated_write_pid = child;
95 integrated_result_fd = dup(vty->wfd);
96 sigprocmask(SIG_SETMASK, &oldmask, NULL);
97 return CMD_SUSPEND;
98 }
99
100 /* redirect stdout/stderr to vty session. Note vty->wfd is marked
101 * CLOEXEC, but dup2 will clear that flag. */
102 dup2(vty->wfd, 1);
103 dup2(vty->wfd, 2);
104
105 /* don't allow the user to pass parameters, we're root here!
106 * should probably harden vtysh at some point too... */
107 execl(VTYSH_BIN_PATH, "vtysh", "-w", NULL);
108
109 /* unbuffered write; we just messed with stdout... */
110 char msg[512];
d62a17ae 111 snprintf(msg, sizeof(msg), "error executing %s: %s\n", VTYSH_BIN_PATH,
112 safe_strerror(errno));
95c4aff2
DL
113 write(1, msg, strlen(msg));
114 exit(1);
115}
116
dff13b6f
DW
117DEFUN_NOSH (show_debugging_watchfrr,
118 show_debugging_watchfrr_cmd,
119 "show debugging [watchfrr]",
120 SHOW_STR
121 DEBUG_STR
122 WATCHFRR_STR)
123{
124 return CMD_SUCCESS;
125}
126
af568444
DL
127DEFUN (show_watchfrr,
128 show_watchfrr_cmd,
129 "show watchfrr",
130 SHOW_STR
131 WATCHFRR_STR)
132{
133 watchfrr_status(vty);
134 return CMD_SUCCESS;
135}
136
95c4aff2
DL
137void integrated_write_sigchld(int status)
138{
d62a17ae 139 uint8_t reply[4] = {0, 0, 0, CMD_WARNING};
95c4aff2
DL
140
141 if (WIFEXITED(status)) {
142 zlog_info("configuration write completed with exit code %d",
a6810074 143 WEXITSTATUS(status));
95c4aff2
DL
144 reply[3] = WEXITSTATUS(status);
145 } else if (WIFSIGNALED(status)) {
146 zlog_warn("configuration write terminated by signal %d",
a6810074 147 WTERMSIG(status));
95c4aff2
DL
148 } else {
149 zlog_warn("configuration write terminated");
150 }
151
c10c5926
DL
152 if (reply[3] != CMD_SUCCESS) {
153 /* failure might be silent in vtysh without this */
154 static const char msg[] = "% Configuration write failed.\n";
155 write(integrated_result_fd, msg, strlen(msg));
156 }
157
95c4aff2
DL
158 /* don't care about failures here, if the connection is broken the
159 * return value will just be lost. */
160 write(integrated_result_fd, reply, sizeof(reply));
161 close(integrated_result_fd);
162
163 integrated_write_pid = -1;
164}
165
9473e340 166void watchfrr_vty_init(void)
95c4aff2
DL
167{
168 integrated_write_pid = -1;
169 install_element(ENABLE_NODE, &config_write_integrated_cmd);
dff13b6f
DW
170 install_element(ENABLE_NODE, &show_debugging_watchfrr_cmd);
171 install_element(CONFIG_NODE, &show_debugging_watchfrr_cmd);
af568444 172 install_element(VIEW_NODE, &show_watchfrr_cmd);
95c4aff2 173}