mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-04-28 21:20:48 +00:00
vtysh: use fork() workflow for -f too
It was being used for -b only; we should be able to use it for -f as well. This also merges the codepaths for -b and -f since they have no real functional difference. Signed-off-by: Quentin Young <qlyoung@nvidia.com>
This commit is contained in:
parent
449f66552f
commit
ac76809027
@ -3536,7 +3536,7 @@ DEFUN (vtysh_copy_to_running,
|
||||
int ret;
|
||||
const char *fname = argv[1]->arg;
|
||||
|
||||
ret = vtysh_read_config(fname, true);
|
||||
ret = vtysh_apply_config(fname, true, false);
|
||||
|
||||
/* Return to enable mode - the 'read_config' api leaves us up a level */
|
||||
vtysh_execute_no_pager("enable");
|
||||
|
@ -98,7 +98,7 @@ void config_add_line(struct list *, const char *);
|
||||
|
||||
int vtysh_mark_file(const char *filename);
|
||||
|
||||
int vtysh_read_config(const char *filename, bool dry_run);
|
||||
int vtysh_apply_config(const char *config_file_path, bool dry_run, bool fork);
|
||||
int vtysh_write_config_integrated(void);
|
||||
|
||||
void vtysh_config_parse_line(void *, const char *);
|
||||
|
@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
#include <zebra.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "command.h"
|
||||
#include "linklist.h"
|
||||
@ -625,18 +626,20 @@ static int vtysh_read_file(FILE *confp, bool dry_run)
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/* Read up configuration file from config_default_dir. */
|
||||
int vtysh_read_config(const char *config_default_dir, bool dry_run)
|
||||
/*
|
||||
* Read configuration file and send it to all connected daemons
|
||||
*/
|
||||
static int vtysh_read_config(const char *config_file_path, bool dry_run)
|
||||
{
|
||||
FILE *confp = NULL;
|
||||
bool save;
|
||||
int ret;
|
||||
|
||||
confp = fopen(config_default_dir, "r");
|
||||
confp = fopen(config_file_path, "r");
|
||||
if (confp == NULL) {
|
||||
fprintf(stderr,
|
||||
"%% Can't open configuration file %s due to '%s'.\n",
|
||||
config_default_dir, safe_strerror(errno));
|
||||
config_file_path, safe_strerror(errno));
|
||||
return CMD_ERR_NO_FILE;
|
||||
}
|
||||
|
||||
@ -648,7 +651,93 @@ int vtysh_read_config(const char *config_default_dir, bool dry_run)
|
||||
|
||||
vtysh_add_timestamp = save;
|
||||
|
||||
return (ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int vtysh_apply_config(const char *config_file_path, bool dry_run, bool do_fork)
|
||||
{
|
||||
/*
|
||||
* We need to apply the whole config file to all daemons. Instead of
|
||||
* having one client talk to N daemons, we fork N times and let each
|
||||
* child handle one daemon.
|
||||
*/
|
||||
pid_t fork_pid = getpid();
|
||||
int status = 0;
|
||||
int ret;
|
||||
int my_client_type;
|
||||
char my_client[64];
|
||||
|
||||
if (do_fork) {
|
||||
for (unsigned int i = 0; i < array_size(vtysh_client); i++) {
|
||||
/* Store name of client this fork will handle */
|
||||
strlcpy(my_client, vtysh_client[i].name,
|
||||
sizeof(my_client));
|
||||
my_client_type = vtysh_client[i].flag;
|
||||
fork_pid = fork();
|
||||
|
||||
/* If child, break */
|
||||
if (fork_pid == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
/* parent, wait for children */
|
||||
if (fork_pid != 0) {
|
||||
fprintf(stdout,
|
||||
"Waiting for children to finish applying config...\n");
|
||||
while (wait(&status) > 0)
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* children, grow up to be cowboys
|
||||
*/
|
||||
for (unsigned int i = 0; i < array_size(vtysh_client); i++) {
|
||||
if (my_client_type != vtysh_client[i].flag) {
|
||||
struct vtysh_client *cl;
|
||||
|
||||
/*
|
||||
* If this is a client we aren't responsible
|
||||
* for, disconnect
|
||||
*/
|
||||
for (cl = &vtysh_client[i]; cl; cl = cl->next) {
|
||||
if (cl->fd >= 0)
|
||||
close(cl->fd);
|
||||
cl->fd = -1;
|
||||
}
|
||||
} else if (vtysh_client[i].fd == -1 &&
|
||||
vtysh_client[i].next == NULL) {
|
||||
/*
|
||||
* If this is the client we are responsible
|
||||
* for, but we aren't already connected to that
|
||||
* client, that means the client isn't up in
|
||||
* the first place and we can exit early
|
||||
*/
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stdout, "[%d|%s] sending configuration\n", getpid(),
|
||||
my_client);
|
||||
}
|
||||
|
||||
ret = vtysh_read_config(config_file_path, dry_run);
|
||||
|
||||
if (ret) {
|
||||
if (do_fork)
|
||||
fprintf(stderr,
|
||||
"[%d|%s] Configuration file[%s] processing failure: %d\n",
|
||||
getpid(), my_client, frr_config, ret);
|
||||
else
|
||||
fprintf(stderr,
|
||||
"Configuration file[%s] processing failure: %d\n",
|
||||
frr_config, ret);
|
||||
} else if (do_fork) {
|
||||
fprintf(stderr, "[%d|%s] done\n", getpid(), my_client);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* We don't write vtysh specific into file from vtysh. vtysh.conf should
|
||||
|
@ -7,7 +7,6 @@
|
||||
|
||||
#include <sys/un.h>
|
||||
#include <setjmp.h>
|
||||
#include <sys/wait.h>
|
||||
#include <pwd.h>
|
||||
#include <sys/file.h>
|
||||
#include <unistd.h>
|
||||
@ -345,8 +344,6 @@ int main(int argc, char **argv, char **env)
|
||||
char pathspace[MAXPATHLEN] = "";
|
||||
const char *histfile = NULL;
|
||||
const char *histfile_env = getenv("VTYSH_HISTFILE");
|
||||
char my_client[64];
|
||||
int my_client_type;
|
||||
|
||||
/* SUID: drop down to calling user & go back up when needed */
|
||||
elevuid = geteuid();
|
||||
@ -497,7 +494,7 @@ int main(int argc, char **argv, char **env)
|
||||
/* Read vtysh configuration file before connecting to daemons.
|
||||
* (file may not be readable to calling user in SUID mode) */
|
||||
suid_on();
|
||||
vtysh_read_config(vtysh_config, dryrun);
|
||||
vtysh_apply_config(vtysh_config, dryrun, false);
|
||||
suid_off();
|
||||
}
|
||||
/* Error code library system */
|
||||
@ -516,9 +513,9 @@ int main(int argc, char **argv, char **env)
|
||||
/* Start execution only if not in dry-run mode */
|
||||
if (dryrun && !cmd) {
|
||||
if (inputfile) {
|
||||
ret = vtysh_read_config(inputfile, dryrun);
|
||||
ret = vtysh_apply_config(inputfile, dryrun, false);
|
||||
} else {
|
||||
ret = vtysh_read_config(frr_config, dryrun);
|
||||
ret = vtysh_apply_config(frr_config, dryrun, false);
|
||||
}
|
||||
|
||||
exit(ret);
|
||||
@ -597,10 +594,17 @@ int main(int argc, char **argv, char **env)
|
||||
return vtysh_write_config_integrated();
|
||||
}
|
||||
|
||||
if (inputfile) {
|
||||
if (boot_flag)
|
||||
inputfile = frr_config;
|
||||
|
||||
if (inputfile || boot_flag) {
|
||||
vtysh_flock_config(inputfile);
|
||||
ret = vtysh_read_config(inputfile, dryrun);
|
||||
ret = vtysh_apply_config(inputfile, dryrun, !no_fork);
|
||||
vtysh_unflock_config();
|
||||
|
||||
if (no_error)
|
||||
ret = 0;
|
||||
|
||||
exit(ret);
|
||||
}
|
||||
|
||||
@ -717,106 +721,6 @@ int main(int argc, char **argv, char **env)
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* Boot startup configuration file. */
|
||||
if (boot_flag) {
|
||||
/*
|
||||
* flock config file before fork. After fork, each child will
|
||||
* hold the same lock. The lock can be released by any one of
|
||||
* them but they will exit without releasing the lock - the
|
||||
* parent (us) will release it when they are done
|
||||
*/
|
||||
vtysh_flock_config(frr_config);
|
||||
|
||||
/*
|
||||
* In boot mode, we need to apply the whole config file to all
|
||||
* daemons. Instead of having one client talk to N daemons, we
|
||||
* fork N times and let each child handle one daemon.
|
||||
*/
|
||||
pid_t fork_pid = getpid();
|
||||
int status = 0;
|
||||
|
||||
if (!no_fork) {
|
||||
for (unsigned int i = 0; i < array_size(vtysh_client);
|
||||
i++) {
|
||||
/* Store name of client this fork will handle */
|
||||
strlcpy(my_client, vtysh_client[i].name,
|
||||
sizeof(my_client));
|
||||
my_client_type = vtysh_client[i].flag;
|
||||
fork_pid = fork();
|
||||
|
||||
/* If child, break */
|
||||
if (fork_pid == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
/* parent, wait for children */
|
||||
if (fork_pid != 0) {
|
||||
fprintf(stdout,
|
||||
"Waiting for children to finish applying config...\n");
|
||||
while (wait(&status) > 0)
|
||||
;
|
||||
ret = 0;
|
||||
goto boot_done;
|
||||
}
|
||||
|
||||
/*
|
||||
* children, grow up to be cowboys
|
||||
*/
|
||||
for (unsigned int i = 0; i < array_size(vtysh_client);
|
||||
i++) {
|
||||
if (my_client_type != vtysh_client[i].flag) {
|
||||
struct vtysh_client *cl;
|
||||
|
||||
/*
|
||||
* If this is a client we aren't
|
||||
* responsible for, disconnect
|
||||
*/
|
||||
for (cl = &vtysh_client[i]; cl;
|
||||
cl = cl->next) {
|
||||
if (cl->fd >= 0)
|
||||
close(cl->fd);
|
||||
cl->fd = -1;
|
||||
}
|
||||
} else if (vtysh_client[i].fd == -1 &&
|
||||
vtysh_client[i].next == NULL) {
|
||||
/*
|
||||
* If this is the client we are
|
||||
* responsible for, but we aren't
|
||||
* already connected to that client,
|
||||
* that means the client isn't up in the
|
||||
* first place and we can exit early
|
||||
*/
|
||||
ret = 0;
|
||||
goto boot_done;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stdout, "[%d|%s] sending configuration\n",
|
||||
getpid(), my_client);
|
||||
}
|
||||
|
||||
ret = vtysh_read_config(frr_config, dryrun);
|
||||
if (ret) {
|
||||
if (!no_fork)
|
||||
fprintf(stderr,
|
||||
"[%d|%s] Configuration file[%s] processing failure: %d\n",
|
||||
getpid(), my_client, frr_config, ret);
|
||||
else
|
||||
fprintf(stderr,
|
||||
"Configuration file[%s] processing failure: %d\n",
|
||||
frr_config, ret);
|
||||
if (no_error)
|
||||
ret = 0;
|
||||
} else if (!no_fork) {
|
||||
fprintf(stderr, "[%d|%s] done\n", getpid(), my_client);
|
||||
}
|
||||
|
||||
boot_done:
|
||||
if (fork_pid != 0)
|
||||
vtysh_unflock_config();
|
||||
exit(ret);
|
||||
}
|
||||
|
||||
vtysh_readline_init();
|
||||
|
||||
vty_hello(vty);
|
||||
|
Loading…
Reference in New Issue
Block a user