]> git.proxmox.com Git - mirror_frr.git/blame - vtysh/vtysh_main.c
pimd: fix mtracebis tool warning
[mirror_frr.git] / vtysh / vtysh_main.c
CommitLineData
718e3744 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 *
896014f4
DL
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
718e3744 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>
e43716f6
DS
27#include <sys/file.h>
28#include <unistd.h>
718e3744 29
9c149084
DL
30/* readline carries some ancient definitions around */
31#pragma GCC diagnostic push
32#pragma GCC diagnostic ignored "-Wstrict-prototypes"
718e3744 33#include <readline/readline.h>
34#include <readline/history.h>
9c149084 35#pragma GCC diagnostic pop
718e3744 36
8860ffdc
DS
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
5e4fa164 47#include <lib/version.h>
718e3744 48#include "getopt.h"
49#include "command.h"
f366ad31 50#include "memory.h"
4201dd11 51#include "linklist.h"
eb05883f 52#include "libfrr.h"
1f9128d6
QY
53#include "ferr.h"
54#include "lib_errors.h"
718e3744 55
56#include "vtysh/vtysh.h"
57#include "vtysh/vtysh_user.h"
b094d260 58
718e3744 59/* VTY shell program name. */
60char *progname;
61
32f3268f
DL
62/* SUID mode */
63static uid_t elevuid, realuid;
64static gid_t elevgid, realgid;
65
9b8a8249
DL
66#define VTYSH_CONFIG_NAME "vtysh.conf"
67#define FRR_CONFIG_NAME "frr.conf"
68
67e29abc 69/* Configuration file name and directory. */
ff44f570
DS
70static char vtysh_config[MAXPATHLEN * 3];
71char frr_config[MAXPATHLEN * 3];
9b8a8249
DL
72char vtydir[MAXPATHLEN];
73static char history_file[MAXPATHLEN];
718e3744 74
718e3744 75/* Flag for indicate executing child command. */
76int execute_flag = 0;
77
86b28610 78/* Flag to indicate if in user/unprivileged mode. */
186f6af2 79int user_mode;
86b28610 80
718e3744 81/* Master of threads. */
82struct thread_master *master;
b094d260 83
57fb9748
SH
84/* Command logging */
85FILE *logfile;
86
149a3fff
DA
87static void vtysh_rl_callback(char *line_read)
88{
89 HIST_ENTRY *last;
90
91 rl_callback_handler_remove();
92
93 if (!line_read) {
94 vtysh_loop_exited = true;
95 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 if (*line_read) {
102 using_history();
103 last = previous_history();
104 if (!last || strcmp(last->line, line_read) != 0) {
105 add_history(line_read);
106 append_history(1, history_file);
107 }
108 }
109
110 vtysh_execute(line_read);
111
112 if (!vtysh_loop_exited)
113 rl_callback_handler_install(vtysh_prompt(), vtysh_rl_callback);
5098d577
DS
114
115 free(line_read);
149a3fff
DA
116}
117
718e3744 118/* SIGTSTP handler. This function care user's ^Z input. */
d62a17ae 119static void sigtstp(int sig)
718e3744 120{
149a3fff
DA
121 rl_callback_handler_remove();
122
d62a17ae 123 /* Execute "end" command. */
124 vtysh_execute("end");
718e3744 125
149a3fff
DA
126 if (!vtysh_loop_exited)
127 rl_callback_handler_install(vtysh_prompt(), vtysh_rl_callback);
128
d62a17ae 129 /* Initialize readline. */
130 rl_initialize();
131 printf("\n");
149a3fff 132 rl_forced_update_display();
718e3744 133}
134
135/* SIGINT handler. This function care user's ^Z input. */
d62a17ae 136static void sigint(int sig)
718e3744 137{
d62a17ae 138 /* Check this process is not child process. */
139 if (!execute_flag) {
140 rl_initialize();
141 printf("\n");
142 rl_forced_update_display();
143 }
718e3744 144}
145
e42f5a37 146/* Signale wrapper for vtysh. We don't use sigevent because
147 * vtysh doesn't use threads. TODO */
d62a17ae 148static void vtysh_signal_set(int signo, void (*func)(int))
718e3744 149{
d62a17ae 150 struct sigaction sig;
151 struct sigaction osig;
718e3744 152
d62a17ae 153 sig.sa_handler = func;
154 sigemptyset(&sig.sa_mask);
155 sig.sa_flags = 0;
718e3744 156#ifdef SA_RESTART
d62a17ae 157 sig.sa_flags |= SA_RESTART;
718e3744 158#endif /* SA_RESTART */
159
d62a17ae 160 sigaction(signo, &sig, &osig);
718e3744 161}
162
163/* Initialization of signal handles. */
d62a17ae 164static void vtysh_signal_init(void)
718e3744 165{
d62a17ae 166 vtysh_signal_set(SIGINT, sigint);
167 vtysh_signal_set(SIGTSTP, sigtstp);
168 vtysh_signal_set(SIGPIPE, SIG_IGN);
718e3744 169}
b094d260 170
718e3744 171/* Help information display. */
d62a17ae 172static void usage(int status)
718e3744 173{
d62a17ae 174 if (status != 0)
175 fprintf(stderr, "Try `%s --help' for more information.\n",
176 progname);
177 else
178 printf("Usage : %s [OPTION...]\n\n"
69d4cc70
DA
179 "Integrated shell for FRR (version " FRR_VERSION
180 "). \n"
181 "Configured with:\n " FRR_CONFIG_ARGS
182 "\n\n"
d62a17ae 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"
8bd33a03 192 "-N --pathspace Insert prefix into config & socket paths\n"
86b28610 193 "-u --user Run as an unprivileged user\n"
d62a17ae 194 "-w, --writeconfig Write integrated config (frr.conf) and exit\n"
69d4cc70 195 "-H, --histfile Override history file\n"
d62a17ae 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 exit(status);
718e3744 204}
205
206/* VTY shell options, we use GNU getopt library. */
87d79a9f 207#define OPTION_VTYSOCK 1000
ce2e9ec3 208#define OPTION_CONFDIR 1001
d62a17ae 209struct 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'},
69d4cc70 218 {"histfile", required_argument, NULL, 'H'},
d62a17ae 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'},
bd29d463 225 {"pathspace", required_argument, NULL, 'N'},
86b28610 226 {"user", no_argument, NULL, 'u'},
744bc17d 227 {"timestamp", no_argument, NULL, 't'},
d62a17ae 228 {0}};
b094d260 229
4c92dd90
DL
230bool vtysh_loop_exited;
231
4c92dd90
DL
232static struct thread *vtysh_rl_read_thread;
233
234static void vtysh_rl_read(struct thread *thread)
235{
236 thread_add_read(master, vtysh_rl_read, NULL, STDIN_FILENO,
237 &vtysh_rl_read_thread);
238 rl_callback_read_char();
239}
240
241/* Read a string, and return a pointer to it. Returns NULL on EOF. */
242static void vtysh_rl_run(void)
243{
244 struct thread thread;
245
246 master = thread_master_create(NULL);
247
248 rl_callback_handler_install(vtysh_prompt(), vtysh_rl_callback);
249 thread_add_read(master, vtysh_rl_read, NULL, STDIN_FILENO,
250 &vtysh_rl_read_thread);
251
252 while (!vtysh_loop_exited && thread_fetch(master, &thread))
253 thread_call(&thread);
254
255 if (!vtysh_loop_exited)
256 rl_callback_handler_remove();
257
258 thread_master_free(master);
718e3744 259}
b094d260 260
57fb9748
SH
261static void log_it(const char *line)
262{
d62a17ae 263 time_t t = time(NULL);
a2700b50 264 struct tm tmp;
d62a17ae 265 const char *user = getenv("USER");
266 char tod[64];
57fb9748 267
a2700b50 268 localtime_r(&t, &tmp);
d62a17ae 269 if (!user)
270 user = "boot";
f03db93b 271
0d6f7fd6 272 strftime(tod, sizeof(tod), "%Y%m%d-%H:%M.%S", &tmp);
d62a17ae 273
274 fprintf(logfile, "%s:%s %s\n", tod, user, line);
57fb9748
SH
275}
276
e43716f6
DS
277static int flock_fd;
278
d62a17ae 279static void vtysh_flock_config(const char *flock_file)
e43716f6 280{
d62a17ae 281 int count = 0;
282
283 flock_fd = open(flock_file, O_RDONLY, 0644);
284 if (flock_fd < 0) {
285 fprintf(stderr, "Unable to create lock file: %s, %s\n",
286 flock_file, safe_strerror(errno));
287 return;
288 }
289
290 while (count < 400 && (flock(flock_fd, LOCK_EX | LOCK_NB) < 0)) {
291 count++;
292 usleep(500000);
293 }
294
295 if (count >= 400)
296 fprintf(stderr,
297 "Flock of %s failed, continuing this may cause issues\n",
298 flock_file);
e43716f6
DS
299}
300
d62a17ae 301static void vtysh_unflock_config(void)
e43716f6 302{
d62a17ae 303 flock(flock_fd, LOCK_UN);
304 close(flock_fd);
e43716f6
DS
305}
306
32f3268f
DL
307void suid_on(void)
308{
309 if (elevuid != realuid && seteuid(elevuid)) {
310 perror("seteuid(on)");
311 exit(1);
312 }
313 if (elevgid != realgid && setegid(elevgid)) {
314 perror("setegid(on)");
315 exit(1);
316 }
317}
318
319void suid_off(void)
320{
321 if (elevuid != realuid && seteuid(realuid)) {
322 perror("seteuid(off)");
323 exit(1);
324 }
325 if (elevgid != realgid && setegid(realgid)) {
326 perror("setegid(off)");
327 exit(1);
328 }
329}
330
718e3744 331/* VTY shell main routine. */
d62a17ae 332int main(int argc, char **argv, char **env)
718e3744 333{
d62a17ae 334 char *p;
335 int opt;
336 int dryrun = 0;
337 int boot_flag = 0;
744bc17d 338 bool ts_flag = false;
d62a17ae 339 const char *daemon_name = NULL;
340 const char *inputfile = NULL;
d62a17ae 341 struct cmd_rec {
342 char *line;
343 struct cmd_rec *next;
344 } *cmd = NULL;
345 struct cmd_rec *tail = NULL;
346 int echo_command = 0;
347 int no_error = 0;
348 int markfile = 0;
349 int writeconfig = 0;
350 int ret = 0;
351 char *homedir = NULL;
32f3268f 352 int ditch_suid = 0;
9b8a8249 353 char sysconfdir[MAXPATHLEN];
1dede1f8 354 const char *pathspace_arg = NULL;
8bd33a03 355 char pathspace[MAXPATHLEN] = "";
69d4cc70 356 const char *histfile = NULL;
99a9f25c 357 const char *histfile_env = getenv("VTYSH_HISTFILE");
d62a17ae 358
32f3268f
DL
359 /* SUID: drop down to calling user & go back up when needed */
360 elevuid = geteuid();
361 elevgid = getegid();
362 realuid = getuid();
363 realgid = getgid();
364 suid_off();
d62a17ae 365
186f6af2
LB
366 user_mode = 0; /* may be set in options processing */
367
d62a17ae 368 /* Preserve name of myself. */
369 progname = ((p = strrchr(argv[0], '/')) ? ++p : argv[0]);
370
9b8a8249 371 strlcpy(sysconfdir, frr_sysconfdir, sizeof(sysconfdir));
43e587c1
DS
372
373 frr_init_vtydir();
9b8a8249
DL
374 strlcpy(vtydir, frr_vtydir, sizeof(vtydir));
375
d62a17ae 376 /* Option handling. */
377 while (1) {
744bc17d 378 opt = getopt_long(argc, argv, "be:c:d:nf:H:mEhCwN:ut", longopts,
69d4cc70 379 0);
d62a17ae 380
381 if (opt == EOF)
382 break;
383
384 switch (opt) {
385 case 0:
386 break;
387 case 'b':
388 boot_flag = 1;
389 break;
390 case 'e':
391 case 'c': {
392 struct cmd_rec *cr;
393 cr = XMALLOC(MTYPE_TMP, sizeof(*cr));
394 cr->line = optarg;
395 cr->next = NULL;
396 if (tail)
397 tail->next = cr;
398 else
399 cmd = cr;
400 tail = cr;
401 } break;
402 case OPTION_VTYSOCK:
32f3268f 403 ditch_suid = 1; /* option disables SUID */
9b8a8249 404 strlcpy(vtydir, optarg, sizeof(vtydir));
d62a17ae 405 break;
406 case OPTION_CONFDIR:
32f3268f 407 ditch_suid = 1; /* option disables SUID */
45d00587 408 snprintf(sysconfdir, sizeof(sysconfdir), "%s/", optarg);
d62a17ae 409 break;
8bd33a03
DL
410 case 'N':
411 if (strchr(optarg, '/') || strchr(optarg, '.')) {
412 fprintf(stderr,
413 "slashes or dots are not permitted in the --pathspace option.\n");
414 exit(1);
415 }
1dede1f8
CF
416 pathspace_arg = optarg;
417 snprintf(pathspace, sizeof(pathspace), "%s/", optarg);
8bd33a03 418 break;
d62a17ae 419 case 'd':
420 daemon_name = optarg;
421 break;
422 case 'f':
423 inputfile = optarg;
424 break;
425 case 'm':
426 markfile = 1;
427 break;
428 case 'n':
429 no_error = 1;
430 break;
431 case 'E':
432 echo_command = 1;
433 break;
434 case 'C':
435 dryrun = 1;
436 break;
86b28610
LB
437 case 'u':
438 user_mode = 1;
439 break;
744bc17d
CH
440 case 't':
441 ts_flag = true;
442 break;
d62a17ae 443 case 'w':
444 writeconfig = 1;
445 break;
446 case 'h':
447 usage(0);
448 break;
69d4cc70
DA
449 case 'H':
450 histfile = optarg;
451 break;
d62a17ae 452 default:
453 usage(1);
454 break;
455 }
456 }
457
32f3268f
DL
458 if (ditch_suid) {
459 elevuid = realuid;
460 elevgid = realgid;
461 }
462
d62a17ae 463 if (markfile + writeconfig + dryrun + boot_flag > 1) {
464 fprintf(stderr,
3efd0893 465 "Invalid combination of arguments. Please specify at most one of:\n\t-b, -C, -m, -w\n");
d62a17ae 466 return 1;
467 }
468 if (inputfile && (writeconfig || boot_flag)) {
469 fprintf(stderr,
3efd0893 470 "WARNING: Combinining the -f option with -b or -w is NOT SUPPORTED since its\nresults are inconsistent!\n");
d62a17ae 471 }
472
e82314b1 473 snprintf(vtysh_config, sizeof(vtysh_config), "%s%s%s", sysconfdir,
60466a63 474 pathspace, VTYSH_CONFIG_NAME);
e82314b1 475 snprintf(frr_config, sizeof(frr_config), "%s%s%s", sysconfdir,
60466a63 476 pathspace, FRR_CONFIG_NAME);
1dede1f8
CF
477
478 if (pathspace_arg) {
479 strlcat(vtydir, "/", sizeof(vtydir));
480 strlcat(vtydir, pathspace_arg, sizeof(vtydir));
481 }
9b8a8249 482
d62a17ae 483 /* Initialize user input buffer. */
d62a17ae 484 setlinebuf(stdout);
485
486 /* Signal and others. */
487 vtysh_signal_init();
488
489 /* Make vty structure and register commands. */
490 vtysh_init_vty();
491 vtysh_init_cmd();
492 vtysh_user_init();
493 vtysh_config_init();
494
495 vty_init_vtysh();
496
86b28610
LB
497 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 suid_on();
77f7b4b0 501 vtysh_read_config(vtysh_config, dryrun);
86b28610
LB
502 suid_off();
503 }
1f9128d6
QY
504 /* Error code library system */
505 log_ref_init();
506 lib_error_init();
d62a17ae 507
508 if (markfile) {
509 if (!inputfile) {
510 fprintf(stderr,
511 "-f option MUST be specified with -m option\n");
95f7965d 512 return 1;
d62a17ae 513 }
514 return (vtysh_mark_file(inputfile));
515 }
516
517 /* Start execution only if not in dry-run mode */
518 if (dryrun && !cmd) {
519 if (inputfile) {
77f7b4b0 520 ret = vtysh_read_config(inputfile, dryrun);
d62a17ae 521 } else {
77f7b4b0 522 ret = vtysh_read_config(frr_config, dryrun);
d62a17ae 523 }
524
525 exit(ret);
718e3744 526 }
d62a17ae 527
47402c0f 528 if (dryrun && cmd && cmd->line) {
f205fcdb
LB
529 if (!user_mode)
530 vtysh_execute("enable");
d62a17ae 531 while (cmd) {
532 struct cmd_rec *cr;
533 char *cmdnow = cmd->line, *next;
534 do {
535 next = strchr(cmdnow, '\n');
536 if (next)
537 *next++ = '\0';
538
539 if (echo_command)
540 printf("%s%s\n", vtysh_prompt(),
541 cmdnow);
542
543 ret = vtysh_execute_no_pager(cmdnow);
544 if (!no_error
545 && !(ret == CMD_SUCCESS
546 || ret == CMD_SUCCESS_DAEMON
547 || ret == CMD_WARNING))
548 exit(1);
549 } while ((cmdnow = next) != NULL);
550
551 cr = cmd;
552 cmd = cmd->next;
553 XFREE(MTYPE_TMP, cr);
554 }
555 exit(ret);
0846286b 556 }
d62a17ae 557
558 /* Ignore error messages */
559 if (no_error) {
560 if (freopen("/dev/null", "w", stdout) == NULL) {
561 fprintf(stderr,
562 "Exiting: Failed to duplicate stdout with -n option");
563 exit(1);
564 }
0846286b 565 }
d62a17ae 566
32f3268f
DL
567 /* SUID: go back up elevated privs */
568 suid_on();
569
d62a17ae 570 /* Make sure we pass authentication before proceeding. */
571 vtysh_auth();
572
573 /* Do not connect until we have passed authentication. */
574 if (vtysh_connect_all(daemon_name) <= 0) {
575 fprintf(stderr, "Exiting: failed to connect to any daemons.\n");
14275475
QY
576 if (geteuid() != 0)
577 fprintf(stderr,
578 "Hint: if this seems wrong, try running me as a privileged user!\n");
d62a17ae 579 if (no_error)
580 exit(0);
581 else
582 exit(1);
3221dca8 583 }
cd272640 584
32f3268f
DL
585 /* SUID: back down, don't need privs further on */
586 suid_off();
587
d62a17ae 588 if (writeconfig) {
f205fcdb
LB
589 if (user_mode) {
590 fprintf(stderr,
591 "writeconfig cannot be used when running as an unprivileged user.\n");
592 if (no_error)
593 exit(0);
594 else
595 exit(1);
596 }
d62a17ae 597 vtysh_execute("enable");
598 return vtysh_write_config_integrated();
7a49a5b5 599 }
d62a17ae 600
601 if (inputfile) {
602 vtysh_flock_config(inputfile);
77f7b4b0 603 ret = vtysh_read_config(inputfile, dryrun);
d62a17ae 604 vtysh_unflock_config();
605 exit(ret);
fba55c8a 606 }
d62a17ae 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
69d4cc70 611 * the history information.
11743d10 612 * VTYSH_HISTFILE is preferred over command line
69d4cc70 613 * argument (-H/--histfile).
d62a17ae 614 */
99a9f25c
DS
615 if (histfile_env) {
616 strlcpy(history_file, histfile_env, sizeof(history_file));
69d4cc70
DA
617 } else if (histfile) {
618 strlcpy(history_file, histfile, sizeof(history_file));
619 } else {
620 homedir = vtysh_get_home();
621 if (homedir)
622 snprintf(history_file, sizeof(history_file),
623 "%s/.history_frr", homedir);
624 }
625
626 if (strlen(history_file) > 0) {
d62a17ae 627 if (read_history(history_file) != 0) {
628 int fp;
629
630 fp = open(history_file, O_CREAT | O_EXCL,
631 S_IRUSR | S_IWUSR);
cbb65f5e 632 if (fp != -1)
d62a17ae 633 close(fp);
634
635 read_history(history_file);
636 }
637 }
638
32f3268f
DL
639 if (getenv("VTYSH_LOG")) {
640 const char *logpath = getenv("VTYSH_LOG");
641
642 logfile = fopen(logpath, "a");
643 if (!logfile) {
644 fprintf(stderr, "Failed to open logfile (%s): %s\n",
645 logpath, strerror(errno));
646 exit(1);
647 }
648 }
649
d62a17ae 650 /* If eval mode. */
47402c0f 651 if (cmd && cmd->line) {
d62a17ae 652 /* Enter into enable node. */
f205fcdb
LB
653 if (!user_mode)
654 vtysh_execute("enable");
d62a17ae 655
744bc17d
CH
656 vtysh_add_timestamp = ts_flag;
657
d62a17ae 658 while (cmd != NULL) {
d62a17ae 659 char *eol;
660
661 while ((eol = strchr(cmd->line, '\n')) != NULL) {
662 *eol = '\0';
663
664 add_history(cmd->line);
665 append_history(1, history_file);
666
667 if (echo_command)
668 printf("%s%s\n", vtysh_prompt(),
669 cmd->line);
670
671 if (logfile)
672 log_it(cmd->line);
673
674 ret = vtysh_execute_no_pager(cmd->line);
675 if (!no_error
676 && !(ret == CMD_SUCCESS
677 || ret == CMD_SUCCESS_DAEMON
678 || ret == CMD_WARNING))
679 exit(1);
680
681 cmd->line = eol + 1;
682 }
683
684 add_history(cmd->line);
685 append_history(1, history_file);
686
687 if (echo_command)
688 printf("%s%s\n", vtysh_prompt(), cmd->line);
689
690 if (logfile)
691 log_it(cmd->line);
692
a4364a44 693 /*
76015847
QY
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.
a4364a44
RM
698 */
699 if (!vtysh_execute_command_questionmark(cmd->line))
700 ret = CMD_SUCCESS;
701 else
702 ret = vtysh_execute_no_pager(cmd->line);
703
d62a17ae 704 if (!no_error
705 && !(ret == CMD_SUCCESS || ret == CMD_SUCCESS_DAEMON
706 || ret == CMD_WARNING))
707 exit(1);
708
709 {
710 struct cmd_rec *cr;
711 cr = cmd;
712 cmd = cmd->next;
713 XFREE(MTYPE_TMP, cr);
714 }
715 }
716
717 history_truncate_file(history_file, 1000);
718 exit(0);
719 }
720
721 /* Boot startup configuration file. */
722 if (boot_flag) {
9b8a8249 723 vtysh_flock_config(frr_config);
77f7b4b0 724 ret = vtysh_read_config(frr_config, dryrun);
d62a17ae 725 vtysh_unflock_config();
726 if (ret) {
727 fprintf(stderr,
728 "Configuration file[%s] processing failure: %d\n",
9b8a8249 729 frr_config, ret);
d62a17ae 730 if (no_error)
731 exit(0);
732 else
733 exit(ret);
734 } else
735 exit(0);
e7168df4 736 }
718e3744 737
d62a17ae 738 vtysh_readline_init();
718e3744 739
d62a17ae 740 vty_hello(vty);
718e3744 741
d62a17ae 742 /* Enter into enable node. */
f205fcdb
LB
743 if (!user_mode)
744 vtysh_execute("enable");
e7168df4 745
744bc17d
CH
746 vtysh_add_timestamp = ts_flag;
747
d62a17ae 748 /* Main command loop. */
4c92dd90 749 vtysh_rl_run();
718e3744 750
193a5a95
QY
751 vtysh_uninit();
752
d62a17ae 753 history_truncate_file(history_file, 1000);
754 printf("\n");
718e3744 755
d62a17ae 756 /* Rest in peace. */
757 exit(0);
718e3744 758}