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