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