xref: /openbsd-src/usr.bin/bgplg/bgplgsh.c (revision 2c2259b239ba1a134632b2b39054740575e8f185)
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