]> git.proxmox.com Git - mirror_frr.git/blame - watchfrr/watchfrr_vty.c
Merge pull request #219 from opensourcerouting/feature/isis-draft-ietf-rtgwg-backoff...
[mirror_frr.git] / watchfrr / watchfrr_vty.c
CommitLineData
95c4aff2 1/*
9473e340 2 watchfrr CLI functions.
95c4aff2
DL
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
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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
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"
38 "Write integrated all-daemon Frr.conf file\n")
95c4aff2
DL
39{
40 pid_t child;
41 sigset_t oldmask, sigmask;
42
43 if (integrated_write_pid != -1) {
44 vty_out(vty, "%% configuration write already in progress.%s",
a6810074 45 VTY_NEWLINE);
95c4aff2
DL
46 return CMD_WARNING;
47 }
48
49 fflush(stdout);
50 fflush(stderr);
51
52 /* need to temporarily block SIGCHLD because it could arrive between
53 * fork() call and setting the integrated_write_pid variable. This
54 * would mean the completion call gets lost and this hangs forever.
55 */
56 sigemptyset(&oldmask);
57 sigemptyset(&sigmask);
58 sigaddset(&sigmask, SIGCHLD);
59 sigprocmask(SIG_BLOCK, &sigmask, &oldmask);
60
61 child = fork();
62 if (child == -1) {
63 vty_out(vty, "%% configuration write fork() failed: %s.%s",
a6810074 64 safe_strerror(errno), VTY_NEWLINE);
95c4aff2
DL
65 sigprocmask(SIG_SETMASK, &oldmask, NULL);
66 return CMD_WARNING;
67 }
68 if (child != 0) {
a6810074
DL
69 /* note: the VTY won't write a command return value to vtysh; the
70 * session temporarily enters an intentional "hang" state. This is
71 * to make sure latency in vtysh doing the config write (several
72 * seconds is not rare to see) does not interfere with watchfrr's
73 * supervisor job.
74 *
75 * The fd is duplicated here so we don't need to hold a vty pointer
76 * (which could become invalid in the meantime).
77 */
95c4aff2
DL
78 integrated_write_pid = child;
79 integrated_result_fd = dup(vty->wfd);
80 sigprocmask(SIG_SETMASK, &oldmask, NULL);
81 return CMD_SUSPEND;
82 }
83
84 /* redirect stdout/stderr to vty session. Note vty->wfd is marked
85 * CLOEXEC, but dup2 will clear that flag. */
86 dup2(vty->wfd, 1);
87 dup2(vty->wfd, 2);
88
89 /* don't allow the user to pass parameters, we're root here!
90 * should probably harden vtysh at some point too... */
91 execl(VTYSH_BIN_PATH, "vtysh", "-w", NULL);
92
93 /* unbuffered write; we just messed with stdout... */
94 char msg[512];
95 snprintf(msg, sizeof(msg), "error executing %s: %s\n",
a6810074 96 VTYSH_BIN_PATH, safe_strerror(errno));
95c4aff2
DL
97 write(1, msg, strlen(msg));
98 exit(1);
99}
100
101void integrated_write_sigchld(int status)
102{
103 uint8_t reply[4] = { 0, 0, 0, CMD_WARNING };
104
105 if (WIFEXITED(status)) {
106 zlog_info("configuration write completed with exit code %d",
a6810074 107 WEXITSTATUS(status));
95c4aff2
DL
108 reply[3] = WEXITSTATUS(status);
109 } else if (WIFSIGNALED(status)) {
110 zlog_warn("configuration write terminated by signal %d",
a6810074 111 WTERMSIG(status));
95c4aff2
DL
112 } else {
113 zlog_warn("configuration write terminated");
114 }
115
c10c5926
DL
116 if (reply[3] != CMD_SUCCESS) {
117 /* failure might be silent in vtysh without this */
118 static const char msg[] = "% Configuration write failed.\n";
119 write(integrated_result_fd, msg, strlen(msg));
120 }
121
95c4aff2
DL
122 /* don't care about failures here, if the connection is broken the
123 * return value will just be lost. */
124 write(integrated_result_fd, reply, sizeof(reply));
125 close(integrated_result_fd);
126
127 integrated_write_pid = -1;
128}
129
9473e340 130void watchfrr_vty_init(void)
95c4aff2
DL
131{
132 integrated_write_pid = -1;
133 install_element(ENABLE_NODE, &config_write_integrated_cmd);
134}