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