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
lg_checkarg(char * arg)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 **
lg_arg2argv(char * arg,int * argc)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 **
lg_argextra(char ** argv,int argc,int off,struct cmd * cmdp)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
lg_checkcmd(int argc,char ** argv,int * off,struct cmd * cmd)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 *
lg_completion(const char * str,int state)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
main(void)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