xref: /openbsd/usr.bin/bgplg/bgplgsh.c (revision 891d7ab6)
1 /*	$OpenBSD: bgplgsh.c,v 1.3 2010/04/02 21:20:49 sthen Exp $	*/
2 
3 /*
4  * Copyright (c) 2005, 2006 Reyk Floeter <reyk@vantronix.net>
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/stat.h>
20 #include <sys/types.h>
21 #include <sys/param.h>
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <signal.h>
26 #include <string.h>
27 #include <unistd.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/logs/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(_x) || isprint(_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 
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(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 	if (argv != NULL)
155 		free(argv);
156 
157 	return (new_argv);
158 }
159 
160 int
161 lg_checkcmd(int argc, char **argv, int *off, struct cmd *cmd)
162 {
163 	char **cmdp = NULL, *cmdstr = NULL;
164 	int i, ncmd, v, ret = -1;
165 
166 	if ((cmdstr = strdup(cmd->name)) == NULL)
167 		goto done;
168 	if ((cmdp = lg_arg2argv(cmdstr, &ncmd)) == NULL)
169 		goto done;
170 	if (ncmd > argc || argc > (ncmd + cmd->maxargs))
171 		goto done;
172 
173 	for (i = 0; i < ncmd; i++)
174 		if (strcmp(argv[i], cmdp[i]) != 0)
175 			goto done;
176 
177 	if ((v = argc - ncmd) < 0 ||
178 	    (*off != -1 && *off < v))
179 		goto done;
180 	if (cmd->minargs && v < cmd->minargs) {
181 		ret = EINVAL;
182 		goto done;
183 	}
184 	*off = v;
185 	ret = 0;
186 
187  done:
188 	if (cmdp != NULL)
189 		free(cmdp);
190 	if (cmdstr != NULL)
191 		free(cmdstr);
192 	return (ret);
193 }
194 
195 char *
196 lg_completion(const char *str, int state)
197 {
198 	static int lg_complidx, len;
199 	const char *name;
200 
201 	if (state == 0) {
202 		len = strlen(str);
203 		lg_complidx = 0;
204 	}
205 	while ((name = cmds[lg_complidx].name) != NULL) {
206 		lg_complidx++;
207 		if (strncmp(name, str, len) == 0)
208 			return (strdup(name));
209 	}
210 
211 	return (NULL);
212 }
213 
214 int
215 main(void)
216 {
217 	struct cmd *cmd = NULL;
218 	char prompt[MAXHOSTNAMELEN], *line, **argp = NULL;
219 	int ncmd, ret, v = -1;
220 	u_int i;
221 
222 	rl_readline_name = NAME;
223 	rl_completion_entry_function = lg_completion;
224 
225 	/* Ignore the whitespace character */
226 	rl_basic_word_break_characters = "\t\n\"\\'`@$><=;|&{(";
227 
228 	while (!quit) {
229 		v = -1;
230 		gethostname(prompt, sizeof(prompt) - 2);
231 		strlcat(prompt, "> ", sizeof(prompt));
232 
233 		if ((line = readline(prompt)) == NULL) {
234 			printf("\n");
235 			lg_help(cmds, NULL);
236 			continue;
237 		}
238 		if (!lg_strip(line))
239 			goto next;
240 		if (strcmp(line, "exit") == 0) {
241 			quit = 1;
242 			goto next;
243 		}
244 
245 		add_history(line);
246 
247 		if ((argp = lg_arg2argv(line, &ncmd)) == NULL)
248 			goto next;
249 
250 		for (i = 0; cmds[i].name != NULL; i++) {
251 			ret = lg_checkcmd(ncmd, argp, &v, &cmds[i]);
252 			if (ret == 0)
253 				cmd = &cmds[i];
254 			else if (ret == EINVAL) {
255 				printf("invalid number of arguments\n");
256 				goto next;
257 			}
258 		}
259 
260 		if (cmd == NULL) {
261 			printf("invalid command\n");
262 		} else if (cmd->func != NULL) {
263 			cmd->func(cmds, argp);
264 		} else {
265 			if ((argp = lg_argextra(argp, ncmd, v, cmd)) == NULL)
266 				goto next;
267 			lg_exec(cmd->earg[0], argp);
268 		}
269 
270  next:
271 		if (argp != NULL) {
272 			free(argp);
273 			argp = NULL;
274 		}
275 		if (line != NULL) {
276 			free(line);
277 			line = NULL;
278 		}
279 		cmd = NULL;
280 	}
281 
282 	return (0);
283 }
284