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