mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-05-28 19:43:29 +00:00
Merge branch 'cmaster-next' into vtysh-grammar
Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com> Conflicts: lib/command.c lib/vty.c
This commit is contained in:
commit
07321a065d
12
configure.ac
12
configure.ac
@ -1746,8 +1746,20 @@ AC_DEFINE_UNQUOTED(OSPF6_VTYSH_PATH, "$quagga_statedir/ospf6d.vty",ospf6d vty so
|
||||
AC_DEFINE_UNQUOTED(LDP_VTYSH_PATH, "$quagga_statedir/ldpd.vty",ldpd vty socket)
|
||||
AC_DEFINE_UNQUOTED(ISIS_VTYSH_PATH, "$quagga_statedir/isisd.vty",isisd vty socket)
|
||||
AC_DEFINE_UNQUOTED(PIM_VTYSH_PATH, "$quagga_statedir/pimd.vty",pimd vty socket)
|
||||
AC_DEFINE_UNQUOTED(WATCHQUAGGA_VTYSH_PATH, "$quagga_statedir/watchquagga.vty",watchquagga vty socket)
|
||||
AC_DEFINE_UNQUOTED(DAEMON_VTY_DIR, "$quagga_statedir",daemon vty directory)
|
||||
|
||||
dnl autoconf does this, but it does it too late...
|
||||
test "x$prefix" = xNONE && prefix=$ac_default_prefix
|
||||
test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
|
||||
|
||||
dnl get the full path, recursing through variables...
|
||||
vtysh_bin="$bindir/vtysh"
|
||||
for I in 1 2 3 4 5 6 7 8 9 10; do
|
||||
eval vtysh_bin="\"$vtysh_bin\""
|
||||
done
|
||||
AC_DEFINE_UNQUOTED(VTYSH_BIN_PATH, "$vtysh_bin",path to vtysh binary)
|
||||
|
||||
dnl -------------------------------
|
||||
dnl Quagga sources should always be
|
||||
dnl current wrt interfaces. Dont
|
||||
|
@ -13,3 +13,4 @@
|
||||
@set INSTALL_PREFIX_ETC /etc/quagga
|
||||
@set INSTALL_PREFIX_SBIN /usr/sbin
|
||||
@set INSTALL_PREFIX_STATE /var/run/quagga
|
||||
@set INSTALL_VTY_GROUP @enable_vty_group@
|
||||
|
@ -44,15 +44,10 @@ commands:
|
||||
@cindex Options to @code{./configure}
|
||||
|
||||
Quagga has an excellent configure script which automatically detects most
|
||||
host configurations. There are several additional configure options you can
|
||||
use to turn off IPv6 support, to disable the compilation of specific
|
||||
daemons, and to enable SNMP support.
|
||||
host configurations. There are several additional configure options to
|
||||
customize the build to include or exclude specific features and dependencies.
|
||||
|
||||
@table @option
|
||||
@item --disable-ipv6
|
||||
Turn off IPv6 related features and daemons. Quagga configure script
|
||||
automatically detects IPv6 stack. But sometimes you might want to
|
||||
disable IPv6 support of Quagga.
|
||||
@item --disable-zebra
|
||||
Do not build zebra daemon.
|
||||
@item --disable-ripd
|
||||
@ -68,28 +63,18 @@ Do not build bgpd.
|
||||
@item --disable-bgp-announce
|
||||
Make @command{bgpd} which does not make bgp announcements at all. This
|
||||
feature is good for using @command{bgpd} as a BGP announcement listener.
|
||||
@item --enable-netlink
|
||||
Force to enable @sc{gnu}/Linux netlink interface. Quagga configure
|
||||
script detects netlink interface by checking a header file. When the header
|
||||
file does not match to the current running kernel, configure script will
|
||||
not turn on netlink support.
|
||||
@item --enable-snmp
|
||||
Enable SNMP support. By default, SNMP support is disabled.
|
||||
@item --disable-opaque-lsa
|
||||
Disable support for Opaque LSAs (RFC2370) in ospfd.
|
||||
@item --disable-ospfapi
|
||||
Disable support for OSPF-API, an API to interface directly with ospfd.
|
||||
OSPF-API is enabled if --enable-opaque-lsa is set.
|
||||
@item --disable-ospfclient
|
||||
Disable building of the example OSPF-API client.
|
||||
@item --disable-ospf-te
|
||||
Disable support for OSPF Traffic Engineering Extension (RFC3630) this
|
||||
requires support for Opaque LSAs.
|
||||
@item --disable-ospf-ri
|
||||
Disable support for OSPF Router Information (RFC4970 & RFC5088) this
|
||||
requires support for Opaque LSAs and Traffic Engineering.
|
||||
@item --enable-isisd
|
||||
Build isisd.
|
||||
@item --disable-isisd
|
||||
Do not build isisd.
|
||||
@item --enable-isis-topology
|
||||
Enable IS-IS topology generator.
|
||||
@item --enable-isis-te
|
||||
@ -104,7 +89,7 @@ Pass the @command{-rdynamic} option to the linker driver. This is in most
|
||||
cases neccessary for getting usable backtraces. This option defaults to on
|
||||
if the compiler is detected as gcc, but giving an explicit enable/disable is
|
||||
suggested.
|
||||
@item --enable-backtrace
|
||||
@item --disable-backtrace
|
||||
Controls backtrace support for the crash handlers. This is autodetected by
|
||||
default. Using the switch will enforce the requested behaviour, failing with
|
||||
an error if support is requested but not available. On BSD systems, this
|
||||
@ -129,7 +114,7 @@ as pid files and unix sockets.
|
||||
@end table
|
||||
|
||||
@example
|
||||
% ./configure --disable-ipv6
|
||||
% ./configure --disable-snmp
|
||||
@end example
|
||||
|
||||
This command will configure zebra and the routing daemons.
|
||||
|
@ -8,6 +8,9 @@ automatic address configuration via a feature called @code{address
|
||||
auto configuration}. To do it, the router must send router advertisement
|
||||
messages to the all nodes that exist on the network.
|
||||
|
||||
Previous versions of Quagga could be built without IPv6 support. This is
|
||||
no longer possible.
|
||||
|
||||
@menu
|
||||
* Router Advertisement::
|
||||
@end menu
|
||||
|
176
doc/vtysh.texi
176
doc/vtysh.texi
@ -1,56 +1,105 @@
|
||||
@node VTY shell
|
||||
@chapter VTY shell
|
||||
|
||||
@command{vtysh} is integrated shell of Quagga software.
|
||||
|
||||
To use vtysh please specify ---enable-vtysh to configure script. To use
|
||||
PAM for authentication use ---with-libpam option to configure script.
|
||||
|
||||
vtysh only searches @value{INSTALL_PREFIX_ETC} path for vtysh.conf which
|
||||
is the vtysh configuration file. Vtysh does not search current
|
||||
directory for configuration file because the file includes user
|
||||
authentication settings.
|
||||
|
||||
Currently, vtysh.conf has only two commands.
|
||||
|
||||
@menu
|
||||
* VTY shell username::
|
||||
* VTY shell integrated configuration::
|
||||
* Integrated configuration mode::
|
||||
@end menu
|
||||
|
||||
@node VTY shell username
|
||||
@section VTY shell username
|
||||
@command{vtysh} provides a combined frontend to all Quagga daemons in a
|
||||
single combined session. It is enabled by default at build time, but can
|
||||
be disabled through the @option{--disable-vtysh} option to
|
||||
@command{./configure}.
|
||||
|
||||
@command{vtysh} has a configuration file, @file{vtysh.conf}. The location
|
||||
of that file cannot be changed from @file{@value{INSTALL_PREFIX_ETC}} since
|
||||
it contains options controlling authentication behavior. This file will
|
||||
also not be written by configuration-save commands, it is intended to be
|
||||
updated manually by an administrator with an external editor.
|
||||
|
||||
@quotation Warning
|
||||
This also means the @command{hostname} and @command{banner motd} commands
|
||||
(which both do have effect for vtysh) need to be manually updated in
|
||||
@file{vtysh.conf}.
|
||||
@end quotation
|
||||
|
||||
@section Permissions and setup requirements
|
||||
|
||||
@command{vtysh} connects to running daemons through Unix sockets located in
|
||||
@file{@value{INSTALL_PREFIX_STATE}}. Running vtysh thus requires access to
|
||||
that directory, plus membership in the @emph{@value{INSTALL_VTY_GROUP}}
|
||||
group (which is the group that the daemons will change ownership of their
|
||||
sockets to).
|
||||
|
||||
To restrict access to Quagga configuration, make sure no unauthorized users
|
||||
are members of the @emph{@value{INSTALL_VTY_GROUP}} group.
|
||||
|
||||
@subsection PAM support (experimental)
|
||||
|
||||
vtysh has working (but rather useless) PAM support. It will perform
|
||||
an "authenticate" PAM call using @emph{@value{PACKAGE_NAME}} as service
|
||||
name. No other (accounting, session, password change) calls will be
|
||||
performed by vtysh.
|
||||
|
||||
Users using vtysh still need to have appropriate access to the daemons'
|
||||
VTY sockets, usually by being member of the @emph{@value{INSTALL_VTY_GROUP}}
|
||||
group. If they have this membership, PAM support is useless since they can
|
||||
connect to daemons and issue commands using some other tool. Alternatively,
|
||||
the @command{vtysh} binary could be made SGID (set group ID) to the
|
||||
@emph{@value{INSTALL_VTY_GROUP}} group. @strong{No security guarantees are
|
||||
made for this configuration}.
|
||||
|
||||
@deffn {Command} {username @var{username} nopassword} {}
|
||||
|
||||
With this set, user foo does not need password authentication for user vtysh.
|
||||
With PAM vtysh uses PAM authentication mechanism.
|
||||
|
||||
If vtysh is compiled without PAM authentication, every user can use vtysh
|
||||
without authentication. vtysh requires read/write permission
|
||||
to the various daemons vty sockets, this can be accomplished through use
|
||||
of unix groups and the --enable-vty-group configure option.
|
||||
If PAM support is enabled at build-time, this command allows disabling the
|
||||
use of PAM on a per-user basis. If vtysh finds that an user is trying to
|
||||
use vtysh and a "nopassword" entry is found, no calls to PAM will be made
|
||||
at all.
|
||||
|
||||
@end deffn
|
||||
|
||||
@node VTY shell integrated configuration
|
||||
@section VTY shell integrated configuration
|
||||
@node Integrated configuration mode
|
||||
@section Integrated configuration mode
|
||||
|
||||
@deffn {Command} {service integrated-vtysh-config} {}
|
||||
Write out integrated Quagga.conf file when 'write file' is issued.
|
||||
Integrated configuration mode uses a single configuration file,
|
||||
@file{Quagga.conf}, for all daemons. This replaces the individual files like
|
||||
@file{zebra.conf} or @file{bgpd.conf}.
|
||||
|
||||
This command controls the behaviour of vtysh when it is told to write out
|
||||
the configuration. Per default, vtysh will instruct each daemon to write
|
||||
out their own config files when @command{write file} is issued. However, if
|
||||
@command{service integrated-vtysh-config} is set, when @command{write file}
|
||||
is issued, vtysh will instruct the daemons will write out a Quagga.conf with
|
||||
all daemons' commands integrated into it.
|
||||
@file{Quagga.conf} is located in @file{@value{INSTALL_PREFIX_ETC}}. All
|
||||
daemons check for the existence of this file at startup, and if it exists
|
||||
will not load their individual configuration files. Instead,
|
||||
@command{vtysh -b} must be invoked to process @file{Quagga.conf} and apply
|
||||
its settings to the individual daemons.
|
||||
|
||||
Vtysh per default behaves as if @command{write-conf daemon} is set. Note
|
||||
that both may be set at same time if one wishes to have both Quagga.conf and
|
||||
daemon specific files written out. Further, note that the daemons are
|
||||
hard-coded to first look for the integrated Quagga.conf file before looking
|
||||
for their own file.
|
||||
@quotation Warning
|
||||
@command{vtysh -b} must also be executed after restarting any daemon.
|
||||
@end quotation
|
||||
|
||||
@subsection Configuration saving, file ownership and permissions
|
||||
|
||||
The @file{Quagga.conf} file is not written by any of the daemons; instead
|
||||
@command{vtysh} contains the neccessary logic to collect configuration from
|
||||
all of the daemons, combine it and write it out.
|
||||
|
||||
@quotation Warning
|
||||
Daemons must be running for @command{vtysh} to be able to collect their
|
||||
configuration. Any configuration from non-running daemons is permanently
|
||||
lost after doing a configuration save.
|
||||
@end quotation
|
||||
|
||||
Since the @command{vtysh} command may be running as ordinary user on the
|
||||
system, configuration writes will be tried through @command{watchquagga},
|
||||
using the @command{write integrated} command internally. Since
|
||||
@command{watchquagga} is running as superuser, @command{vtysh} is able to
|
||||
ensure correct ownership and permissions on @file{Quagga.conf}.
|
||||
|
||||
If @command{watchquagga} is not running or the configuration write fails,
|
||||
@command{vtysh} will attempt to directly write to the file. This is likely
|
||||
to fail if running as unprivileged user; alternatively it may leave the
|
||||
file with incorrect owner or permissions.
|
||||
|
||||
Writing the configuration can be triggered directly by invoking
|
||||
@command{vtysh -w}. This may be useful for scripting. Note this command
|
||||
should be run as either the superuser or the Quagga user.
|
||||
|
||||
We recommend you do not mix the use of the two types of files. Further, it
|
||||
is better not to use the integrated Quagga.conf file, as any syntax error in
|
||||
@ -58,4 +107,55 @@ it can lead to /all/ of your daemons being unable to start up. Per daemon
|
||||
files are more robust as impact of errors in configuration are limited to
|
||||
the daemon in whose file the error is made.
|
||||
|
||||
@deffn {Command} {service integrated-vtysh-config} {}
|
||||
@deffnx {Command} {no service integrated-vtysh-config} {}
|
||||
|
||||
Control whether integrated @file{Quagga.conf} file is written when
|
||||
'write file' is issued.
|
||||
|
||||
These commands need to be placed in @file{vtysh.conf} to have any effect.
|
||||
Note that since @file{vtysh.conf} is not written by Quagga itself, they
|
||||
therefore need to be manually placed in that file.
|
||||
|
||||
This command has 3 states:
|
||||
@itemize @bullet
|
||||
@item
|
||||
@command{service integrated-vtysh-config}
|
||||
|
||||
@command{vtysh} will always write @file{Quagga.conf}.
|
||||
|
||||
@item
|
||||
@command{no service integrated-vtysh-config}
|
||||
|
||||
@command{vtysh} will never write @file{Quagga.conf}; instead it will ask
|
||||
daemons to write their individual configuration files.
|
||||
|
||||
@item
|
||||
Neither option present (default)
|
||||
|
||||
@command{vtysh} will check whether @file{Quagga.conf} exists. If it does,
|
||||
configuration writes will update that file. Otherwise, writes are performed
|
||||
through the individual daemons.
|
||||
@end itemize
|
||||
|
||||
This command is primarily intended for packaging/distribution purposes, to
|
||||
preset one of the two operating modes and ensure consistent operation across
|
||||
installations.
|
||||
@end deffn
|
||||
|
||||
@deffn {Command} {write integrated} {}
|
||||
|
||||
Unconditionally (regardless of @command{service integrated-vtysh-config}
|
||||
setting) write out integrated @file{Quagga.conf} file through
|
||||
@command{watchquagga}. If @command{watchquagga} is not running, this command
|
||||
is unavailable.
|
||||
|
||||
@end deffn
|
||||
|
||||
@section Caveats
|
||||
|
||||
Configuration changes made while some daemon is not running will be invisible
|
||||
to that daemon. The daemon will start up with its saved configuration
|
||||
(either in its individual configuration file, or in @file{Quagga.conf}).
|
||||
This is particularly troublesome for route-maps and prefix lists, which would
|
||||
otherwise be synchronized between daemons.
|
||||
|
@ -1350,6 +1350,9 @@ DEFUN (config_write,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
if (host.noconfig)
|
||||
return CMD_SUCCESS;
|
||||
|
||||
/* Check and see if we are operating under vtysh configuration */
|
||||
if (host.config == NULL)
|
||||
{
|
||||
@ -1478,6 +1481,11 @@ DEFUN (show_startup_config,
|
||||
char buf[BUFSIZ];
|
||||
FILE *confp;
|
||||
|
||||
if (host.noconfig)
|
||||
return CMD_SUCCESS;
|
||||
if (host.config == NULL)
|
||||
return CMD_WARNING;
|
||||
|
||||
confp = fopen (host.config, "r");
|
||||
if (confp == NULL)
|
||||
{
|
||||
@ -2281,7 +2289,11 @@ install_default (enum node_type node)
|
||||
install_element (node, &show_running_config_cmd);
|
||||
}
|
||||
|
||||
/* Initialize command interface. Install basic nodes and commands. */
|
||||
/* Initialize command interface. Install basic nodes and commands.
|
||||
*
|
||||
* terminal = 0 -- vtysh / no logging, no config control
|
||||
* terminal = 1 -- normal daemon
|
||||
* terminal = -1 -- watchquagga / no logging, but minimal config control */
|
||||
void
|
||||
cmd_init (int terminal)
|
||||
{
|
||||
@ -2296,6 +2308,7 @@ cmd_init (int terminal)
|
||||
host.enable = NULL;
|
||||
host.logfile = NULL;
|
||||
host.config = NULL;
|
||||
host.noconfig = (terminal < 0);
|
||||
host.lines = -1;
|
||||
host.motd = default_motd;
|
||||
host.motdfile = NULL;
|
||||
@ -2338,12 +2351,17 @@ cmd_init (int terminal)
|
||||
{
|
||||
install_element (ENABLE_NODE, &config_logmsg_cmd);
|
||||
install_default (CONFIG_NODE);
|
||||
|
||||
install_element (VIEW_NODE, &show_thread_cpu_cmd);
|
||||
install_element (ENABLE_NODE, &clear_thread_cpu_cmd);
|
||||
|
||||
install_element (VIEW_NODE, &show_work_queues_cmd);
|
||||
}
|
||||
|
||||
install_element (CONFIG_NODE, &hostname_cmd);
|
||||
install_element (CONFIG_NODE, &no_hostname_cmd);
|
||||
|
||||
if (terminal)
|
||||
if (terminal > 0)
|
||||
{
|
||||
install_element (CONFIG_NODE, &password_cmd);
|
||||
install_element (CONFIG_NODE, &enable_password_cmd);
|
||||
@ -2373,11 +2391,6 @@ cmd_init (int terminal)
|
||||
install_element (CONFIG_NODE, &service_terminal_length_cmd);
|
||||
install_element (CONFIG_NODE, &no_service_terminal_length_cmd);
|
||||
|
||||
install_element (VIEW_NODE, &show_thread_cpu_cmd);
|
||||
|
||||
install_element (ENABLE_NODE, &clear_thread_cpu_cmd);
|
||||
install_element (VIEW_NODE, &show_work_queues_cmd);
|
||||
|
||||
vrf_install_commands ();
|
||||
}
|
||||
srandom(time(NULL));
|
||||
|
@ -57,6 +57,7 @@ struct host
|
||||
|
||||
/* config file name of this host */
|
||||
char *config;
|
||||
int noconfig;
|
||||
|
||||
/* Flags for services */
|
||||
int advanced;
|
||||
@ -226,6 +227,7 @@ struct cmd_element
|
||||
#define CMD_COMPLETE_LIST_MATCH 9
|
||||
#define CMD_SUCCESS_DAEMON 10
|
||||
#define CMD_ERR_NO_FILE 11
|
||||
#define CMD_SUSPEND 12
|
||||
|
||||
/* Argc max counts. */
|
||||
#define CMD_ARGC_MAX 25
|
||||
|
@ -58,7 +58,8 @@ const char *zlog_proto_names[] =
|
||||
"LDP",
|
||||
"ISIS",
|
||||
"PIM",
|
||||
"RFP",
|
||||
"RFP",
|
||||
"WATCHQUAGGA",
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
@ -59,6 +59,7 @@ typedef enum
|
||||
ZLOG_ISIS,
|
||||
ZLOG_PIM,
|
||||
ZLOG_RFP,
|
||||
ZLOG_WATCHQUAGGA,
|
||||
} zlog_proto_t;
|
||||
|
||||
/* If maxlvl is set to ZLOG_DISABLED, then no messages will be sent
|
||||
|
@ -94,6 +94,20 @@ set_nonblocking(int fd)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
set_cloexec(int fd)
|
||||
{
|
||||
int flags;
|
||||
flags = fcntl(fd, F_GETFD, 0);
|
||||
if (flags == -1)
|
||||
return -1;
|
||||
|
||||
flags |= FD_CLOEXEC;
|
||||
if (fcntl(fd, F_SETFD, flags) == -1)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
float
|
||||
htonf (float host)
|
||||
{
|
||||
|
@ -33,6 +33,8 @@ extern int writen (int, const u_char *, int);
|
||||
-1 on error. */
|
||||
extern int set_nonblocking(int fd);
|
||||
|
||||
extern int set_cloexec(int fd);
|
||||
|
||||
/* Does the I/O error indicate that the operation should be retried later? */
|
||||
#define ERRNO_IO_RETRY(EN) \
|
||||
(((EN) == EAGAIN) || ((EN) == EWOULDBLOCK) || ((EN) == EINTR))
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <fcntl.h>
|
||||
#include <log.h>
|
||||
#include "version.h"
|
||||
#include "network.h"
|
||||
|
||||
#define PIDFILE_MASK 0644
|
||||
#ifndef HAVE_FCNTL
|
||||
@ -84,6 +85,8 @@ pid_output (const char *path)
|
||||
umask(oldumask);
|
||||
memset (&lock, 0, sizeof(lock));
|
||||
|
||||
set_cloexec(fd);
|
||||
|
||||
lock.l_type = F_WRLCK;
|
||||
lock.l_whence = SEEK_SET;
|
||||
|
||||
|
51
lib/privs.c
51
lib/privs.c
@ -679,6 +679,15 @@ zprivs_init(struct zebra_privs_t *zprivs)
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (zprivs->vty_group)
|
||||
{
|
||||
/* in a "NULL" setup, this is allowed to fail too, but still try. */
|
||||
if ((grentry = getgrnam (zprivs->vty_group)))
|
||||
zprivs_state.vtygrp = grentry->gr_gid;
|
||||
else
|
||||
zprivs_state.vtygrp = (gid_t)-1;
|
||||
}
|
||||
|
||||
/* NULL privs */
|
||||
if (! (zprivs->user || zprivs->group
|
||||
|| zprivs->cap_num_p || zprivs->cap_num_i) )
|
||||
@ -731,34 +740,30 @@ zprivs_init(struct zebra_privs_t *zprivs)
|
||||
if (zprivs->vty_group)
|
||||
/* Add the vty_group to the supplementary groups so it can be chowned to */
|
||||
{
|
||||
if ( (grentry = getgrnam (zprivs->vty_group)) )
|
||||
{
|
||||
zprivs_state.vtygrp = grentry->gr_gid;
|
||||
|
||||
for ( i = 0; i < ngroups; i++ )
|
||||
if ( groups[i] == zprivs_state.vtygrp )
|
||||
{
|
||||
found++;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
fprintf (stderr, "privs_init: user(%s) is not part of vty group specified(%s)\n",
|
||||
zprivs->user, zprivs->vty_group);
|
||||
exit (1);
|
||||
}
|
||||
if ( i >= ngroups && ngroups < (int) ZEBRA_NUM_OF(groups) )
|
||||
{
|
||||
groups[i] = zprivs_state.vtygrp;
|
||||
}
|
||||
}
|
||||
else
|
||||
if (zprivs_state.vtygrp == (gid_t)-1)
|
||||
{
|
||||
fprintf (stderr, "privs_init: could not lookup vty group %s\n",
|
||||
zprivs->vty_group);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
for ( i = 0; i < ngroups; i++ )
|
||||
if ( groups[i] == zprivs_state.vtygrp )
|
||||
{
|
||||
found++;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
{
|
||||
fprintf (stderr, "privs_init: user(%s) is not part of vty group specified(%s)\n",
|
||||
zprivs->user, zprivs->vty_group);
|
||||
exit (1);
|
||||
}
|
||||
if ( i >= ngroups && ngroups < (int) ZEBRA_NUM_OF(groups) )
|
||||
{
|
||||
groups[i] = zprivs_state.vtygrp;
|
||||
}
|
||||
}
|
||||
|
||||
if (ngroups)
|
||||
|
17
lib/vty.c
17
lib/vty.c
@ -1839,6 +1839,7 @@ vty_accept (struct thread *thread)
|
||||
return -1;
|
||||
}
|
||||
set_nonblocking(vty_sock);
|
||||
set_cloexec(vty_sock);
|
||||
|
||||
sockunion2hostprefix (&su, &p);
|
||||
|
||||
@ -1937,6 +1938,7 @@ vty_serv_sock_addrinfo (const char *hostname, unsigned short port)
|
||||
sockopt_v6only (ainfo->ai_family, sock);
|
||||
sockopt_reuseaddr (sock);
|
||||
sockopt_reuseport (sock);
|
||||
set_cloexec (sock);
|
||||
|
||||
ret = bind (sock, ainfo->ai_addr, ainfo->ai_addrlen);
|
||||
if (ret < 0)
|
||||
@ -2004,6 +2006,7 @@ vty_serv_sock_family (const char* addr, unsigned short port, int family)
|
||||
/* This is server, so reuse address. */
|
||||
sockopt_reuseaddr (accept_sock);
|
||||
sockopt_reuseport (accept_sock);
|
||||
set_cloexec (accept_sock);
|
||||
|
||||
/* Bind socket to universal address and given port. */
|
||||
ret = sockunion_bind (accept_sock, &su, port, naddr);
|
||||
@ -2066,6 +2069,8 @@ vty_serv_un (const char *path)
|
||||
len = sizeof (serv.sun_family) + strlen (serv.sun_path);
|
||||
#endif /* HAVE_STRUCT_SOCKADDR_UN_SUN_LEN */
|
||||
|
||||
set_cloexec (sock);
|
||||
|
||||
ret = bind (sock, (struct sockaddr *) &serv, len);
|
||||
if (ret < 0)
|
||||
{
|
||||
@ -2133,6 +2138,7 @@ vtysh_accept (struct thread *thread)
|
||||
close (sock);
|
||||
return -1;
|
||||
}
|
||||
set_cloexec(sock);
|
||||
|
||||
#ifdef VTYSH_DEBUG
|
||||
printf ("VTY shell accept\n");
|
||||
@ -2227,8 +2233,15 @@ vtysh_read (struct thread *thread)
|
||||
printf ("vtysh node: %d\n", vty->node);
|
||||
#endif /* VTYSH_DEBUG */
|
||||
|
||||
header[3] = ret;
|
||||
buffer_put(vty->obuf, header, 4);
|
||||
/* hack for asynchronous "write integrated"
|
||||
* - other commands in "buf" will be ditched
|
||||
* - input during pending config-write is "unsupported" */
|
||||
if (ret == CMD_SUSPEND)
|
||||
break;
|
||||
|
||||
/* warning: watchquagga hardcodes this result write */
|
||||
header[3] = ret;
|
||||
buffer_put(vty->obuf, header, 4);
|
||||
|
||||
if (!vty->t_write && (vtysh_flush(vty) < 0))
|
||||
/* Try to flush results; exit if a write error occurs. */
|
||||
|
14
tools/quagga
14
tools/quagga
@ -33,7 +33,6 @@ else
|
||||
SSD=`which start-stop-daemon`
|
||||
fi
|
||||
|
||||
echo ${SSD}
|
||||
# Print the name of the pidfile.
|
||||
pidfile()
|
||||
{
|
||||
@ -114,12 +113,23 @@ start()
|
||||
echo -n " $1"
|
||||
fi
|
||||
|
||||
if [ -e /var/run/quagga/watchquagga.started ] ; then
|
||||
rm /var/run/quagga/watchquagga.started
|
||||
fi
|
||||
${SSD} \
|
||||
--start \
|
||||
--pidfile=`pidfile $1` \
|
||||
--exec "$D_PATH/$1" \
|
||||
-- \
|
||||
"${watchquagga_options[@]}"
|
||||
for i in `seq 1 10`;
|
||||
do
|
||||
if [ -e /var/run/quagga/watchquagga.started ] ; then
|
||||
break
|
||||
else
|
||||
sleep 1
|
||||
fi
|
||||
done
|
||||
elif [ -n "$2" ]; then
|
||||
echo -n " $1-$2"
|
||||
if ! check_daemon $1 $2 ; then
|
||||
@ -502,8 +512,8 @@ case "$1" in
|
||||
if [ "$2" != "watchquagga" ]; then
|
||||
start_prio 10 $dmn
|
||||
fi
|
||||
vtysh_b
|
||||
start_watchquagga
|
||||
vtysh_b
|
||||
;;
|
||||
|
||||
1|2|3|4|5|6|7|8|9|10)
|
||||
|
@ -86,6 +86,7 @@ vtysh_cmd_FILES = $(vtysh_scan) \
|
||||
$(top_srcdir)/zebra/zebra_fpm.c \
|
||||
$(top_srcdir)/zebra/zebra_ptm.c \
|
||||
$(top_srcdir)/zebra/zebra_mpls_vty.c \
|
||||
$(top_srcdir)/watchquagga/watchquagga_vty.c \
|
||||
$(BGP_VNC_RFAPI_SRC) $(BGP_VNC_RFP_SRC)
|
||||
|
||||
vtysh_cmd.c: $(vtysh_cmd_FILES) extract.pl
|
||||
|
174
vtysh/vtysh.c
174
vtysh/vtysh.c
@ -73,12 +73,11 @@ struct vtysh_client vtysh_client[] =
|
||||
{ .fd = -1, .name = "bgpd", .flag = VTYSH_BGPD, .path = BGP_VTYSH_PATH, .next = NULL},
|
||||
{ .fd = -1, .name = "isisd", .flag = VTYSH_ISISD, .path = ISIS_VTYSH_PATH, .next = NULL},
|
||||
{ .fd = -1, .name = "pimd", .flag = VTYSH_PIMD, .path = PIM_VTYSH_PATH, .next = NULL},
|
||||
{ .fd = -1, .name = "watchquagga", .flag = VTYSH_WATCHQUAGGA, .path = WATCHQUAGGA_VTYSH_PATH, .next = NULL},
|
||||
};
|
||||
|
||||
enum vtysh_write_integrated vtysh_write_integrated = WRITE_INTEGRATED_UNSPECIFIED;
|
||||
|
||||
extern char config_default[];
|
||||
|
||||
static void
|
||||
vclient_close (struct vtysh_client *vclient)
|
||||
{
|
||||
@ -1068,7 +1067,7 @@ vtysh_end (void)
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUNSH (VTYSH_ALL,
|
||||
DEFUNSH (VTYSH_REALLYALL,
|
||||
vtysh_end_all,
|
||||
vtysh_end_all_cmd,
|
||||
"end",
|
||||
@ -1410,8 +1409,8 @@ DEFUNSH (VTYSH_ALL,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUNSH (VTYSH_ALL,
|
||||
vtysh_enable,
|
||||
DEFUNSH (VTYSH_REALLYALL,
|
||||
vtysh_enable,
|
||||
vtysh_enable_cmd,
|
||||
"enable",
|
||||
"Turn on privileged mode command\n")
|
||||
@ -1420,8 +1419,8 @@ DEFUNSH (VTYSH_ALL,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUNSH (VTYSH_ALL,
|
||||
vtysh_disable,
|
||||
DEFUNSH (VTYSH_REALLYALL,
|
||||
vtysh_disable,
|
||||
vtysh_disable_cmd,
|
||||
"disable",
|
||||
"Turn off privileged mode command\n")
|
||||
@ -1431,7 +1430,7 @@ DEFUNSH (VTYSH_ALL,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUNSH (VTYSH_ALL,
|
||||
DEFUNSH (VTYSH_REALLYALL,
|
||||
vtysh_config_terminal,
|
||||
vtysh_config_terminal_cmd,
|
||||
"configure terminal",
|
||||
@ -1512,7 +1511,7 @@ vtysh_exit (struct vty *vty)
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUNSH (VTYSH_ALL,
|
||||
DEFUNSH (VTYSH_REALLYALL,
|
||||
vtysh_exit_all,
|
||||
vtysh_exit_all_cmd,
|
||||
"exit",
|
||||
@ -2399,74 +2398,101 @@ backup_config_file (const char *fbackup)
|
||||
free (integrate_sav);
|
||||
}
|
||||
|
||||
static int
|
||||
write_config_integrated(void)
|
||||
int
|
||||
vtysh_write_config_integrated(void)
|
||||
{
|
||||
u_int i;
|
||||
char line[] = "write terminal\n";
|
||||
FILE *fp, *fp1;
|
||||
FILE *fp;
|
||||
int fd;
|
||||
struct passwd *pwentry;
|
||||
struct group *grentry;
|
||||
uid_t uid = -1;
|
||||
gid_t gid = -1;
|
||||
struct stat st;
|
||||
int err = 0;
|
||||
|
||||
fprintf (stdout,"Building Configuration...\n");
|
||||
|
||||
backup_config_file(integrate_default);
|
||||
backup_config_file(host.config);
|
||||
|
||||
fp = fopen (integrate_default, "w");
|
||||
backup_config_file(quagga_config);
|
||||
fp = fopen (quagga_config, "w");
|
||||
if (fp == NULL)
|
||||
{
|
||||
fprintf (stdout,"%% Can't open configuration file %s due to '%s'\n",
|
||||
integrate_default, safe_strerror(errno));
|
||||
return CMD_SUCCESS;
|
||||
fprintf (stdout,"%% Error: failed to open configuration file %s: %s\n",
|
||||
quagga_config, safe_strerror(errno));
|
||||
return CMD_WARNING;
|
||||
}
|
||||
fd = fileno (fp);
|
||||
|
||||
fp1 = fopen (host.config, "w");
|
||||
if (fp1 == NULL)
|
||||
{
|
||||
fprintf (stdout,"%% Can't open configuration file %s due to '%s'\n",
|
||||
host.config, safe_strerror(errno));
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
vtysh_config_write ();
|
||||
vtysh_config_dump (fp1);
|
||||
|
||||
fclose (fp1);
|
||||
for (i = 0; i < array_size(vtysh_client); i++)
|
||||
vtysh_client_config (&vtysh_client[i], line);
|
||||
|
||||
vtysh_config_write ();
|
||||
vtysh_config_dump (fp);
|
||||
|
||||
if (fchmod (fd, CONFIGFILE_MASK) != 0)
|
||||
{
|
||||
printf ("%% Warning: can't chmod configuration file %s: %s\n",
|
||||
quagga_config, safe_strerror(errno));
|
||||
err++;
|
||||
}
|
||||
|
||||
pwentry = getpwnam (QUAGGA_USER);
|
||||
if (pwentry)
|
||||
uid = pwentry->pw_uid;
|
||||
else
|
||||
{
|
||||
printf ("%% Warning: could not look up user \"%s\"\n", QUAGGA_USER);
|
||||
err++;
|
||||
}
|
||||
|
||||
grentry = getgrnam (QUAGGA_GROUP);
|
||||
if (grentry)
|
||||
gid = grentry->gr_gid;
|
||||
else
|
||||
{
|
||||
printf ("%% Warning: could not look up group \"%s\"\n", QUAGGA_GROUP);
|
||||
err++;
|
||||
}
|
||||
|
||||
if (!fstat (fd, &st))
|
||||
{
|
||||
if (st.st_uid == uid)
|
||||
uid = -1;
|
||||
if (st.st_gid == gid)
|
||||
gid = -1;
|
||||
if ((uid != (uid_t)-1 || gid != (gid_t)-1) && fchown (fd, uid, gid))
|
||||
{
|
||||
printf ("%% Warning: can't chown configuration file %s: %s\n",
|
||||
quagga_config, safe_strerror(errno));
|
||||
err++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("%% Warning: stat() failed on %s: %s\n",
|
||||
quagga_config, safe_strerror(errno));
|
||||
err++;
|
||||
}
|
||||
|
||||
fclose (fp);
|
||||
|
||||
if (chmod (integrate_default, CONFIGFILE_MASK) != 0)
|
||||
{
|
||||
fprintf (stdout,"%% Can't chmod configuration file %s: %s\n",
|
||||
integrate_default, safe_strerror(errno));
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
if (chmod (host.config, CONFIGFILE_MASK) != 0)
|
||||
{
|
||||
fprintf (stdout,"%% Can't chmod configuration file %s: %s (%d)\n",
|
||||
integrate_default, safe_strerror(errno), errno);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
fprintf(stdout,"Integrated configuration saved to %s\n",integrate_default);
|
||||
|
||||
fprintf (stdout,"[OK]\n");
|
||||
printf ("Integrated configuration saved to %s\n", quagga_config);
|
||||
if (err)
|
||||
return CMD_WARNING;
|
||||
|
||||
printf ("[OK]\n");
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static bool vtysh_writeconfig_integrated(void)
|
||||
static bool want_config_integrated(void)
|
||||
{
|
||||
struct stat s;
|
||||
|
||||
switch (vtysh_write_integrated)
|
||||
{
|
||||
case WRITE_INTEGRATED_UNSPECIFIED:
|
||||
if (stat(integrate_default, &s) && errno == ENOENT)
|
||||
if (stat(quagga_config, &s) && errno == ENOENT)
|
||||
return false;
|
||||
return true;
|
||||
case WRITE_INTEGRATED_NO:
|
||||
@ -2487,42 +2513,34 @@ DEFUN (vtysh_write_memory,
|
||||
int ret = CMD_SUCCESS;
|
||||
char line[] = "write memory\n";
|
||||
u_int i;
|
||||
FILE *fp;
|
||||
|
||||
fprintf (stdout, "Note: this version of vtysh never writes vtysh.conf\n");
|
||||
|
||||
/* If integrated Quagga.conf explicitely set. */
|
||||
if (vtysh_writeconfig_integrated())
|
||||
return write_config_integrated();
|
||||
else
|
||||
backup_config_file(integrate_default);
|
||||
if (want_config_integrated())
|
||||
{
|
||||
ret = CMD_WARNING;
|
||||
for (i = 0; i < array_size(vtysh_client); i++)
|
||||
if (vtysh_client[i].flag == VTYSH_WATCHQUAGGA)
|
||||
break;
|
||||
if (i < array_size(vtysh_client) && vtysh_client[i].fd != -1)
|
||||
ret = vtysh_client_execute (&vtysh_client[i], "write integrated", stdout);
|
||||
|
||||
if (ret != CMD_SUCCESS)
|
||||
{
|
||||
printf("\nWarning: attempting direct configuration write without "
|
||||
"watchquagga.\nFile permissions and ownership may be "
|
||||
"incorrect, or write may fail.\n\n");
|
||||
ret = vtysh_write_config_integrated();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
fprintf (stdout,"Building Configuration...\n");
|
||||
|
||||
|
||||
for (i = 0; i < array_size(vtysh_client); i++)
|
||||
ret = vtysh_client_execute (&vtysh_client[i], line, stdout);
|
||||
|
||||
|
||||
fp = fopen(host.config, "w");
|
||||
if (fp == NULL)
|
||||
{
|
||||
fprintf (stdout,"%% Can't open configuration file %s due to '%s'\n",
|
||||
host.config, safe_strerror(errno));
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
vtysh_config_write ();
|
||||
vtysh_config_dump (fp);
|
||||
|
||||
fclose (fp);
|
||||
|
||||
if (chmod (host.config, CONFIGFILE_MASK) != 0)
|
||||
{
|
||||
fprintf (stdout,"%% Can't chmod configuration file %s: %s\n",
|
||||
integrate_default, safe_strerror(errno));
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
fprintf (stdout,"[OK]\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,13 @@ DECLARE_MGROUP(MVTYSH)
|
||||
#define VTYSH_ISISD 0x40
|
||||
#define VTYSH_PIMD 0x100
|
||||
#define VTYSH_LDPD 0x200
|
||||
#define VTYSH_WATCHQUAGGA 0x400
|
||||
|
||||
/* commands in REALLYALL are crucial to correct vtysh operation */
|
||||
#define VTYSH_REALLYALL ~0U
|
||||
/* watchquagga is not in ALL since library CLI functions should not be
|
||||
* run on it (logging & co. should stay in a fixed/frozen config, and
|
||||
* things like prefix lists are not even initialised) */
|
||||
#define VTYSH_ALL VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_BGPD|VTYSH_ISISD|VTYSH_PIMD
|
||||
#define VTYSH_RMAP VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_PIMD
|
||||
#define VTYSH_INTERFACE VTYSH_ZEBRA|VTYSH_RIPD|VTYSH_RIPNGD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_LDPD|VTYSH_ISISD|VTYSH_PIMD
|
||||
@ -53,6 +59,8 @@ enum vtysh_write_integrated {
|
||||
|
||||
extern enum vtysh_write_integrated vtysh_write_integrated;
|
||||
|
||||
extern char *quagga_config;
|
||||
|
||||
void vtysh_init_vty (void);
|
||||
void vtysh_init_cmd (void);
|
||||
extern int vtysh_connect_all (const char *optional_daemon_name);
|
||||
@ -73,6 +81,7 @@ void config_add_line (struct list *, const char *);
|
||||
int vtysh_mark_file(const char *filename);
|
||||
|
||||
int vtysh_read_config (const char *);
|
||||
int vtysh_write_config_integrated (void);
|
||||
|
||||
void vtysh_config_parse_line (const char *);
|
||||
|
||||
|
@ -376,7 +376,6 @@ vtysh_read_config (const char *config_default_dir)
|
||||
FILE *confp = NULL;
|
||||
int ret;
|
||||
|
||||
host_config_set (config_default_dir);
|
||||
confp = fopen (config_default_dir, "r");
|
||||
if (confp == NULL)
|
||||
{
|
||||
|
@ -35,7 +35,6 @@
|
||||
#include "getopt.h"
|
||||
#include "command.h"
|
||||
#include "memory.h"
|
||||
#include "privs.h"
|
||||
#include "linklist.h"
|
||||
#include "memory_vty.h"
|
||||
|
||||
@ -45,30 +44,10 @@
|
||||
/* VTY shell program name. */
|
||||
char *progname;
|
||||
|
||||
static zebra_capabilities_t _caps_p [] =
|
||||
{
|
||||
ZCAP_BIND,
|
||||
ZCAP_NET_RAW,
|
||||
ZCAP_NET_ADMIN,
|
||||
};
|
||||
|
||||
struct zebra_privs_t vtysh_privs =
|
||||
{
|
||||
#if defined(QUAGGA_USER) && defined(QUAGGA_GROUP)
|
||||
.user = QUAGGA_USER,
|
||||
.group = QUAGGA_GROUP,
|
||||
#endif
|
||||
#ifdef VTY_GROUP
|
||||
.vty_group = VTY_GROUP,
|
||||
#endif
|
||||
.caps_p = _caps_p,
|
||||
.cap_num_p = array_size(_caps_p),
|
||||
.cap_num_i = 0,
|
||||
};
|
||||
|
||||
/* Configuration file name and directory. */
|
||||
char config_default[] = SYSCONFDIR VTYSH_DEFAULT_CONFIG;
|
||||
char quagga_config_default[] = SYSCONFDIR QUAGGA_DEFAULT_CONFIG;
|
||||
static char vtysh_config_always[] = SYSCONFDIR VTYSH_DEFAULT_CONFIG;
|
||||
static char quagga_config_default[] = SYSCONFDIR QUAGGA_DEFAULT_CONFIG;
|
||||
char *quagga_config = quagga_config_default;
|
||||
char history_file[MAXPATHLEN];
|
||||
|
||||
/* Flag for indicate executing child command. */
|
||||
@ -166,6 +145,7 @@ usage (int status)
|
||||
"-E, --echo Echo prompt and command in -c mode\n" \
|
||||
"-C, --dryrun Check configuration for validity and exit\n" \
|
||||
"-m, --markfile Mark input file with context end\n"
|
||||
"-w, --writeconfig Write integrated config (Quagga.conf) and exit\n"
|
||||
"-h, --help Display this help and exit\n\n" \
|
||||
"Note that multiple commands may be executed from the command\n" \
|
||||
"line by passing multiple -c args, or by embedding linefeed\n" \
|
||||
@ -189,6 +169,7 @@ struct option longopts[] =
|
||||
{ "help", no_argument, NULL, 'h'},
|
||||
{ "noerror", no_argument, NULL, 'n'},
|
||||
{ "mark", no_argument, NULL, 'm'},
|
||||
{ "writeconfig", no_argument, NULL, 'w'},
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
@ -289,6 +270,7 @@ main (int argc, char **argv, char **env)
|
||||
int echo_command = 0;
|
||||
int no_error = 0;
|
||||
int markfile = 0;
|
||||
int writeconfig = 0;
|
||||
int ret = 0;
|
||||
char *homedir = NULL;
|
||||
|
||||
@ -302,7 +284,7 @@ main (int argc, char **argv, char **env)
|
||||
/* Option handling. */
|
||||
while (1)
|
||||
{
|
||||
opt = getopt_long (argc, argv, "be:c:d:nf:mEhC", longopts, 0);
|
||||
opt = getopt_long (argc, argv, "be:c:d:nf:mEhCw", longopts, 0);
|
||||
|
||||
if (opt == EOF)
|
||||
break;
|
||||
@ -346,6 +328,9 @@ main (int argc, char **argv, char **env)
|
||||
case 'C':
|
||||
dryrun = 1;
|
||||
break;
|
||||
case 'w':
|
||||
writeconfig = 1;
|
||||
break;
|
||||
case 'h':
|
||||
usage (0);
|
||||
break;
|
||||
@ -355,12 +340,22 @@ main (int argc, char **argv, char **env)
|
||||
}
|
||||
}
|
||||
|
||||
if (markfile + writeconfig + dryrun + boot_flag > 1)
|
||||
{
|
||||
fprintf (stderr, "Invalid combination of arguments. Please specify at "
|
||||
"most one of:\n\t-b, -C, -m, -w\n");
|
||||
return 1;
|
||||
}
|
||||
if (inputfile && (writeconfig || boot_flag))
|
||||
{
|
||||
fprintf (stderr, "WARNING: Combinining the -f option with -b or -w is "
|
||||
"NOT SUPPORTED since its\nresults are inconsistent!\n");
|
||||
}
|
||||
|
||||
/* Initialize user input buffer. */
|
||||
line_read = NULL;
|
||||
setlinebuf(stdout);
|
||||
|
||||
zprivs_init (&vtysh_privs);
|
||||
|
||||
/* Signal and others. */
|
||||
vtysh_signal_init ();
|
||||
|
||||
@ -373,7 +368,7 @@ main (int argc, char **argv, char **env)
|
||||
vty_init_vtysh ();
|
||||
|
||||
/* Read vtysh configuration file before connecting to daemons. */
|
||||
vtysh_read_config(config_default);
|
||||
vtysh_read_config(vtysh_config_always);
|
||||
|
||||
if (markfile)
|
||||
{
|
||||
@ -422,6 +417,12 @@ main (int argc, char **argv, char **env)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (writeconfig)
|
||||
{
|
||||
vtysh_execute ("enable");
|
||||
return vtysh_write_config_integrated ();
|
||||
}
|
||||
|
||||
if (inputfile)
|
||||
{
|
||||
vtysh_flock_config (inputfile);
|
||||
@ -512,17 +513,17 @@ main (int argc, char **argv, char **env)
|
||||
history_truncate_file(history_file,1000);
|
||||
exit (0);
|
||||
}
|
||||
|
||||
|
||||
/* Boot startup configuration file. */
|
||||
if (boot_flag)
|
||||
{
|
||||
vtysh_flock_config (integrate_default);
|
||||
int ret = vtysh_read_config (integrate_default);
|
||||
vtysh_flock_config (quagga_config);
|
||||
int ret = vtysh_read_config (quagga_config);
|
||||
vtysh_unflock_config ();
|
||||
if (ret)
|
||||
{
|
||||
fprintf (stderr, "Configuration file[%s] processing failure: %d\n",
|
||||
integrate_default, ret);
|
||||
quagga_config, ret);
|
||||
if (no_error)
|
||||
exit (0);
|
||||
else
|
||||
|
@ -7,5 +7,7 @@ AM_CFLAGS = $(WERROR)
|
||||
|
||||
sbin_PROGRAMS = watchquagga
|
||||
|
||||
watchquagga_SOURCES = watchquagga.c
|
||||
noinst_HEADERS = watchquagga.h
|
||||
|
||||
watchquagga_SOURCES = watchquagga.c watchquagga_vty.c
|
||||
watchquagga_LDADD = ../lib/libzebra.la @LIBCAP@
|
||||
|
@ -24,12 +24,17 @@
|
||||
#include <network.h>
|
||||
#include <sigevent.h>
|
||||
#include <lib/version.h>
|
||||
#include "command.h"
|
||||
#include "memory_vty.h"
|
||||
|
||||
#include <getopt.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/wait.h>
|
||||
#include <memory.h>
|
||||
#include <systemd.h>
|
||||
|
||||
#include "watchquagga.h"
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(X,Y) (((X) <= (Y)) ? (X) : (Y))
|
||||
#endif
|
||||
@ -437,6 +442,12 @@ sigchild(void)
|
||||
return;
|
||||
}
|
||||
|
||||
if (child == integrated_write_pid)
|
||||
{
|
||||
integrated_write_sigchld(status);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((restart = find_child(child)) != NULL)
|
||||
{
|
||||
name = restart->name;
|
||||
@ -682,6 +693,28 @@ handle_read(struct thread *t_read)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Wait till we notice that all daemons are ready before
|
||||
* we send we are ready to systemd
|
||||
*/
|
||||
static void
|
||||
daemon_send_ready (void)
|
||||
{
|
||||
static int sent = 0;
|
||||
if (!sent && gs.numdown == 0)
|
||||
{
|
||||
#if defined (HAVE_CUMULUS)
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen("/var/run/quagga/watchquagga.started", "w");
|
||||
fclose(fp);
|
||||
#endif
|
||||
zlog_notice ("Watchquagga: Notifying Systemd we are up and running");
|
||||
systemd_send_started(master, 0);
|
||||
sent = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
daemon_up(struct daemon *dmn, const char *why)
|
||||
{
|
||||
@ -689,6 +722,7 @@ daemon_up(struct daemon *dmn, const char *why)
|
||||
gs.numdown--;
|
||||
dmn->connect_tries = 0;
|
||||
zlog_notice("%s state -> up : %s",dmn->name,why);
|
||||
daemon_send_ready();
|
||||
if (gs.do_ping)
|
||||
SET_WAKEUP_ECHO(dmn);
|
||||
phase_check();
|
||||
@ -775,9 +809,9 @@ try_connect(struct daemon *dmn)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (set_nonblocking(sock) < 0)
|
||||
if (set_nonblocking(sock) < 0 || set_cloexec(sock) < 0)
|
||||
{
|
||||
zlog_err("%s(%s): set_nonblocking(%d) failed",
|
||||
zlog_err("%s(%s): set_nonblocking/cloexec(%d) failed",
|
||||
__func__, addr.sun_path, sock);
|
||||
close(sock);
|
||||
return -1;
|
||||
@ -1028,6 +1062,13 @@ translate_blanks(const char *cmd, const char *blankstr)
|
||||
return res;
|
||||
}
|
||||
|
||||
struct zebra_privs_t watchquagga_privs =
|
||||
{
|
||||
#ifdef VTY_GROUP
|
||||
.vty_group = VTY_GROUP,
|
||||
#endif
|
||||
};
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
@ -1283,8 +1324,16 @@ main(int argc, char **argv)
|
||||
}
|
||||
|
||||
gs.restart.interval = gs.min_restart_interval;
|
||||
|
||||
zprivs_init (&watchquagga_privs);
|
||||
|
||||
master = thread_master_create();
|
||||
systemd_send_started (master, 0);
|
||||
cmd_init(-1);
|
||||
memory_init();
|
||||
vty_init(master);
|
||||
watchquagga_vty_init();
|
||||
vty_serv_sock(NULL, 0, WATCHQUAGGA_VTYSH_PATH);
|
||||
|
||||
signal_init (master, array_size(my_signals), my_signals);
|
||||
srandom(time(NULL));
|
||||
|
||||
@ -1335,7 +1384,7 @@ main(int argc, char **argv)
|
||||
return usage(progname,1);
|
||||
}
|
||||
|
||||
zlog_default = openzlog(progname, ZLOG_NONE, 0,
|
||||
zlog_default = openzlog(progname, ZLOG_WATCHQUAGGA, 0,
|
||||
LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON);
|
||||
zlog_set_level(NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED);
|
||||
if (daemon_mode)
|
||||
|
29
watchquagga/watchquagga.h
Normal file
29
watchquagga/watchquagga.h
Normal file
@ -0,0 +1,29 @@
|
||||
/*
|
||||
Common definitions for watchquagga API socket.
|
||||
|
||||
Copyright (C) 2016 David Lamparter for NetDEF, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef QUAGGA_WATCHQUAGGA_H
|
||||
#define QUAGGA_WATCHQUAGGA_H
|
||||
|
||||
extern void watchquagga_vty_init(void);
|
||||
|
||||
extern pid_t integrated_write_pid;
|
||||
extern void integrated_write_sigchld(int status);
|
||||
|
||||
#endif /* QUAGGA_WATCHQUAGGA_H */
|
134
watchquagga/watchquagga_vty.c
Normal file
134
watchquagga/watchquagga_vty.c
Normal file
@ -0,0 +1,134 @@
|
||||
/*
|
||||
watchquagga CLI functions.
|
||||
|
||||
Copyright (C) 2016 David Lamparter for NetDEF, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <zebra.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "memory.h"
|
||||
#include "log.h"
|
||||
#include "vty.h"
|
||||
#include "command.h"
|
||||
|
||||
#include "watchquagga.h"
|
||||
|
||||
pid_t integrated_write_pid;
|
||||
static int integrated_result_fd;
|
||||
|
||||
DEFUN (config_write_integrated,
|
||||
config_write_integrated_cmd,
|
||||
"write integrated",
|
||||
"Write running configuration to memory, network, or terminal\n"
|
||||
"Write integrated all-daemon Quagga.conf file\n")
|
||||
{
|
||||
pid_t child;
|
||||
sigset_t oldmask, sigmask;
|
||||
|
||||
if (integrated_write_pid != -1) {
|
||||
vty_out(vty, "%% configuration write already in progress.%s",
|
||||
VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
|
||||
/* need to temporarily block SIGCHLD because it could arrive between
|
||||
* fork() call and setting the integrated_write_pid variable. This
|
||||
* would mean the completion call gets lost and this hangs forever.
|
||||
*/
|
||||
sigemptyset(&oldmask);
|
||||
sigemptyset(&sigmask);
|
||||
sigaddset(&sigmask, SIGCHLD);
|
||||
sigprocmask(SIG_BLOCK, &sigmask, &oldmask);
|
||||
|
||||
child = fork();
|
||||
if (child == -1) {
|
||||
vty_out(vty, "%% configuration write fork() failed: %s.%s",
|
||||
safe_strerror(errno), VTY_NEWLINE);
|
||||
sigprocmask(SIG_SETMASK, &oldmask, NULL);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
if (child != 0) {
|
||||
/* note: the VTY won't write a command return value to vtysh; the
|
||||
* session temporarily enters an intentional "hang" state. This is
|
||||
* to make sure latency in vtysh doing the config write (several
|
||||
* seconds is not rare to see) does not interfere with watchquagga's
|
||||
* supervisor job.
|
||||
*
|
||||
* The fd is duplicated here so we don't need to hold a vty pointer
|
||||
* (which could become invalid in the meantime).
|
||||
*/
|
||||
integrated_write_pid = child;
|
||||
integrated_result_fd = dup(vty->wfd);
|
||||
sigprocmask(SIG_SETMASK, &oldmask, NULL);
|
||||
return CMD_SUSPEND;
|
||||
}
|
||||
|
||||
/* redirect stdout/stderr to vty session. Note vty->wfd is marked
|
||||
* CLOEXEC, but dup2 will clear that flag. */
|
||||
dup2(vty->wfd, 1);
|
||||
dup2(vty->wfd, 2);
|
||||
|
||||
/* don't allow the user to pass parameters, we're root here!
|
||||
* should probably harden vtysh at some point too... */
|
||||
execl(VTYSH_BIN_PATH, "vtysh", "-w", NULL);
|
||||
|
||||
/* unbuffered write; we just messed with stdout... */
|
||||
char msg[512];
|
||||
snprintf(msg, sizeof(msg), "error executing %s: %s\n",
|
||||
VTYSH_BIN_PATH, safe_strerror(errno));
|
||||
write(1, msg, strlen(msg));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void integrated_write_sigchld(int status)
|
||||
{
|
||||
uint8_t reply[4] = { 0, 0, 0, CMD_WARNING };
|
||||
|
||||
if (WIFEXITED(status)) {
|
||||
zlog_info("configuration write completed with exit code %d",
|
||||
WEXITSTATUS(status));
|
||||
reply[3] = WEXITSTATUS(status);
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
zlog_warn("configuration write terminated by signal %d",
|
||||
WTERMSIG(status));
|
||||
} else {
|
||||
zlog_warn("configuration write terminated");
|
||||
}
|
||||
|
||||
if (reply[3] != CMD_SUCCESS) {
|
||||
/* failure might be silent in vtysh without this */
|
||||
static const char msg[] = "% Configuration write failed.\n";
|
||||
write(integrated_result_fd, msg, strlen(msg));
|
||||
}
|
||||
|
||||
/* don't care about failures here, if the connection is broken the
|
||||
* return value will just be lost. */
|
||||
write(integrated_result_fd, reply, sizeof(reply));
|
||||
close(integrated_result_fd);
|
||||
|
||||
integrated_write_pid = -1;
|
||||
}
|
||||
|
||||
void watchquagga_vty_init(void)
|
||||
{
|
||||
integrated_write_pid = -1;
|
||||
install_element(ENABLE_NODE, &config_write_integrated_cmd);
|
||||
}
|
Loading…
Reference in New Issue
Block a user