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