summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorQuentin Young <qlyoung@nvidia.com>2021-11-19 16:03:02 -0500
committerDonald Sharp <sharpd@nvidia.com>2023-03-28 10:10:33 -0400
commitac768090270459cd032f5f325a8dffa27819c541 (patch)
tree9e4dbf2276fffe4b4a4ae690ee85cb572af964a3
parent449f66552fd85277f9fa8724ae9c26e652ded7e0 (diff)
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>
-rw-r--r--vtysh/vtysh.c2
-rw-r--r--vtysh/vtysh.h2
-rw-r--r--vtysh/vtysh_config.c99
-rw-r--r--vtysh/vtysh_main.c120
4 files changed, 108 insertions, 115 deletions
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index 7c9c46202e..4d52bd036d 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -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");
diff --git a/vtysh/vtysh.h b/vtysh/vtysh.h
index 640922eed9..1c2cca9d90 100644
--- a/vtysh/vtysh.h
+++ b/vtysh/vtysh.h
@@ -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 *);
diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c
index 905761a011..0a0c745fda 100644
--- a/vtysh/vtysh_config.c
+++ b/vtysh/vtysh_config.c
@@ -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
diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c
index 053d663245..860d79d5f9 100644
--- a/vtysh/vtysh_main.c
+++ b/vtysh/vtysh_main.c
@@ -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);