1/* 2 * Test code for lib/command.c 3 * 4 * Copyright (C) 2013 by Open Source Routing. 5 * Copyright (C) 2013 by Internet Systems Consortium, Inc. ("ISC") 6 * 7 * This program reads in a list of commandlines from stdin 8 * and calls all the public functions of lib/command.c for 9 * both the given command lines and fuzzed versions thereof. 10 * 11 * The output is currently not validated but only logged. It can 12 * be diffed to find regressions between versions. 13 * 14 * Quagga is free software; you can redistribute it and/or modify it 15 * under the terms of the GNU General Public License as published by the 16 * Free Software Foundation; either version 2, or (at your option) any 17 * later version. 18 * 19 * Quagga is distributed in the hope that it will be useful, but 20 * WITHOUT ANY WARRANTY; without even the implied warranty of 21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 22 * General Public License for more details. 23 * 24 * You should have received a copy of the GNU General Public License 25 * along with Quagga; see the file COPYING. If not, write to the Free 26 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 27 * 02111-1307, USA. 28 */ 29 30#define REALLY_NEED_PLAIN_GETOPT 1 31 32#include <zebra.h> 33 34#include <stdio.h> 35#include <stdlib.h> 36#include <unistd.h> 37 38#include "command.h" 39#include "memory.h" 40#include "vector.h" 41#include "prng.h" 42 43extern vector cmdvec; 44extern struct cmd_node vty_node; 45extern void test_init_cmd(void); /* provided in test-commands-defun.c */ 46 47struct thread_master *master; /* dummy for libzebra*/ 48 49static vector test_cmds; 50static char test_buf[32768]; 51 52static struct cmd_node bgp_node = 53{ 54 BGP_NODE, 55 "%s(config-router)# ", 56}; 57 58static struct cmd_node rip_node = 59{ 60 RIP_NODE, 61 "%s(config-router)# ", 62}; 63 64static struct cmd_node isis_node = 65{ 66 ISIS_NODE, 67 "%s(config-router)# ", 68}; 69 70static struct cmd_node interface_node = 71{ 72 INTERFACE_NODE, 73 "%s(config-if)# ", 74}; 75 76static struct cmd_node rmap_node = 77{ 78 RMAP_NODE, 79 "%s(config-route-map)# " 80}; 81 82static struct cmd_node zebra_node = 83{ 84 ZEBRA_NODE, 85 "%s(config-router)# " 86}; 87 88static struct cmd_node bgp_vpnv4_node = 89{ 90 BGP_VPNV4_NODE, 91 "%s(config-router-af)# " 92}; 93 94static struct cmd_node bgp_ipv4_node = 95{ 96 BGP_IPV4_NODE, 97 "%s(config-router-af)# " 98}; 99 100static struct cmd_node bgp_ipv4m_node = 101{ 102 BGP_IPV4M_NODE, 103 "%s(config-router-af)# " 104}; 105 106static struct cmd_node bgp_ipv6_node = 107{ 108 BGP_IPV6_NODE, 109 "%s(config-router-af)# " 110}; 111 112static struct cmd_node bgp_ipv6m_node = 113{ 114 BGP_IPV6M_NODE, 115 "%s(config-router-af)# " 116}; 117 118static struct cmd_node ospf_node = 119{ 120 OSPF_NODE, 121 "%s(config-router)# " 122}; 123 124static struct cmd_node ripng_node = 125{ 126 RIPNG_NODE, 127 "%s(config-router)# " 128}; 129 130static struct cmd_node ospf6_node = 131{ 132 OSPF6_NODE, 133 "%s(config-ospf6)# " 134}; 135 136static struct cmd_node babel_node = 137{ 138 BABEL_NODE, 139 "%s(config-babel)# " 140}; 141 142static struct cmd_node keychain_node = 143{ 144 KEYCHAIN_NODE, 145 "%s(config-keychain)# " 146}; 147 148static struct cmd_node keychain_key_node = 149{ 150 KEYCHAIN_KEY_NODE, 151 "%s(config-keychain-key)# " 152}; 153 154static int 155test_callback(struct cmd_element *cmd, struct vty *vty, int argc, const char *argv[]) 156{ 157 int offset; 158 int rv; 159 int i; 160 161 offset = 0; 162 rv = snprintf(test_buf, sizeof(test_buf), "'%s'", cmd->string); 163 if (rv < 0) 164 abort(); 165 166 offset += rv; 167 168 for (i = 0; i < argc; i++) 169 { 170 rv = snprintf(test_buf + offset, sizeof(test_buf) - offset, "%s'%s'", 171 (i == 0) ? ": " : ", ", argv[i]); 172 if (rv < 0) 173 abort(); 174 offset += rv; 175 } 176 177 return CMD_SUCCESS; 178} 179 180static void 181test_load(void) 182{ 183 char line[4096]; 184 185 test_cmds = vector_init(VECTOR_MIN_SIZE); 186 187 while (fgets(line, sizeof(line), stdin) != NULL) 188 { 189 if (strlen(line)) 190 line[strlen(line) - 1] = '\0'; 191 if (line[0] == '#') 192 continue; 193 vector_set(test_cmds, XSTRDUP(MTYPE_STRVEC, line)); 194 } 195} 196 197static void 198test_init(void) 199{ 200 unsigned int node; 201 unsigned int i; 202 struct cmd_node *cnode; 203 struct cmd_element *cmd; 204 205 cmd_init(1); 206 207 install_node (&bgp_node, NULL); 208 install_node (&rip_node, NULL); 209 install_node (&interface_node, NULL); 210 install_node (&rmap_node, NULL); 211 install_node (&zebra_node, NULL); 212 install_node (&bgp_vpnv4_node, NULL); 213 install_node (&bgp_ipv4_node, NULL); 214 install_node (&bgp_ipv4m_node, NULL); 215 install_node (&bgp_ipv6_node, NULL); 216 install_node (&bgp_ipv6m_node, NULL); 217 install_node (&ospf_node, NULL); 218 install_node (&ripng_node, NULL); 219 install_node (&ospf6_node, NULL); 220 install_node (&babel_node, NULL); 221 install_node (&keychain_node, NULL); 222 install_node (&keychain_key_node, NULL); 223 install_node (&isis_node, NULL); 224 install_node (&vty_node, NULL); 225 226 test_init_cmd(); 227 228 for (node = 0; node < vector_active(cmdvec); node++) 229 if ((cnode = vector_slot(cmdvec, node)) != NULL) 230 for (i = 0; i < vector_active(cnode->cmd_vector); i++) 231 if ((cmd = vector_slot(cnode->cmd_vector, i)) != NULL) 232 { 233 cmd->daemon = 0; 234 cmd->func = test_callback; 235 } 236 test_load(); 237 vty_init_vtysh(); 238} 239 240static void 241test_terminate(void) 242{ 243 unsigned int i; 244 245 vty_terminate(); 246 for (i = 0; i < vector_active(test_cmds); i++) 247 XFREE(MTYPE_STRVEC, vector_slot(test_cmds, i)); 248 vector_free(test_cmds); 249 cmd_terminate(); 250} 251 252static void 253test_run(struct prng *prng, struct vty *vty, const char *cmd, unsigned int edit_dist, unsigned int node_index, int verbose) 254{ 255 const char *test_str; 256 vector vline; 257 int ret; 258 unsigned int i; 259 char **completions; 260 unsigned int j; 261 struct cmd_node *cnode; 262 vector descriptions; 263 int appended_null; 264 int no_match; 265 266 test_str = prng_fuzz(prng, cmd, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_:. /", edit_dist); 267 vline = cmd_make_strvec(test_str); 268 269 if (vline == NULL) 270 return; 271 272 appended_null = 0; 273 for (i = 0; i < vector_active(cmdvec); i++) 274 if ((cnode = vector_slot(cmdvec, i)) != NULL) 275 { 276 if (node_index != (unsigned int)-1 && i != node_index) 277 continue; 278 279 if (appended_null) 280 { 281 vector_unset(vline, vector_active(vline) - 1); 282 appended_null = 0; 283 } 284 vty->node = cnode->node; 285 test_buf[0] = '\0'; 286 ret = cmd_execute_command(vline, vty, NULL, 0); 287 no_match = (ret == CMD_ERR_NO_MATCH); 288 if (verbose || !no_match) 289 printf("execute relaxed '%s'@%d: rv==%d%s%s\n", 290 test_str, 291 cnode->node, 292 ret, 293 (test_buf[0] != '\0') ? ", " : "", 294 test_buf); 295 296 vty->node = cnode->node; 297 test_buf[0] = '\0'; 298 ret = cmd_execute_command_strict(vline, vty, NULL); 299 if (verbose || !no_match) 300 printf("execute strict '%s'@%d: rv==%d%s%s\n", 301 test_str, 302 cnode->node, 303 ret, 304 (test_buf[0] != '\0') ? ", " : "", 305 test_buf); 306 307 if (isspace((int) test_str[strlen(test_str) - 1])) 308 { 309 vector_set (vline, NULL); 310 appended_null = 1; 311 } 312 313 vty->node = cnode->node; 314 completions = cmd_complete_command(vline, vty, &ret); 315 if (verbose || !no_match) 316 printf("complete '%s'@%d: rv==%d\n", 317 test_str, 318 cnode->node, 319 ret); 320 if (completions != NULL) 321 { 322 for (j = 0; completions[j] != NULL; j++) 323 { 324 printf(" '%s'\n", completions[j]); 325 XFREE(MTYPE_TMP, completions[j]); 326 } 327 XFREE(MTYPE_VECTOR_INDEX, completions); 328 } 329 330 vty->node = cnode->node; 331 descriptions = cmd_describe_command(vline, vty, &ret); 332 if (verbose || !no_match) 333 printf("describe '%s'@%d: rv==%d\n", 334 test_str, 335 cnode->node, 336 ret); 337 if (descriptions != NULL) 338 { 339 for (j = 0; j < vector_active(descriptions); j++) 340 { 341 struct cmd_token *cmd = vector_slot(descriptions, j); 342 printf(" '%s' '%s'\n", cmd->cmd, cmd->desc); 343 } 344 vector_free(descriptions); 345 } 346 } 347 cmd_free_strvec(vline); 348} 349 350int 351main(int argc, char **argv) 352{ 353 int opt; 354 struct prng *prng; 355 struct vty *vty; 356 unsigned int edit_distance; 357 unsigned int max_edit_distance; 358 unsigned int node_index; 359 int verbose; 360 unsigned int test_cmd; 361 unsigned int iteration; 362 unsigned int num_iterations; 363 364 max_edit_distance = 3; 365 node_index = -1; 366 verbose = 0; 367 368 while ((opt = getopt(argc, argv, "e:n:v")) != -1) 369 { 370 switch (opt) 371 { 372 case 'e': 373 max_edit_distance = atoi(optarg); 374 break; 375 case 'n': 376 node_index = atoi(optarg); 377 break; 378 case 'v': 379 verbose++; 380 break; 381 default: 382 fprintf(stderr, "Usage: %s [-e <edit_dist>] [-n <node_idx>] [-v]\n", argv[0]); 383 exit(1); 384 break; 385 } 386 } 387 388 test_init(); 389 prng = prng_new(0); 390 391 vty = vty_new(); 392 vty->type = VTY_TERM; 393 394 fprintf(stderr, "Progress:\n0/%u", vector_active(test_cmds)); 395 for (test_cmd = 0; test_cmd < vector_active(test_cmds); test_cmd++) 396 { 397 for (edit_distance = 0; 398 edit_distance <= max_edit_distance; 399 edit_distance++) 400 { 401 num_iterations = 1 << edit_distance; 402 num_iterations *= num_iterations * num_iterations; 403 404 for (iteration = 0; iteration < num_iterations; iteration++) 405 test_run(prng, vty, vector_slot(test_cmds, test_cmd), edit_distance, node_index, verbose); 406 } 407 fprintf(stderr, "\r%u/%u", test_cmd + 1, vector_active(test_cmds)); 408 } 409 fprintf(stderr, "\nDone.\n"); 410 411 vty_close(vty); 412 prng_free(prng); 413 test_terminate(); 414 return 0; 415} 416