getproto_test.c revision 251818
1/*- 2 * Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org> 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 * 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: head/tools/regression/lib/libc/nss/test-getproto.c 251818 2013-06-16 19:35:01Z eadler $"); 29 30#include <arpa/inet.h> 31#include <assert.h> 32#include <errno.h> 33#include <netdb.h> 34#include <stdio.h> 35#include <stdlib.h> 36#include <string.h> 37#include <stringlist.h> 38#include <unistd.h> 39#include "testutil.h" 40 41enum test_methods { 42 TEST_GETPROTOENT, 43 TEST_GETPROTOBYNAME, 44 TEST_GETPROTOBYNUMBER, 45 TEST_GETPROTOENT_2PASS, 46 TEST_BUILD_SNAPSHOT 47}; 48 49static int debug = 0; 50static enum test_methods method = TEST_BUILD_SNAPSHOT; 51 52DECLARE_TEST_DATA(protoent) 53DECLARE_TEST_FILE_SNAPSHOT(protoent) 54DECLARE_1PASS_TEST(protoent) 55DECLARE_2PASS_TEST(protoent) 56 57static void clone_protoent(struct protoent *, struct protoent const *); 58static int compare_protoent(struct protoent *, struct protoent *, void *); 59static void dump_protoent(struct protoent *); 60static void free_protoent(struct protoent *); 61 62static void sdump_protoent(struct protoent *, char *, size_t); 63static int protoent_read_snapshot_func(struct protoent *, char *); 64 65static int protoent_check_ambiguity(struct protoent_test_data *, 66 struct protoent *); 67static int protoent_fill_test_data(struct protoent_test_data *); 68static int protoent_test_correctness(struct protoent *, void *); 69static int protoent_test_getprotobyname(struct protoent *, void *); 70static int protoent_test_getprotobynumber(struct protoent *, void *); 71static int protoent_test_getprotoent(struct protoent *, void *); 72 73static void usage(void) __attribute__((__noreturn__)); 74 75IMPLEMENT_TEST_DATA(protoent) 76IMPLEMENT_TEST_FILE_SNAPSHOT(protoent) 77IMPLEMENT_1PASS_TEST(protoent) 78IMPLEMENT_2PASS_TEST(protoent) 79 80static void 81clone_protoent(struct protoent *dest, struct protoent const *src) 82{ 83 assert(dest != NULL); 84 assert(src != NULL); 85 86 char **cp; 87 int aliases_num; 88 89 memset(dest, 0, sizeof(struct protoent)); 90 91 if (src->p_name != NULL) { 92 dest->p_name = strdup(src->p_name); 93 assert(dest->p_name != NULL); 94 } 95 96 dest->p_proto = src->p_proto; 97 98 if (src->p_aliases != NULL) { 99 aliases_num = 0; 100 for (cp = src->p_aliases; *cp; ++cp) 101 ++aliases_num; 102 103 dest->p_aliases = (char **)malloc((aliases_num+1) * (sizeof(char *))); 104 assert(dest->p_aliases != NULL); 105 memset(dest->p_aliases, 0, (aliases_num+1) * (sizeof(char *))); 106 107 for (cp = src->p_aliases; *cp; ++cp) { 108 dest->p_aliases[cp - src->p_aliases] = strdup(*cp); 109 assert(dest->p_aliases[cp - src->p_aliases] != NULL); 110 } 111 } 112} 113 114static void 115free_protoent(struct protoent *pe) 116{ 117 char **cp; 118 119 assert(pe != NULL); 120 121 free(pe->p_name); 122 123 for (cp = pe->p_aliases; *cp; ++cp) 124 free(*cp); 125 free(pe->p_aliases); 126} 127 128static int 129compare_protoent(struct protoent *pe1, struct protoent *pe2, void *mdata) 130{ 131 char **c1, **c2; 132 133 if (pe1 == pe2) 134 return 0; 135 136 if ((pe1 == NULL) || (pe2 == NULL)) 137 goto errfin; 138 139 if ((strcmp(pe1->p_name, pe2->p_name) != 0) || 140 (pe1->p_proto != pe2->p_proto)) 141 goto errfin; 142 143 c1 = pe1->p_aliases; 144 c2 = pe2->p_aliases; 145 146 if ((pe1->p_aliases == NULL) || (pe2->p_aliases == NULL)) 147 goto errfin; 148 149 for (;*c1 && *c2; ++c1, ++c2) 150 if (strcmp(*c1, *c2) != 0) 151 goto errfin; 152 153 if ((*c1 != '\0') || (*c2 != '\0')) 154 goto errfin; 155 156 return 0; 157 158errfin: 159 if ((debug) && (mdata == NULL)) { 160 printf("following structures are not equal:\n"); 161 dump_protoent(pe1); 162 dump_protoent(pe2); 163 } 164 165 return (-1); 166} 167 168static void 169sdump_protoent(struct protoent *pe, char *buffer, size_t buflen) 170{ 171 char **cp; 172 int written; 173 174 written = snprintf(buffer, buflen, "%s %d", 175 pe->p_name, pe->p_proto); 176 buffer += written; 177 if (written > buflen) 178 return; 179 buflen -= written; 180 181 if (pe->p_aliases != NULL) { 182 if (*(pe->p_aliases) != '\0') { 183 for (cp = pe->p_aliases; *cp; ++cp) { 184 written = snprintf(buffer, buflen, " %s",*cp); 185 buffer += written; 186 if (written > buflen) 187 return; 188 buflen -= written; 189 190 if (buflen == 0) 191 return; 192 } 193 } else 194 snprintf(buffer, buflen, " noaliases"); 195 } else 196 snprintf(buffer, buflen, " (null)"); 197} 198 199static int 200protoent_read_snapshot_func(struct protoent *pe, char *line) 201{ 202 StringList *sl; 203 char *s, *ps, *ts; 204 int i; 205 206 if (debug) 207 printf("1 line read from snapshot:\n%s\n", line); 208 209 i = 0; 210 sl = NULL; 211 ps = line; 212 memset(pe, 0, sizeof(struct protoent)); 213 while ( (s = strsep(&ps, " ")) != NULL) { 214 switch (i) { 215 case 0: 216 pe->p_name = strdup(s); 217 assert(pe->p_name != NULL); 218 break; 219 220 case 1: 221 pe->p_proto = (int)strtol(s, &ts, 10); 222 if (*ts != '\0') { 223 free(pe->p_name); 224 return (-1); 225 } 226 break; 227 228 default: 229 if (sl == NULL) { 230 if (strcmp(s, "(null)") == 0) 231 return (0); 232 233 sl = sl_init(); 234 assert(sl != NULL); 235 236 if (strcmp(s, "noaliases") != 0) { 237 ts = strdup(s); 238 assert(ts != NULL); 239 sl_add(sl, ts); 240 } 241 } else { 242 ts = strdup(s); 243 assert(ts != NULL); 244 sl_add(sl, ts); 245 } 246 break; 247 }; 248 ++i; 249 } 250 251 if (i < 3) { 252 free(pe->p_name); 253 memset(pe, 0, sizeof(struct protoent)); 254 return (-1); 255 } 256 257 sl_add(sl, NULL); 258 pe->p_aliases = sl->sl_str; 259 260 /* NOTE: is it a dirty hack or not? */ 261 free(sl); 262 return (0); 263} 264 265static void 266dump_protoent(struct protoent *result) 267{ 268 if (result != NULL) { 269 char buffer[1024]; 270 sdump_protoent(result, buffer, sizeof(buffer)); 271 printf("%s\n", buffer); 272 } else 273 printf("(null)\n"); 274} 275 276static int 277protoent_fill_test_data(struct protoent_test_data *td) 278{ 279 struct protoent *pe; 280 281 setprotoent(1); 282 while ((pe = getprotoent()) != NULL) { 283 if (protoent_test_correctness(pe, NULL) == 0) 284 TEST_DATA_APPEND(protoent, td, pe); 285 else 286 return (-1); 287 } 288 endprotoent(); 289 290 return (0); 291} 292 293static int 294protoent_test_correctness(struct protoent *pe, void *mdata) 295{ 296 if (debug) { 297 printf("testing correctness with the following data:\n"); 298 dump_protoent(pe); 299 } 300 301 if (pe == NULL) 302 goto errfin; 303 304 if (pe->p_name == NULL) 305 goto errfin; 306 307 if (pe->p_proto < 0) 308 goto errfin; 309 310 if (pe->p_aliases == NULL) 311 goto errfin; 312 313 if (debug) 314 printf("correct\n"); 315 316 return (0); 317errfin: 318 if (debug) 319 printf("incorrect\n"); 320 321 return (-1); 322} 323 324/* protoent_check_ambiguity() is needed when one port+proto is associated with 325 * more than one peice (these cases are usually marked as PROBLEM in 326 * /etc/peices. This functions is needed also when one peice+proto is 327 * associated with several ports. We have to check all the protoent structures 328 * to make sure that pe really exists and correct */ 329static int 330protoent_check_ambiguity(struct protoent_test_data *td, struct protoent *pe) 331{ 332 333 return (TEST_DATA_FIND(protoent, td, pe, compare_protoent, 334 NULL) != NULL ? 0 : -1); 335} 336 337static int 338protoent_test_getprotobyname(struct protoent *pe_model, void *mdata) 339{ 340 char **alias; 341 struct protoent *pe; 342 343 if (debug) { 344 printf("testing getprotobyname() with the following data:\n"); 345 dump_protoent(pe_model); 346 } 347 348 pe = getprotobyname(pe_model->p_name); 349 if (protoent_test_correctness(pe, NULL) != 0) 350 goto errfin; 351 352 if ((compare_protoent(pe, pe_model, NULL) != 0) && 353 (protoent_check_ambiguity((struct protoent_test_data *)mdata, pe) 354 !=0)) 355 goto errfin; 356 357 for (alias = pe_model->p_aliases; *alias; ++alias) { 358 pe = getprotobyname(*alias); 359 360 if (protoent_test_correctness(pe, NULL) != 0) 361 goto errfin; 362 363 if ((compare_protoent(pe, pe_model, NULL) != 0) && 364 (protoent_check_ambiguity( 365 (struct protoent_test_data *)mdata, pe) != 0)) 366 goto errfin; 367 } 368 369 if (debug) 370 printf("ok\n"); 371 return (0); 372 373errfin: 374 if (debug) 375 printf("not ok\n"); 376 377 return (-1); 378} 379 380static int 381protoent_test_getprotobynumber(struct protoent *pe_model, void *mdata) 382{ 383 struct protoent *pe; 384 385 if (debug) { 386 printf("testing getprotobyport() with the following data...\n"); 387 dump_protoent(pe_model); 388 } 389 390 pe = getprotobynumber(pe_model->p_proto); 391 if ((protoent_test_correctness(pe, NULL) != 0) || 392 ((compare_protoent(pe, pe_model, NULL) != 0) && 393 (protoent_check_ambiguity((struct protoent_test_data *)mdata, pe) 394 != 0))) { 395 if (debug) 396 printf("not ok\n"); 397 return (-1); 398 } else { 399 if (debug) 400 printf("ok\n"); 401 return (0); 402 } 403} 404 405static int 406protoent_test_getprotoent(struct protoent *pe, void *mdata) 407{ 408 /* Only correctness can be checked when doing 1-pass test for 409 * getprotoent(). */ 410 return (protoent_test_correctness(pe, NULL)); 411} 412 413static void 414usage(void) 415{ 416 (void)fprintf(stderr, 417 "Usage: %s -nve2 [-d] [-s <file>]\n", 418 getprogname()); 419 exit(1); 420} 421 422int 423main(int argc, char **argv) 424{ 425 struct protoent_test_data td, td_snap, td_2pass; 426 char *snapshot_file; 427 int rv; 428 int c; 429 430 if (argc < 2) 431 usage(); 432 433 snapshot_file = NULL; 434 while ((c = getopt(argc, argv, "nve2ds:")) != -1) 435 switch (c) { 436 case 'd': 437 debug++; 438 break; 439 case 'n': 440 method = TEST_GETPROTOBYNAME; 441 break; 442 case 'v': 443 method = TEST_GETPROTOBYNUMBER; 444 break; 445 case 'e': 446 method = TEST_GETPROTOENT; 447 break; 448 case '2': 449 method = TEST_GETPROTOENT_2PASS; 450 break; 451 case 's': 452 snapshot_file = strdup(optarg); 453 break; 454 default: 455 usage(); 456 } 457 458 TEST_DATA_INIT(protoent, &td, clone_protoent, free_protoent); 459 TEST_DATA_INIT(protoent, &td_snap, clone_protoent, free_protoent); 460 if (snapshot_file != NULL) { 461 if (access(snapshot_file, W_OK | R_OK) != 0) { 462 if (errno == ENOENT) 463 method = TEST_BUILD_SNAPSHOT; 464 else { 465 if (debug) 466 printf("can't access the file %s\n", 467 snapshot_file); 468 469 rv = -1; 470 goto fin; 471 } 472 } else { 473 if (method == TEST_BUILD_SNAPSHOT) { 474 rv = 0; 475 goto fin; 476 } 477 478 TEST_SNAPSHOT_FILE_READ(protoent, snapshot_file, 479 &td_snap, protoent_read_snapshot_func); 480 } 481 } 482 483 rv = protoent_fill_test_data(&td); 484 if (rv == -1) 485 return (-1); 486 switch (method) { 487 case TEST_GETPROTOBYNAME: 488 if (snapshot_file == NULL) 489 rv = DO_1PASS_TEST(protoent, &td, 490 protoent_test_getprotobyname, (void *)&td); 491 else 492 rv = DO_1PASS_TEST(protoent, &td_snap, 493 protoent_test_getprotobyname, (void *)&td_snap); 494 break; 495 case TEST_GETPROTOBYNUMBER: 496 if (snapshot_file == NULL) 497 rv = DO_1PASS_TEST(protoent, &td, 498 protoent_test_getprotobynumber, (void *)&td); 499 else 500 rv = DO_1PASS_TEST(protoent, &td_snap, 501 protoent_test_getprotobynumber, (void *)&td_snap); 502 break; 503 case TEST_GETPROTOENT: 504 if (snapshot_file == NULL) 505 rv = DO_1PASS_TEST(protoent, &td, 506 protoent_test_getprotoent, (void *)&td); 507 else 508 rv = DO_2PASS_TEST(protoent, &td, &td_snap, 509 compare_protoent, NULL); 510 break; 511 case TEST_GETPROTOENT_2PASS: 512 TEST_DATA_INIT(protoent, &td_2pass, clone_protoent, 513 free_protoent); 514 rv = protoent_fill_test_data(&td_2pass); 515 if (rv != -1) 516 rv = DO_2PASS_TEST(protoent, &td, &td_2pass, 517 compare_protoent, NULL); 518 TEST_DATA_DESTROY(protoent, &td_2pass); 519 break; 520 case TEST_BUILD_SNAPSHOT: 521 if (snapshot_file != NULL) 522 rv = TEST_SNAPSHOT_FILE_WRITE(protoent, snapshot_file, &td, 523 sdump_protoent); 524 break; 525 default: 526 rv = 0; 527 break; 528 }; 529 530fin: 531 TEST_DATA_DESTROY(protoent, &td_snap); 532 TEST_DATA_DESTROY(protoent, &td); 533 free(snapshot_file); 534 return (rv); 535} 536