back to topotato report
topotato coverage report
Current view: top level - vtysh - vtysh_main.c (source / functions) Hit Total Coverage
Test: aggregated run ( view descriptions ) Lines: 114 366 31.1 %
Date: 2023-02-24 19:38:44 Functions: 7 14 50.0 %

          Line data    Source code
       1             : /* Virtual terminal interface shell.
       2             :  * Copyright (C) 2000 Kunihiro Ishiguro
       3             :  *
       4             :  * This file is part of GNU Zebra.
       5             :  *
       6             :  * GNU Zebra is free software; you can redistribute it and/or modify it
       7             :  * under the terms of the GNU General Public License as published by the
       8             :  * Free Software Foundation; either version 2, or (at your option) any
       9             :  * later version.
      10             :  *
      11             :  * GNU Zebra is distributed in the hope that it will be useful, but
      12             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14             :  * General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU General Public License along
      17             :  * with this program; see the file COPYING; if not, write to the Free Software
      18             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      19             :  */
      20             : 
      21             : #include <zebra.h>
      22             : 
      23             : #include <sys/un.h>
      24             : #include <setjmp.h>
      25             : #include <sys/wait.h>
      26             : #include <pwd.h>
      27             : #include <sys/file.h>
      28             : #include <unistd.h>
      29             : 
      30             : /* readline carries some ancient definitions around */
      31             : #pragma GCC diagnostic push
      32             : #pragma GCC diagnostic ignored "-Wstrict-prototypes"
      33             : #include <readline/readline.h>
      34             : #include <readline/history.h>
      35             : #pragma GCC diagnostic pop
      36             : 
      37             : /*
      38             :  * The append_history function only appears in newer versions
      39             :  * of the readline library it appears like.  Since we don't
      40             :  * need this just silently ignore the code on these
      41             :  * ancient platforms.
      42             :  */
      43             : #if !defined HAVE_APPEND_HISTORY
      44             : #define append_history(A, B)
      45             : #endif
      46             : 
      47             : #include <lib/version.h>
      48             : #include "getopt.h"
      49             : #include "command.h"
      50             : #include "memory.h"
      51             : #include "linklist.h"
      52             : #include "libfrr.h"
      53             : #include "ferr.h"
      54             : #include "lib_errors.h"
      55             : 
      56             : #include "vtysh/vtysh.h"
      57             : #include "vtysh/vtysh_user.h"
      58             : 
      59             : /* VTY shell program name. */
      60             : char *progname;
      61             : 
      62             : /* SUID mode */
      63             : static uid_t elevuid, realuid;
      64             : static gid_t elevgid, realgid;
      65             : 
      66             : #define VTYSH_CONFIG_NAME "vtysh.conf"
      67             : #define FRR_CONFIG_NAME "frr.conf"
      68             : 
      69             : /* Configuration file name and directory. */
      70             : static char vtysh_config[MAXPATHLEN * 3];
      71             : char frr_config[MAXPATHLEN * 3];
      72             : char vtydir[MAXPATHLEN];
      73             : static char history_file[MAXPATHLEN];
      74             : 
      75             : /* Flag for indicate executing child command. */
      76             : int execute_flag = 0;
      77             : 
      78             : /* Flag to indicate if in user/unprivileged mode. */
      79             : int user_mode;
      80             : 
      81             : /* Master of threads. */
      82             : struct thread_master *master;
      83             : 
      84             : /* Command logging */
      85             : FILE *logfile;
      86             : 
      87           0 : static void vtysh_rl_callback(char *line_read)
      88             : {
      89           0 :         HIST_ENTRY *last;
      90             : 
      91           0 :         rl_callback_handler_remove();
      92             : 
      93           0 :         if (!line_read) {
      94           0 :                 vtysh_loop_exited = true;
      95           0 :                 return;
      96             :         }
      97             : 
      98             :         /* If the line has any text in it, save it on the history. But only if
      99             :          * last command in history isn't the same one.
     100             :          */
     101           0 :         if (*line_read) {
     102           0 :                 using_history();
     103           0 :                 last = previous_history();
     104           0 :                 if (!last || strcmp(last->line, line_read) != 0) {
     105           0 :                         add_history(line_read);
     106           0 :                         append_history(1, history_file);
     107             :                 }
     108             :         }
     109             : 
     110           0 :         vtysh_execute(line_read);
     111             : 
     112           0 :         if (!vtysh_loop_exited)
     113           0 :                 rl_callback_handler_install(vtysh_prompt(), vtysh_rl_callback);
     114             : 
     115           0 :         free(line_read);
     116             : }
     117             : 
     118             : /* SIGTSTP handler.  This function care user's ^Z input. */
     119           0 : static void sigtstp(int sig)
     120             : {
     121           0 :         rl_callback_handler_remove();
     122             : 
     123             :         /* Execute "end" command. */
     124           0 :         vtysh_execute("end");
     125             : 
     126           0 :         if (!vtysh_loop_exited)
     127           0 :                 rl_callback_handler_install(vtysh_prompt(), vtysh_rl_callback);
     128             : 
     129             :         /* Initialize readline. */
     130           0 :         rl_initialize();
     131           0 :         printf("\n");
     132           0 :         rl_forced_update_display();
     133           0 : }
     134             : 
     135             : /* SIGINT handler.  This function care user's ^Z input.  */
     136           0 : static void sigint(int sig)
     137             : {
     138             :         /* Check this process is not child process. */
     139           0 :         if (!execute_flag) {
     140           0 :                 rl_initialize();
     141           0 :                 printf("\n");
     142           0 :                 rl_forced_update_display();
     143             :         }
     144           0 : }
     145             : 
     146             : /* Signale wrapper for vtysh. We don't use sigevent because
     147             :  * vtysh doesn't use threads. TODO */
     148          24 : static void vtysh_signal_set(int signo, void (*func)(int))
     149             : {
     150          24 :         struct sigaction sig;
     151          24 :         struct sigaction osig;
     152             : 
     153          24 :         sig.sa_handler = func;
     154          24 :         sigemptyset(&sig.sa_mask);
     155          24 :         sig.sa_flags = 0;
     156             : #ifdef SA_RESTART
     157          24 :         sig.sa_flags |= SA_RESTART;
     158             : #endif /* SA_RESTART */
     159             : 
     160          24 :         sigaction(signo, &sig, &osig);
     161          24 : }
     162             : 
     163             : /* Initialization of signal handles. */
     164           8 : static void vtysh_signal_init(void)
     165             : {
     166           8 :         vtysh_signal_set(SIGINT, sigint);
     167           8 :         vtysh_signal_set(SIGTSTP, sigtstp);
     168           8 :         vtysh_signal_set(SIGPIPE, SIG_IGN);
     169           8 : }
     170             : 
     171             : /* Help information display. */
     172           0 : static void usage(int status)
     173             : {
     174           0 :         if (status != 0)
     175           0 :                 fprintf(stderr, "Try `%s --help' for more information.\n",
     176             :                         progname);
     177             :         else
     178           0 :                 printf("Usage : %s [OPTION...]\n\n"
     179             :                        "Integrated shell for FRR (version " FRR_VERSION
     180             :                        "). \n"
     181             :                        "Configured with:\n    " FRR_CONFIG_ARGS
     182             :                        "\n\n"
     183             :                        "-b, --boot               Execute boot startup configuration\n"
     184             :                        "-c, --command            Execute argument as command\n"
     185             :                        "-d, --daemon             Connect only to the specified daemon\n"
     186             :                        "-f, --inputfile          Execute commands from specific file and exit\n"
     187             :                        "-E, --echo               Echo prompt and command in -c mode\n"
     188             :                        "-C, --dryrun             Check configuration for validity and exit\n"
     189             :                        "-m, --markfile           Mark input file with context end\n"
     190             :                        "    --vty_socket         Override vty socket path\n"
     191             :                        "    --config_dir         Override config directory path\n"
     192             :                        "-N  --pathspace          Insert prefix into config & socket paths\n"
     193             :                        "-u  --user               Run as an unprivileged user\n"
     194             :                        "-w, --writeconfig        Write integrated config (frr.conf) and exit\n"
     195             :                        "-H, --histfile           Override history file\n"
     196             :                        "-h, --help               Display this help and exit\n\n"
     197             :                        "Note that multiple commands may be executed from the command\n"
     198             :                        "line by passing multiple -c args, or by embedding linefeed\n"
     199             :                        "characters in one or more of the commands.\n\n"
     200             :                        "Report bugs to %s\n",
     201             :                        progname, FRR_BUG_ADDRESS);
     202             : 
     203           0 :         exit(status);
     204             : }
     205             : 
     206             : /* VTY shell options, we use GNU getopt library. */
     207             : #define OPTION_VTYSOCK 1000
     208             : #define OPTION_CONFDIR 1001
     209             : struct option longopts[] = {
     210             :         {"boot", no_argument, NULL, 'b'},
     211             :         /* For compatibility with older zebra/quagga versions */
     212             :         {"eval", required_argument, NULL, 'e'},
     213             :         {"command", required_argument, NULL, 'c'},
     214             :         {"daemon", required_argument, NULL, 'd'},
     215             :         {"vty_socket", required_argument, NULL, OPTION_VTYSOCK},
     216             :         {"config_dir", required_argument, NULL, OPTION_CONFDIR},
     217             :         {"inputfile", required_argument, NULL, 'f'},
     218             :         {"histfile", required_argument, NULL, 'H'},
     219             :         {"echo", no_argument, NULL, 'E'},
     220             :         {"dryrun", no_argument, NULL, 'C'},
     221             :         {"help", no_argument, NULL, 'h'},
     222             :         {"noerror", no_argument, NULL, 'n'},
     223             :         {"mark", no_argument, NULL, 'm'},
     224             :         {"writeconfig", no_argument, NULL, 'w'},
     225             :         {"pathspace", required_argument, NULL, 'N'},
     226             :         {"user", no_argument, NULL, 'u'},
     227             :         {"timestamp", no_argument, NULL, 't'},
     228             :         {0}};
     229             : 
     230             : bool vtysh_loop_exited;
     231             : 
     232             : static struct thread *vtysh_rl_read_thread;
     233             : 
     234           0 : static void vtysh_rl_read(struct thread *thread)
     235             : {
     236           0 :         thread_add_read(master, vtysh_rl_read, NULL, STDIN_FILENO,
     237             :                         &vtysh_rl_read_thread);
     238           0 :         rl_callback_read_char();
     239           0 : }
     240             : 
     241             : /* Read a string, and return a pointer to it.  Returns NULL on EOF. */
     242           0 : static void vtysh_rl_run(void)
     243             : {
     244           0 :         struct thread thread;
     245             : 
     246           0 :         master = thread_master_create(NULL);
     247             : 
     248           0 :         rl_callback_handler_install(vtysh_prompt(), vtysh_rl_callback);
     249           0 :         thread_add_read(master, vtysh_rl_read, NULL, STDIN_FILENO,
     250             :                         &vtysh_rl_read_thread);
     251             : 
     252           0 :         while (!vtysh_loop_exited && thread_fetch(master, &thread))
     253           0 :                 thread_call(&thread);
     254             : 
     255           0 :         if (!vtysh_loop_exited)
     256           0 :                 rl_callback_handler_remove();
     257             : 
     258           0 :         thread_master_free(master);
     259           0 : }
     260             : 
     261           0 : static void log_it(const char *line)
     262             : {
     263           0 :         time_t t = time(NULL);
     264           0 :         struct tm tmp;
     265           0 :         const char *user = getenv("USER");
     266           0 :         char tod[64];
     267             : 
     268           0 :         localtime_r(&t, &tmp);
     269           0 :         if (!user)
     270           0 :                 user = "boot";
     271             : 
     272           0 :         strftime(tod, sizeof(tod), "%Y%m%d-%H:%M.%S", &tmp);
     273             : 
     274           0 :         fprintf(logfile, "%s:%s %s\n", tod, user, line);
     275           0 : }
     276             : 
     277             : static int flock_fd;
     278             : 
     279           8 : static void vtysh_flock_config(const char *flock_file)
     280             : {
     281           8 :         int count = 0;
     282             : 
     283           8 :         flock_fd = open(flock_file, O_RDONLY, 0644);
     284           8 :         if (flock_fd < 0) {
     285           0 :                 fprintf(stderr, "Unable to create lock file: %s, %s\n",
     286           0 :                         flock_file, safe_strerror(errno));
     287           0 :                 return;
     288             :         }
     289             : 
     290           8 :         while (count < 400 && (flock(flock_fd, LOCK_EX | LOCK_NB) < 0)) {
     291           0 :                 count++;
     292           0 :                 usleep(500000);
     293             :         }
     294             : 
     295           8 :         if (count >= 400)
     296           0 :                 fprintf(stderr,
     297             :                         "Flock of %s failed, continuing this may cause issues\n",
     298             :                         flock_file);
     299             : }
     300             : 
     301           8 : static void vtysh_unflock_config(void)
     302             : {
     303           8 :         flock(flock_fd, LOCK_UN);
     304           8 :         close(flock_fd);
     305           8 : }
     306             : 
     307          16 : void suid_on(void)
     308             : {
     309          16 :         if (elevuid != realuid && seteuid(elevuid)) {
     310           0 :                 perror("seteuid(on)");
     311           0 :                 exit(1);
     312             :         }
     313          16 :         if (elevgid != realgid && setegid(elevgid)) {
     314           0 :                 perror("setegid(on)");
     315           0 :                 exit(1);
     316             :         }
     317          16 : }
     318             : 
     319          24 : void suid_off(void)
     320             : {
     321          24 :         if (elevuid != realuid && seteuid(realuid)) {
     322           0 :                 perror("seteuid(off)");
     323           0 :                 exit(1);
     324             :         }
     325          24 :         if (elevgid != realgid && setegid(realgid)) {
     326           0 :                 perror("setegid(off)");
     327           0 :                 exit(1);
     328             :         }
     329          24 : }
     330             : 
     331             : /* VTY shell main routine. */
     332           8 : int main(int argc, char **argv, char **env)
     333             : {
     334           8 :         char *p;
     335           8 :         int opt;
     336           8 :         int dryrun = 0;
     337           8 :         int boot_flag = 0;
     338           8 :         bool ts_flag = false;
     339           8 :         const char *daemon_name = NULL;
     340           8 :         const char *inputfile = NULL;
     341           8 :         struct cmd_rec {
     342             :                 char *line;
     343             :                 struct cmd_rec *next;
     344           8 :         } *cmd = NULL;
     345           8 :         struct cmd_rec *tail = NULL;
     346           8 :         int echo_command = 0;
     347           8 :         int no_error = 0;
     348           8 :         int markfile = 0;
     349           8 :         int writeconfig = 0;
     350           8 :         int ret = 0;
     351           8 :         char *homedir = NULL;
     352           8 :         int ditch_suid = 0;
     353           8 :         char sysconfdir[MAXPATHLEN];
     354           8 :         const char *pathspace_arg = NULL;
     355           8 :         char pathspace[MAXPATHLEN] = "";
     356           8 :         const char *histfile = NULL;
     357           8 :         const char *histfile_env = getenv("VTYSH_HISTFILE");
     358             : 
     359             :         /* SUID: drop down to calling user & go back up when needed */
     360           8 :         elevuid = geteuid();
     361           8 :         elevgid = getegid();
     362           8 :         realuid = getuid();
     363           8 :         realgid = getgid();
     364           8 :         suid_off();
     365             : 
     366           8 :         user_mode = 0;          /* may be set in options processing */
     367             : 
     368             :         /* Preserve name of myself. */
     369           8 :         progname = ((p = strrchr(argv[0], '/')) ? ++p : argv[0]);
     370             : 
     371           8 :         strlcpy(sysconfdir, frr_sysconfdir, sizeof(sysconfdir));
     372             : 
     373           8 :         frr_init_vtydir();
     374           8 :         strlcpy(vtydir, frr_vtydir, sizeof(vtydir));
     375             : 
     376             :         /* Option handling. */
     377          32 :         while (1) {
     378          32 :                 opt = getopt_long(argc, argv, "be:c:d:nf:H:mEhCwN:ut", longopts,
     379             :                                   0);
     380             : 
     381          32 :                 if (opt == EOF)
     382             :                         break;
     383             : 
     384          24 :                 switch (opt) {
     385             :                 case 0:
     386             :                         break;
     387           0 :                 case 'b':
     388           0 :                         boot_flag = 1;
     389           0 :                         break;
     390           0 :                 case 'e':
     391             :                 case 'c': {
     392           0 :                         struct cmd_rec *cr;
     393           0 :                         cr = XMALLOC(MTYPE_TMP, sizeof(*cr));
     394           0 :                         cr->line = optarg;
     395           0 :                         cr->next = NULL;
     396           0 :                         if (tail)
     397           0 :                                 tail->next = cr;
     398             :                         else
     399             :                                 cmd = cr;
     400             :                         tail = cr;
     401             :                 } break;
     402           8 :                 case OPTION_VTYSOCK:
     403           8 :                         ditch_suid = 1; /* option disables SUID */
     404           8 :                         strlcpy(vtydir, optarg, sizeof(vtydir));
     405           8 :                         break;
     406           0 :                 case OPTION_CONFDIR:
     407           0 :                         ditch_suid = 1; /* option disables SUID */
     408           0 :                         snprintf(sysconfdir, sizeof(sysconfdir), "%s/", optarg);
     409           0 :                         break;
     410           0 :                 case 'N':
     411           0 :                         if (strchr(optarg, '/') || strchr(optarg, '.')) {
     412           0 :                                 fprintf(stderr,
     413             :                                         "slashes or dots are not permitted in the --pathspace option.\n");
     414           0 :                                 exit(1);
     415             :                         }
     416           0 :                         pathspace_arg = optarg;
     417           0 :                         snprintf(pathspace, sizeof(pathspace), "%s/", optarg);
     418           0 :                         break;
     419           8 :                 case 'd':
     420           8 :                         daemon_name = optarg;
     421           8 :                         break;
     422           8 :                 case 'f':
     423           8 :                         inputfile = optarg;
     424           8 :                         break;
     425           0 :                 case 'm':
     426           0 :                         markfile = 1;
     427           0 :                         break;
     428           0 :                 case 'n':
     429           0 :                         no_error = 1;
     430           0 :                         break;
     431           0 :                 case 'E':
     432           0 :                         echo_command = 1;
     433           0 :                         break;
     434           0 :                 case 'C':
     435           0 :                         dryrun = 1;
     436           0 :                         break;
     437           0 :                 case 'u':
     438           0 :                         user_mode = 1;
     439           0 :                         break;
     440           0 :                 case 't':
     441           0 :                         ts_flag = true;
     442           0 :                         break;
     443           0 :                 case 'w':
     444           0 :                         writeconfig = 1;
     445           0 :                         break;
     446           0 :                 case 'h':
     447           0 :                         usage(0);
     448             :                         break;
     449           0 :                 case 'H':
     450           0 :                         histfile = optarg;
     451           0 :                         break;
     452           0 :                 default:
     453           0 :                         usage(1);
     454             :                         break;
     455             :                 }
     456             :         }
     457             : 
     458           8 :         if (ditch_suid) {
     459           8 :                 elevuid = realuid;
     460           8 :                 elevgid = realgid;
     461             :         }
     462             : 
     463           8 :         if (markfile + writeconfig + dryrun + boot_flag > 1) {
     464           0 :                 fprintf(stderr,
     465             :                         "Invalid combination of arguments.  Please specify at most one of:\n\t-b, -C, -m, -w\n");
     466           0 :                 return 1;
     467             :         }
     468           8 :         if (inputfile && (writeconfig || boot_flag)) {
     469           0 :                 fprintf(stderr,
     470             :                         "WARNING: Combinining the -f option with -b or -w is NOT SUPPORTED since its\nresults are inconsistent!\n");
     471             :         }
     472             : 
     473           8 :         snprintf(vtysh_config, sizeof(vtysh_config), "%s%s%s", sysconfdir,
     474             :                  pathspace, VTYSH_CONFIG_NAME);
     475           8 :         snprintf(frr_config, sizeof(frr_config), "%s%s%s", sysconfdir,
     476             :                  pathspace, FRR_CONFIG_NAME);
     477             : 
     478           8 :         if (pathspace_arg) {
     479           0 :                 strlcat(vtydir, "/", sizeof(vtydir));
     480           0 :                 strlcat(vtydir, pathspace_arg, sizeof(vtydir));
     481             :         }
     482             : 
     483             :         /* Initialize user input buffer. */
     484           8 :         setlinebuf(stdout);
     485             : 
     486             :         /* Signal and others. */
     487           8 :         vtysh_signal_init();
     488             : 
     489             :         /* Make vty structure and register commands. */
     490           8 :         vtysh_init_vty();
     491           8 :         vtysh_init_cmd();
     492           8 :         vtysh_user_init();
     493           8 :         vtysh_config_init();
     494             : 
     495           8 :         vty_init_vtysh();
     496             : 
     497           8 :         if (!user_mode) {
     498             :                 /* Read vtysh configuration file before connecting to daemons.
     499             :                  * (file may not be readable to calling user in SUID mode) */
     500           8 :                 suid_on();
     501           8 :                 vtysh_read_config(vtysh_config, dryrun);
     502           8 :                 suid_off();
     503             :         }
     504             :         /* Error code library system */
     505           8 :         log_ref_init();
     506           8 :         lib_error_init();
     507             : 
     508           8 :         if (markfile) {
     509           0 :                 if (!inputfile) {
     510           0 :                         fprintf(stderr,
     511             :                                 "-f option MUST be specified with -m option\n");
     512           0 :                         return 1;
     513             :                 }
     514           0 :                 return (vtysh_mark_file(inputfile));
     515             :         }
     516             : 
     517             :         /* Start execution only if not in dry-run mode */
     518           8 :         if (dryrun && !cmd) {
     519           0 :                 if (inputfile) {
     520           0 :                         ret = vtysh_read_config(inputfile, dryrun);
     521             :                 } else {
     522           0 :                         ret = vtysh_read_config(frr_config, dryrun);
     523             :                 }
     524             : 
     525           0 :                 exit(ret);
     526             :         }
     527             : 
     528           8 :         if (dryrun && cmd && cmd->line) {
     529           0 :                 if (!user_mode)
     530           0 :                         vtysh_execute("enable");
     531           0 :                 while (cmd) {
     532           0 :                         struct cmd_rec *cr;
     533           0 :                         char *cmdnow = cmd->line, *next;
     534           0 :                         do {
     535           0 :                                 next = strchr(cmdnow, '\n');
     536           0 :                                 if (next)
     537           0 :                                         *next++ = '\0';
     538             : 
     539           0 :                                 if (echo_command)
     540           0 :                                         printf("%s%s\n", vtysh_prompt(),
     541             :                                                cmdnow);
     542             : 
     543           0 :                                 ret = vtysh_execute_no_pager(cmdnow);
     544           0 :                                 if (!no_error
     545           0 :                                     && !(ret == CMD_SUCCESS
     546           0 :                                          || ret == CMD_SUCCESS_DAEMON
     547             :                                          || ret == CMD_WARNING))
     548           0 :                                         exit(1);
     549           0 :                         } while ((cmdnow = next) != NULL);
     550             : 
     551           0 :                         cr = cmd;
     552           0 :                         cmd = cmd->next;
     553           0 :                         XFREE(MTYPE_TMP, cr);
     554             :                 }
     555           0 :                 exit(ret);
     556             :         }
     557             : 
     558             :         /* Ignore error messages */
     559           8 :         if (no_error) {
     560           0 :                 if (freopen("/dev/null", "w", stdout) == NULL) {
     561           0 :                         fprintf(stderr,
     562             :                                 "Exiting: Failed to duplicate stdout with -n option");
     563           0 :                         exit(1);
     564             :                 }
     565             :         }
     566             : 
     567             :         /* SUID: go back up elevated privs */
     568           8 :         suid_on();
     569             : 
     570             :         /* Make sure we pass authentication before proceeding. */
     571           8 :         vtysh_auth();
     572             : 
     573             :         /* Do not connect until we have passed authentication. */
     574           8 :         if (vtysh_connect_all(daemon_name) <= 0) {
     575           0 :                 fprintf(stderr, "Exiting: failed to connect to any daemons.\n");
     576           0 :                 if (geteuid() != 0)
     577           0 :                         fprintf(stderr,
     578             :                                 "Hint: if this seems wrong, try running me as a privileged user!\n");
     579           0 :                 if (no_error)
     580           0 :                         exit(0);
     581             :                 else
     582           0 :                         exit(1);
     583             :         }
     584             : 
     585             :         /* SUID: back down, don't need privs further on */
     586           8 :         suid_off();
     587             : 
     588           8 :         if (writeconfig) {
     589           0 :                 if (user_mode) {
     590           0 :                         fprintf(stderr,
     591             :                                 "writeconfig cannot be used when running as an unprivileged user.\n");
     592           0 :                         if (no_error)
     593           0 :                                 exit(0);
     594             :                         else
     595           0 :                                 exit(1);
     596             :                 }
     597           0 :                 vtysh_execute("enable");
     598           0 :                 return vtysh_write_config_integrated();
     599             :         }
     600             : 
     601           8 :         if (inputfile) {
     602           8 :                 vtysh_flock_config(inputfile);
     603           8 :                 ret = vtysh_read_config(inputfile, dryrun);
     604           8 :                 vtysh_unflock_config();
     605           8 :                 exit(ret);
     606             :         }
     607             : 
     608             :         /*
     609             :          * Setup history file for use by both -c and regular input
     610             :          * If we can't find the home directory, then don't store
     611             :          * the history information.
     612             :          * VTYSH_HISTFILE is preferred over command line
     613             :          * argument (-H/--histfile).
     614             :          */
     615           0 :         if (histfile_env) {
     616           0 :                 strlcpy(history_file, histfile_env, sizeof(history_file));
     617           0 :         } else if (histfile) {
     618           0 :                 strlcpy(history_file, histfile, sizeof(history_file));
     619             :         } else {
     620           0 :                 homedir = vtysh_get_home();
     621           0 :                 if (homedir)
     622           0 :                         snprintf(history_file, sizeof(history_file),
     623             :                                  "%s/.history_frr", homedir);
     624             :         }
     625             : 
     626           0 :         if (strlen(history_file) > 0) {
     627           0 :                 if (read_history(history_file) != 0) {
     628           0 :                         int fp;
     629             : 
     630           0 :                         fp = open(history_file, O_CREAT | O_EXCL,
     631             :                                   S_IRUSR | S_IWUSR);
     632           0 :                         if (fp != -1)
     633           0 :                                 close(fp);
     634             : 
     635           0 :                         read_history(history_file);
     636             :                 }
     637             :         }
     638             : 
     639           0 :         if (getenv("VTYSH_LOG")) {
     640           0 :                 const char *logpath = getenv("VTYSH_LOG");
     641             : 
     642           0 :                 logfile = fopen(logpath, "a");
     643           0 :                 if (!logfile) {
     644           0 :                         fprintf(stderr, "Failed to open logfile (%s): %s\n",
     645           0 :                                 logpath, strerror(errno));
     646           0 :                         exit(1);
     647             :                 }
     648             :         }
     649             : 
     650             :         /* If eval mode. */
     651           0 :         if (cmd && cmd->line) {
     652             :                 /* Enter into enable node. */
     653           0 :                 if (!user_mode)
     654           0 :                         vtysh_execute("enable");
     655             : 
     656           0 :                 vtysh_add_timestamp = ts_flag;
     657             : 
     658           0 :                 while (cmd != NULL) {
     659             :                         char *eol;
     660             : 
     661           0 :                         while ((eol = strchr(cmd->line, '\n')) != NULL) {
     662           0 :                                 *eol = '\0';
     663             : 
     664           0 :                                 add_history(cmd->line);
     665           0 :                                 append_history(1, history_file);
     666             : 
     667           0 :                                 if (echo_command)
     668           0 :                                         printf("%s%s\n", vtysh_prompt(),
     669             :                                                cmd->line);
     670             : 
     671           0 :                                 if (logfile)
     672           0 :                                         log_it(cmd->line);
     673             : 
     674           0 :                                 ret = vtysh_execute_no_pager(cmd->line);
     675           0 :                                 if (!no_error
     676           0 :                                     && !(ret == CMD_SUCCESS
     677           0 :                                          || ret == CMD_SUCCESS_DAEMON
     678             :                                          || ret == CMD_WARNING))
     679           0 :                                         exit(1);
     680             : 
     681           0 :                                 cmd->line = eol + 1;
     682             :                         }
     683             : 
     684           0 :                         add_history(cmd->line);
     685           0 :                         append_history(1, history_file);
     686             : 
     687           0 :                         if (echo_command)
     688           0 :                                 printf("%s%s\n", vtysh_prompt(), cmd->line);
     689             : 
     690           0 :                         if (logfile)
     691           0 :                                 log_it(cmd->line);
     692             : 
     693             :                         /*
     694             :                          * Parsing logic for regular commands will be different
     695             :                          * than for those commands requiring further
     696             :                          * processing, such as cli instructions terminating
     697             :                          * with question-mark character.
     698             :                          */
     699           0 :                         if (!vtysh_execute_command_questionmark(cmd->line))
     700             :                                 ret = CMD_SUCCESS;
     701             :                         else
     702           0 :                                 ret = vtysh_execute_no_pager(cmd->line);
     703             : 
     704           0 :                         if (!no_error
     705           0 :                             && !(ret == CMD_SUCCESS || ret == CMD_SUCCESS_DAEMON
     706             :                                  || ret == CMD_WARNING))
     707           0 :                                 exit(1);
     708             : 
     709             :                         {
     710           0 :                                 struct cmd_rec *cr;
     711           0 :                                 cr = cmd;
     712           0 :                                 cmd = cmd->next;
     713           0 :                                 XFREE(MTYPE_TMP, cr);
     714             :                         }
     715             :                 }
     716             : 
     717           0 :                 history_truncate_file(history_file, 1000);
     718           0 :                 exit(0);
     719             :         }
     720             : 
     721             :         /* Boot startup configuration file. */
     722           0 :         if (boot_flag) {
     723           0 :                 vtysh_flock_config(frr_config);
     724           0 :                 ret = vtysh_read_config(frr_config, dryrun);
     725           0 :                 vtysh_unflock_config();
     726           0 :                 if (ret) {
     727           0 :                         fprintf(stderr,
     728             :                                 "Configuration file[%s] processing failure: %d\n",
     729             :                                 frr_config, ret);
     730           0 :                         if (no_error)
     731           0 :                                 exit(0);
     732             :                         else
     733           0 :                                 exit(ret);
     734             :                 } else
     735           0 :                         exit(0);
     736             :         }
     737             : 
     738           0 :         vtysh_readline_init();
     739             : 
     740           0 :         vty_hello(vty);
     741             : 
     742             :         /* Enter into enable node. */
     743           0 :         if (!user_mode)
     744           0 :                 vtysh_execute("enable");
     745             : 
     746           0 :         vtysh_add_timestamp = ts_flag;
     747             : 
     748             :         /* Main command loop. */
     749           0 :         vtysh_rl_run();
     750             : 
     751           0 :         vtysh_uninit();
     752             : 
     753           0 :         history_truncate_file(history_file, 1000);
     754           0 :         printf("\n");
     755             : 
     756             :         /* Rest in peace. */
     757           0 :         exit(0);
     758             : }

Generated by: LCOV version v1.16-topotato