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
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
31 pid_t integrated_write_pid
;
32 static int integrated_result_fd
;
34 DEFUN(config_write_integrated
,
35 config_write_integrated_cmd
,
37 "Write running configuration to memory, network, or terminal\n"
38 "Write integrated all-daemon frr.conf file\n")
41 sigset_t oldmask
, sigmask
;
43 if (integrated_write_pid
!= -1) {
44 vty_out(vty
, "%% configuration write already in progress.%s",
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.
56 sigemptyset(&oldmask
);
57 sigemptyset(&sigmask
);
58 sigaddset(&sigmask
, SIGCHLD
);
59 sigprocmask(SIG_BLOCK
, &sigmask
, &oldmask
);
63 vty_out(vty
, "%% configuration write fork() failed: %s.%s",
64 safe_strerror(errno
), VTY_NEWLINE
);
65 sigprocmask(SIG_SETMASK
, &oldmask
, NULL
);
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
75 * The fd is duplicated here so we don't need to hold a vty pointer
76 * (which could become invalid in the meantime).
78 integrated_write_pid
= child
;
79 integrated_result_fd
= dup(vty
->wfd
);
80 sigprocmask(SIG_SETMASK
, &oldmask
, NULL
);
84 /* redirect stdout/stderr to vty session. Note vty->wfd is marked
85 * CLOEXEC, but dup2 will clear that flag. */
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
);
93 /* unbuffered write; we just messed with stdout... */
95 snprintf(msg
, sizeof(msg
), "error executing %s: %s\n",
96 VTYSH_BIN_PATH
, safe_strerror(errno
));
97 write(1, msg
, strlen(msg
));
101 void integrated_write_sigchld(int status
)
103 uint8_t reply
[4] = { 0, 0, 0, CMD_WARNING
};
105 if (WIFEXITED(status
)) {
106 zlog_info("configuration write completed with exit code %d",
107 WEXITSTATUS(status
));
108 reply
[3] = WEXITSTATUS(status
);
109 } else if (WIFSIGNALED(status
)) {
110 zlog_warn("configuration write terminated by signal %d",
113 zlog_warn("configuration write terminated");
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
));
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
);
127 integrated_write_pid
= -1;
130 void watchfrr_vty_init(void)
132 integrated_write_pid
= -1;
133 install_element(ENABLE_NODE
, &config_write_integrated_cmd
);