]> git.proxmox.com Git - mirror_frr.git/blobdiff - vtysh/vtysh_main.c
Merge pull request #12798 from donaldsharp/rib_match_multicast
[mirror_frr.git] / vtysh / vtysh_main.c
index 76956574cca3af816319970c54afaa048b2ca70c..25b667252e51218dbc2df44974c0f591df524bae 100644 (file)
@@ -1,21 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
 /* Virtual terminal interface shell.
  * Copyright (C) 2000 Kunihiro Ishiguro
- *
- * This file is part of GNU Zebra.
- *
- * GNU Zebra 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, or (at your option) any
- * later version.
- *
- * GNU Zebra 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; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
 #include <zebra.h>
@@ -78,39 +63,58 @@ int execute_flag = 0;
 /* Flag to indicate if in user/unprivileged mode. */
 int user_mode;
 
-/* For sigsetjmp() & siglongjmp(). */
-static sigjmp_buf jmpbuf;
-
-/* Flag for avoid recursive siglongjmp() call. */
-static int jmpflag = 0;
-
-/* A static variable for holding the line. */
-static char *line_read;
-
 /* Master of threads. */
 struct thread_master *master;
 
 /* Command logging */
 FILE *logfile;
 
+static void vtysh_rl_callback(char *line_read)
+{
+       HIST_ENTRY *last;
+
+       rl_callback_handler_remove();
+
+       if (!line_read) {
+               vtysh_loop_exited = true;
+               return;
+       }
+
+       /* If the line has any text in it, save it on the history. But only if
+        * last command in history isn't the same one.
+        */
+       if (*line_read) {
+               using_history();
+               last = previous_history();
+               if (!last || strcmp(last->line, line_read) != 0) {
+                       add_history(line_read);
+                       append_history(1, history_file);
+               }
+       }
+
+       vtysh_execute(line_read);
+
+       if (!vtysh_loop_exited)
+               rl_callback_handler_install(vtysh_prompt(), vtysh_rl_callback);
+
+       free(line_read);
+}
+
 /* SIGTSTP handler.  This function care user's ^Z input. */
 static void sigtstp(int sig)
 {
+       rl_callback_handler_remove();
+
        /* Execute "end" command. */
        vtysh_execute("end");
 
+       if (!vtysh_loop_exited)
+               rl_callback_handler_install(vtysh_prompt(), vtysh_rl_callback);
+
        /* Initialize readline. */
        rl_initialize();
        printf("\n");
-
-       /* Check jmpflag for duplicate siglongjmp(). */
-       if (!jmpflag)
-               return;
-
-       jmpflag = 0;
-
-       /* Back to main command loop. */
-       siglongjmp(jmpbuf, 1);
+       rl_forced_update_display();
 }
 
 /* SIGINT handler.  This function care user's ^Z input.  */
@@ -208,32 +212,35 @@ struct option longopts[] = {
        {"timestamp", no_argument, NULL, 't'},
        {0}};
 
+bool vtysh_loop_exited;
+
+static struct thread *vtysh_rl_read_thread;
+
+static void vtysh_rl_read(struct thread *thread)
+{
+       thread_add_read(master, vtysh_rl_read, NULL, STDIN_FILENO,
+                       &vtysh_rl_read_thread);
+       rl_callback_read_char();
+}
+
 /* Read a string, and return a pointer to it.  Returns NULL on EOF. */
-static char *vtysh_rl_gets(void)
+static void vtysh_rl_run(void)
 {
-       HIST_ENTRY *last;
-       /* If the buffer has already been allocated, return the memory
-        * to the free pool. */
-       if (line_read) {
-               free(line_read);
-               line_read = NULL;
-       }
+       struct thread thread;
 
-       /* Get a line from the user.  Change prompt according to node.  XXX. */
-       line_read = readline(vtysh_prompt());
+       master = thread_master_create(NULL);
 
-       /* If the line has any text in it, save it on the history. But only if
-        * last command in history isn't the same one. */
-       if (line_read && *line_read) {
-               using_history();
-               last = previous_history();
-               if (!last || strcmp(last->line, line_read) != 0) {
-                       add_history(line_read);
-                       append_history(1, history_file);
-               }
-       }
+       rl_callback_handler_install(vtysh_prompt(), vtysh_rl_callback);
+       thread_add_read(master, vtysh_rl_read, NULL, STDIN_FILENO,
+                       &vtysh_rl_read_thread);
+
+       while (!vtysh_loop_exited && thread_fetch(master, &thread))
+               thread_call(&thread);
 
-       return (line_read);
+       if (!vtysh_loop_exited)
+               rl_callback_handler_remove();
+
+       thread_master_free(master);
 }
 
 static void log_it(const char *line)
@@ -332,6 +339,7 @@ int main(int argc, char **argv, char **env)
        const char *pathspace_arg = NULL;
        char pathspace[MAXPATHLEN] = "";
        const char *histfile = NULL;
+       const char *histfile_env = getenv("VTYSH_HISTFILE");
 
        /* SUID: drop down to calling user & go back up when needed */
        elevuid = geteuid();
@@ -458,7 +466,6 @@ int main(int argc, char **argv, char **env)
        }
 
        /* Initialize user input buffer. */
-       line_read = NULL;
        setlinebuf(stdout);
 
        /* Signal and others. */
@@ -587,13 +594,11 @@ int main(int argc, char **argv, char **env)
         * Setup history file for use by both -c and regular input
         * If we can't find the home directory, then don't store
         * the history information.
-        * VTYSH_HISTFILE is prefered over command line
+        * VTYSH_HISTFILE is preferred over command line
         * argument (-H/--histfile).
         */
-       if (getenv("VTYSH_HISTFILE")) {
-               const char *file = getenv("VTYSH_HISTFILE");
-
-               strlcpy(history_file, file, sizeof(history_file));
+       if (histfile_env) {
+               strlcpy(history_file, histfile_env, sizeof(history_file));
        } else if (histfile) {
                strlcpy(history_file, histfile, sizeof(history_file));
        } else {
@@ -725,13 +730,8 @@ int main(int argc, char **argv, char **env)
 
        vtysh_add_timestamp = ts_flag;
 
-       /* Preparation for longjmp() in sigtstp(). */
-       sigsetjmp(jmpbuf, 1);
-       jmpflag = 1;
-
        /* Main command loop. */
-       while (vtysh_rl_gets())
-               vtysh_execute(line_read);
+       vtysh_rl_run();
 
        vtysh_uninit();