1*2c2259b2Smmcc /* $OpenBSD: bgplgsh.c,v 1.8 2015/12/09 17:52:24 mmcc Exp $ */
2bc5366b8Sreyk
3bc5366b8Sreyk /*
49cf8e0eaSreyk * Copyright (c) 2005, 2006 Reyk Floeter <reyk@openbsd.org>
5bc5366b8Sreyk *
6bc5366b8Sreyk * Permission to use, copy, modify, and distribute this software for any
7bc5366b8Sreyk * purpose with or without fee is hereby granted, provided that the above
8bc5366b8Sreyk * copyright notice and this permission notice appear in all copies.
9bc5366b8Sreyk *
10bc5366b8Sreyk * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11bc5366b8Sreyk * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12bc5366b8Sreyk * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13bc5366b8Sreyk * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14bc5366b8Sreyk * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15bc5366b8Sreyk * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16bc5366b8Sreyk * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17bc5366b8Sreyk */
18bc5366b8Sreyk
19bc5366b8Sreyk #include <sys/types.h>
20b9fc9a72Sderaadt #include <sys/stat.h>
21bc5366b8Sreyk
22bc5366b8Sreyk #include <stdio.h>
23bc5366b8Sreyk #include <stdlib.h>
24bc5366b8Sreyk #include <signal.h>
25bc5366b8Sreyk #include <string.h>
26bc5366b8Sreyk #include <unistd.h>
27b9fc9a72Sderaadt #include <limits.h>
28bc5366b8Sreyk #include <ctype.h>
29bc5366b8Sreyk #include <errno.h>
30bc5366b8Sreyk #include <fcntl.h>
31bc5366b8Sreyk
32bc5366b8Sreyk #include <readline/readline.h>
33bc5366b8Sreyk #include <readline/history.h>
34bc5366b8Sreyk
35bc5366b8Sreyk #include "bgplg.h"
36bc5366b8Sreyk
3774abb244Sflorian #define BGPDSOCK "/var/www/run/bgpd.rsock"
38bc5366b8Sreyk #define BGPCTL "/usr/sbin/bgpctl", "-s", BGPDSOCK
39bc5366b8Sreyk #define PING "/sbin/ping"
40bc5366b8Sreyk #define TRACEROUTE "/usr/sbin/traceroute"
41cc8d9beeSsthen #define PING6 "/sbin/ping6"
42cc8d9beeSsthen #define TRACEROUTE6 "/usr/sbin/traceroute6"
43bc5366b8Sreyk
44bc5366b8Sreyk static volatile int quit;
45bc5366b8Sreyk
46bc5366b8Sreyk static struct cmd cmds[] = CMDS;
47bc5366b8Sreyk
48bc5366b8Sreyk char **lg_arg2argv(char *, int *);
49bc5366b8Sreyk char **lg_argextra(char **, int, int, struct cmd *);
50bc5366b8Sreyk int lg_checkarg(char *);
51bc5366b8Sreyk int lg_checkcmd(int, char **, int *, struct cmd *);
52bc5366b8Sreyk char *lg_completion(const char *, int);
53bc5366b8Sreyk
54bc5366b8Sreyk int
lg_checkarg(char * arg)55bc5366b8Sreyk lg_checkarg(char *arg)
56bc5366b8Sreyk {
57bc5366b8Sreyk size_t len;
58bc5366b8Sreyk u_int i;
59bc5366b8Sreyk
60bc5366b8Sreyk if (!(len = strlen(arg)))
61bc5366b8Sreyk return (0);
62bc5366b8Sreyk
63bc5366b8Sreyk #define allowed_in_string(_x) \
646d73225dSderaadt ((isalnum((unsigned char)_x) || isprint((unsigned char)_x)) && \
65bc5366b8Sreyk (_x != '%' && _x != '\\' && _x != ';' && _x != '&' && _x != '|'))
66bc5366b8Sreyk
67bc5366b8Sreyk for (i = 0; i < len; i++) {
68bc5366b8Sreyk if (!allowed_in_string(arg[i])) {
69bc5366b8Sreyk fprintf(stderr, "invalid character in input\n");
70bc5366b8Sreyk return (EPERM);
71bc5366b8Sreyk }
72bc5366b8Sreyk }
736d73225dSderaadt #undef allowed_in_string
74bc5366b8Sreyk return (0);
75bc5366b8Sreyk }
76bc5366b8Sreyk
77bc5366b8Sreyk char **
lg_arg2argv(char * arg,int * argc)78bc5366b8Sreyk lg_arg2argv(char *arg, int *argc)
79bc5366b8Sreyk {
80bc5366b8Sreyk char **argv, *ptr = arg;
81bc5366b8Sreyk size_t len;
82bc5366b8Sreyk u_int i, c = 1;
83bc5366b8Sreyk
84bc5366b8Sreyk if (lg_checkarg(arg) != 0)
85bc5366b8Sreyk return (NULL);
86bc5366b8Sreyk if (!(len = strlen(arg)))
87bc5366b8Sreyk return (NULL);
88bc5366b8Sreyk
89bc5366b8Sreyk /* Count elements */
90bc5366b8Sreyk for (i = 0; i < len; i++) {
916d73225dSderaadt if (isspace((unsigned char)arg[i])) {
92bc5366b8Sreyk /* filter out additional options */
93bc5366b8Sreyk if (arg[i + 1] == '-') {
94bc5366b8Sreyk printf("invalid input\n");
95bc5366b8Sreyk return (NULL);
96bc5366b8Sreyk }
97bc5366b8Sreyk arg[i] = '\0';
98bc5366b8Sreyk c++;
99bc5366b8Sreyk }
100bc5366b8Sreyk }
101bc5366b8Sreyk if (arg[0] == '\0')
102bc5366b8Sreyk return (NULL);
103bc5366b8Sreyk
104bc5366b8Sreyk /* Generate array */
105bc5366b8Sreyk if ((argv = calloc(c + 1, sizeof(char *))) == NULL) {
106bc5366b8Sreyk printf("fatal error: %s\n", strerror(errno));
107bc5366b8Sreyk return (NULL);
108bc5366b8Sreyk }
109bc5366b8Sreyk
110bc5366b8Sreyk argv[c] = NULL;
111bc5366b8Sreyk *argc = c;
112bc5366b8Sreyk
113bc5366b8Sreyk /* Fill array */
114bc5366b8Sreyk for (i = c = 0; i < len; i++) {
115bc5366b8Sreyk if (arg[i] == '\0' || i == 0) {
116bc5366b8Sreyk if (i != 0)
117bc5366b8Sreyk ptr = &arg[i + 1];
118bc5366b8Sreyk argv[c++] = ptr;
119bc5366b8Sreyk }
120bc5366b8Sreyk }
121bc5366b8Sreyk
122bc5366b8Sreyk return (argv);
123bc5366b8Sreyk }
124bc5366b8Sreyk
125bc5366b8Sreyk char **
lg_argextra(char ** argv,int argc,int off,struct cmd * cmdp)126bc5366b8Sreyk lg_argextra(char **argv, int argc, int off, struct cmd *cmdp)
127bc5366b8Sreyk {
128bc5366b8Sreyk char **new_argv;
129bc5366b8Sreyk int i, c = 0, n;
130bc5366b8Sreyk
131bc5366b8Sreyk if ((n = argc - off) < 0)
132bc5366b8Sreyk return (NULL);
133bc5366b8Sreyk
134bc5366b8Sreyk /* Count elements */
135bc5366b8Sreyk for (i = 0; cmdp->earg[i] != NULL; i++)
136bc5366b8Sreyk c++;
137bc5366b8Sreyk
138bc5366b8Sreyk /* Generate array */
139bc5366b8Sreyk if ((new_argv = calloc(c + n + 1, sizeof(char *))) == NULL) {
140bc5366b8Sreyk printf("fatal error: %s\n", strerror(errno));
141bc5366b8Sreyk return (NULL);
142bc5366b8Sreyk }
143bc5366b8Sreyk
144bc5366b8Sreyk /* Fill array */
145bc5366b8Sreyk for (i = c = 0; cmdp->earg[i] != NULL; i++)
146bc5366b8Sreyk new_argv[c++] = cmdp->earg[i];
147bc5366b8Sreyk
148bc5366b8Sreyk /* Append old array */
149bc5366b8Sreyk for (i = n; i < argc; i++)
150bc5366b8Sreyk new_argv[c++] = argv[i];
151bc5366b8Sreyk
152bc5366b8Sreyk new_argv[c] = NULL;
153bc5366b8Sreyk
154bc5366b8Sreyk free(argv);
155bc5366b8Sreyk
156bc5366b8Sreyk return (new_argv);
157bc5366b8Sreyk }
158bc5366b8Sreyk
159bc5366b8Sreyk int
lg_checkcmd(int argc,char ** argv,int * off,struct cmd * cmd)160bc5366b8Sreyk lg_checkcmd(int argc, char **argv, int *off, struct cmd *cmd)
161bc5366b8Sreyk {
162bc5366b8Sreyk char **cmdp = NULL, *cmdstr = NULL;
163bc5366b8Sreyk int i, ncmd, v, ret = -1;
164bc5366b8Sreyk
165bc5366b8Sreyk if ((cmdstr = strdup(cmd->name)) == NULL)
166bc5366b8Sreyk goto done;
167bc5366b8Sreyk if ((cmdp = lg_arg2argv(cmdstr, &ncmd)) == NULL)
168bc5366b8Sreyk goto done;
169bc5366b8Sreyk if (ncmd > argc || argc > (ncmd + cmd->maxargs))
170bc5366b8Sreyk goto done;
171bc5366b8Sreyk
172bc5366b8Sreyk for (i = 0; i < ncmd; i++)
173bc5366b8Sreyk if (strcmp(argv[i], cmdp[i]) != 0)
174bc5366b8Sreyk goto done;
175bc5366b8Sreyk
176bc5366b8Sreyk if ((v = argc - ncmd) < 0 ||
177bc5366b8Sreyk (*off != -1 && *off < v))
178bc5366b8Sreyk goto done;
179bc5366b8Sreyk if (cmd->minargs && v < cmd->minargs) {
180bc5366b8Sreyk ret = EINVAL;
181bc5366b8Sreyk goto done;
182bc5366b8Sreyk }
183bc5366b8Sreyk *off = v;
184bc5366b8Sreyk ret = 0;
185bc5366b8Sreyk
186bc5366b8Sreyk done:
187bc5366b8Sreyk free(cmdp);
188bc5366b8Sreyk free(cmdstr);
189bc5366b8Sreyk return (ret);
190bc5366b8Sreyk }
191bc5366b8Sreyk
192bc5366b8Sreyk char *
lg_completion(const char * str,int state)193bc5366b8Sreyk lg_completion(const char *str, int state)
194bc5366b8Sreyk {
195bc5366b8Sreyk static int lg_complidx, len;
196bc5366b8Sreyk const char *name;
197bc5366b8Sreyk
198bc5366b8Sreyk if (state == 0) {
199bc5366b8Sreyk len = strlen(str);
200bc5366b8Sreyk lg_complidx = 0;
201bc5366b8Sreyk }
202bc5366b8Sreyk while ((name = cmds[lg_complidx].name) != NULL) {
203bc5366b8Sreyk lg_complidx++;
204bc5366b8Sreyk if (strncmp(name, str, len) == 0)
205bc5366b8Sreyk return (strdup(name));
206bc5366b8Sreyk }
207bc5366b8Sreyk
208bc5366b8Sreyk return (NULL);
209bc5366b8Sreyk }
210bc5366b8Sreyk
211bc5366b8Sreyk int
main(void)212bc5366b8Sreyk main(void)
213bc5366b8Sreyk {
214bc5366b8Sreyk struct cmd *cmd = NULL;
215b9fc9a72Sderaadt char prompt[HOST_NAME_MAX+1], *line, **argp = NULL;
216bc5366b8Sreyk int ncmd, ret, v = -1;
217bc5366b8Sreyk u_int i;
218bc5366b8Sreyk
219bc5366b8Sreyk rl_readline_name = NAME;
220bc5366b8Sreyk rl_completion_entry_function = lg_completion;
221bc5366b8Sreyk
222bc5366b8Sreyk /* Ignore the whitespace character */
223bc5366b8Sreyk rl_basic_word_break_characters = "\t\n\"\\'`@$><=;|&{(";
224bc5366b8Sreyk
225bc5366b8Sreyk while (!quit) {
226bc5366b8Sreyk v = -1;
227bc5366b8Sreyk gethostname(prompt, sizeof(prompt) - 2);
228bc5366b8Sreyk strlcat(prompt, "> ", sizeof(prompt));
229bc5366b8Sreyk
230bc5366b8Sreyk if ((line = readline(prompt)) == NULL) {
231bc5366b8Sreyk printf("\n");
232bc5366b8Sreyk lg_help(cmds, NULL);
233bc5366b8Sreyk continue;
234bc5366b8Sreyk }
235bc5366b8Sreyk if (!lg_strip(line))
236bc5366b8Sreyk goto next;
237bc5366b8Sreyk if (strcmp(line, "exit") == 0) {
238bc5366b8Sreyk quit = 1;
239bc5366b8Sreyk goto next;
240bc5366b8Sreyk }
241bc5366b8Sreyk
242bc5366b8Sreyk add_history(line);
243bc5366b8Sreyk
244bc5366b8Sreyk if ((argp = lg_arg2argv(line, &ncmd)) == NULL)
245bc5366b8Sreyk goto next;
246bc5366b8Sreyk
247bc5366b8Sreyk for (i = 0; cmds[i].name != NULL; i++) {
248bc5366b8Sreyk ret = lg_checkcmd(ncmd, argp, &v, &cmds[i]);
249bc5366b8Sreyk if (ret == 0)
250bc5366b8Sreyk cmd = &cmds[i];
251bc5366b8Sreyk else if (ret == EINVAL) {
252bc5366b8Sreyk printf("invalid number of arguments\n");
253bc5366b8Sreyk goto next;
254bc5366b8Sreyk }
255bc5366b8Sreyk }
256bc5366b8Sreyk
257bc5366b8Sreyk if (cmd == NULL) {
258bc5366b8Sreyk printf("invalid command\n");
259bc5366b8Sreyk } else if (cmd->func != NULL) {
260bc5366b8Sreyk cmd->func(cmds, argp);
261bc5366b8Sreyk } else {
262bc5366b8Sreyk if ((argp = lg_argextra(argp, ncmd, v, cmd)) == NULL)
263bc5366b8Sreyk goto next;
264bc5366b8Sreyk lg_exec(cmd->earg[0], argp);
265bc5366b8Sreyk }
266bc5366b8Sreyk
267bc5366b8Sreyk next:
268bc5366b8Sreyk free(argp);
269bc5366b8Sreyk argp = NULL;
270bc5366b8Sreyk free(line);
271bc5366b8Sreyk line = NULL;
272bc5366b8Sreyk cmd = NULL;
273bc5366b8Sreyk }
274bc5366b8Sreyk
275bc5366b8Sreyk return (0);
276bc5366b8Sreyk }
277