]> git.proxmox.com Git - mirror_frr.git/commitdiff
vtysh: use fork() workflow for -f too
authorQuentin Young <qlyoung@nvidia.com>
Fri, 19 Nov 2021 21:03:02 +0000 (16:03 -0500)
committerDonald Sharp <sharpd@nvidia.com>
Tue, 28 Mar 2023 14:10:33 +0000 (10:10 -0400)
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>
vtysh/vtysh.c
vtysh/vtysh.h
vtysh/vtysh_config.c
vtysh/vtysh_main.c

index 7c9c46202e10877c0dcf973bd66797a65b48dc26..4d52bd036d0380bf6bb90c5c38c08810e4a95e49 100644 (file)
@@ -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");
index 640922eed92f61f74e5d0407f08221983fffe6ec..1c2cca9d902cf37b4f76fd114fec37f733fce47a 100644 (file)
@@ -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 *);
index 905761a01110a1b179bf1418b1a15d9e54fce6d2..0a0c745fda12985413e91b7a96d42cd58f653708 100644 (file)
@@ -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
index 053d66324518e6b88ecd53d2e07ae6e22b421022..860d79d5f9adaf02f137a5f17710803f56d580d8 100644 (file)
@@ -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);