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 <rpc/rpc.h> 33 #include <errno.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <stringlist.h> 38 #include <unistd.h> 39 40 #include <atf-c.h> 41 42 #include "testutil.h" 43 44 enum test_methods { 45 TEST_GETRPCENT, 46 TEST_GETRPCBYNAME, 47 TEST_GETRPCBYNUMBER, 48 TEST_GETRPCENT_2PASS, 49 TEST_BUILD_SNAPSHOT 50 }; 51 52 DECLARE_TEST_DATA(rpcent) 53 DECLARE_TEST_FILE_SNAPSHOT(rpcent) 54 DECLARE_1PASS_TEST(rpcent) 55 DECLARE_2PASS_TEST(rpcent) 56 57 static void clone_rpcent(struct rpcent *, struct rpcent const *); 58 static int compare_rpcent(struct rpcent *, struct rpcent *, void *); 59 static void dump_rpcent(struct rpcent *); 60 static void free_rpcent(struct rpcent *); 61 62 static void sdump_rpcent(struct rpcent *, char *, size_t); 63 static int rpcent_read_snapshot_func(struct rpcent *, char *); 64 65 static int rpcent_check_ambiguity(struct rpcent_test_data *, 66 struct rpcent *); 67 static int rpcent_fill_test_data(struct rpcent_test_data *); 68 static int rpcent_test_correctness(struct rpcent *, void *); 69 static int rpcent_test_getrpcbyname(struct rpcent *, void *); 70 static int rpcent_test_getrpcbynumber(struct rpcent *, void *); 71 static int rpcent_test_getrpcent(struct rpcent *, void *); 72 73 IMPLEMENT_TEST_DATA(rpcent) 74 IMPLEMENT_TEST_FILE_SNAPSHOT(rpcent) 75 IMPLEMENT_1PASS_TEST(rpcent) 76 IMPLEMENT_2PASS_TEST(rpcent) 77 78 static void 79 clone_rpcent(struct rpcent *dest, struct rpcent const *src) 80 { 81 ATF_REQUIRE(dest != NULL); 82 ATF_REQUIRE(src != NULL); 83 84 char **cp; 85 int aliases_num; 86 87 memset(dest, 0, sizeof(struct rpcent)); 88 89 if (src->r_name != NULL) { 90 dest->r_name = strdup(src->r_name); 91 ATF_REQUIRE(dest->r_name != NULL); 92 } 93 94 dest->r_number = src->r_number; 95 96 if (src->r_aliases != NULL) { 97 aliases_num = 0; 98 for (cp = src->r_aliases; *cp; ++cp) 99 ++aliases_num; 100 101 dest->r_aliases = calloc(aliases_num + 1, sizeof(char *)); 102 ATF_REQUIRE(dest->r_aliases != NULL); 103 104 for (cp = src->r_aliases; *cp; ++cp) { 105 dest->r_aliases[cp - src->r_aliases] = strdup(*cp); 106 ATF_REQUIRE(dest->r_aliases[cp - src->r_aliases] != NULL); 107 } 108 } 109 } 110 111 static void 112 free_rpcent(struct rpcent *rpc) 113 { 114 char **cp; 115 116 ATF_REQUIRE(rpc != NULL); 117 118 free(rpc->r_name); 119 120 for (cp = rpc->r_aliases; *cp; ++cp) 121 free(*cp); 122 free(rpc->r_aliases); 123 } 124 125 static int 126 compare_rpcent(struct rpcent *rpc1, struct rpcent *rpc2, void *mdata) 127 { 128 char **c1, **c2; 129 130 if (rpc1 == rpc2) 131 return 0; 132 133 if ((rpc1 == NULL) || (rpc2 == NULL)) 134 goto errfin; 135 136 if ((strcmp(rpc1->r_name, rpc2->r_name) != 0) || 137 (rpc1->r_number != rpc2->r_number)) 138 goto errfin; 139 140 c1 = rpc1->r_aliases; 141 c2 = rpc2->r_aliases; 142 143 if ((rpc1->r_aliases == NULL) || (rpc2->r_aliases == NULL)) 144 goto errfin; 145 146 for (;*c1 && *c2; ++c1, ++c2) 147 if (strcmp(*c1, *c2) != 0) 148 goto errfin; 149 150 if ((*c1 != NULL) || (*c2 != NULL)) 151 goto errfin; 152 153 return 0; 154 155 errfin: 156 if (mdata == NULL) { 157 printf("following structures are not equal:\n"); 158 dump_rpcent(rpc1); 159 dump_rpcent(rpc2); 160 } 161 162 return (-1); 163 } 164 165 static void 166 sdump_rpcent(struct rpcent *rpc, char *buffer, size_t buflen) 167 { 168 char **cp; 169 int written; 170 171 written = snprintf(buffer, buflen, "%s %d", 172 rpc->r_name, rpc->r_number); 173 buffer += written; 174 if (written > (int)buflen) 175 return; 176 buflen -= written; 177 178 if (rpc->r_aliases != NULL) { 179 if (*(rpc->r_aliases) != NULL) { 180 for (cp = rpc->r_aliases; *cp; ++cp) { 181 written = snprintf(buffer, buflen, " %s", *cp); 182 buffer += written; 183 if (written > (int)buflen) 184 return; 185 buflen -= written; 186 187 if (buflen == 0) 188 return; 189 } 190 } else 191 snprintf(buffer, buflen, " noaliases"); 192 } else 193 snprintf(buffer, buflen, " (null)"); 194 } 195 196 static int 197 rpcent_read_snapshot_func(struct rpcent *rpc, char *line) 198 { 199 StringList *sl; 200 char *s, *ps, *ts; 201 int i; 202 203 printf("1 line read from snapshot:\n%s\n", line); 204 205 i = 0; 206 sl = NULL; 207 ps = line; 208 memset(rpc, 0, sizeof(struct rpcent)); 209 while ((s = strsep(&ps, " ")) != NULL) { 210 switch (i) { 211 case 0: 212 rpc->r_name = strdup(s); 213 ATF_REQUIRE(rpc->r_name != NULL); 214 break; 215 216 case 1: 217 rpc->r_number = (int)strtol(s, &ts, 10); 218 if (*ts != '\0') { 219 free(rpc->r_name); 220 return (-1); 221 } 222 break; 223 224 default: 225 if (sl == NULL) { 226 if (strcmp(s, "(null)") == 0) 227 return (0); 228 229 sl = sl_init(); 230 ATF_REQUIRE(sl != NULL); 231 232 if (strcmp(s, "noaliases") != 0) { 233 ts = strdup(s); 234 ATF_REQUIRE(ts != NULL); 235 sl_add(sl, ts); 236 } 237 } else { 238 ts = strdup(s); 239 ATF_REQUIRE(ts != NULL); 240 sl_add(sl, ts); 241 } 242 break; 243 } 244 i++; 245 } 246 247 if (i < 3) { 248 free(rpc->r_name); 249 memset(rpc, 0, sizeof(struct rpcent)); 250 return (-1); 251 } 252 253 sl_add(sl, NULL); 254 rpc->r_aliases = sl->sl_str; 255 256 /* NOTE: is it a dirty hack or not? */ 257 free(sl); 258 return (0); 259 } 260 261 static void 262 dump_rpcent(struct rpcent *result) 263 { 264 if (result != NULL) { 265 char buffer[1024]; 266 sdump_rpcent(result, buffer, sizeof(buffer)); 267 printf("%s\n", buffer); 268 } else 269 printf("(null)\n"); 270 } 271 272 static int 273 rpcent_fill_test_data(struct rpcent_test_data *td) 274 { 275 struct rpcent *rpc; 276 277 setrpcent(1); 278 while ((rpc = getrpcent()) != NULL) { 279 if (rpcent_test_correctness(rpc, NULL) == 0) 280 TEST_DATA_APPEND(rpcent, td, rpc); 281 else 282 return (-1); 283 } 284 endrpcent(); 285 286 return (0); 287 } 288 289 static int 290 rpcent_test_correctness(struct rpcent *rpc, void *mdata __unused) 291 { 292 293 printf("testing correctness with the following data:\n"); 294 dump_rpcent(rpc); 295 296 if (rpc == NULL) 297 goto errfin; 298 299 if (rpc->r_name == NULL) 300 goto errfin; 301 302 if (rpc->r_number < 0) 303 goto errfin; 304 305 if (rpc->r_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 /* rpcent_check_ambiguity() is needed when one port+rpc 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+rpc is 320 * associated with several ports. We have to check all the rpcent structures 321 * to make sure that rpc really exists and correct */ 322 static int 323 rpcent_check_ambiguity(struct rpcent_test_data *td, struct rpcent *rpc) 324 { 325 326 return (TEST_DATA_FIND(rpcent, td, rpc, compare_rpcent, 327 NULL) != NULL ? 0 : -1); 328 } 329 330 static int 331 rpcent_test_getrpcbyname(struct rpcent *rpc_model, void *mdata) 332 { 333 char **alias; 334 struct rpcent *rpc; 335 336 printf("testing getrpcbyname() with the following data:\n"); 337 dump_rpcent(rpc_model); 338 339 rpc = getrpcbyname(rpc_model->r_name); 340 if (rpcent_test_correctness(rpc, NULL) != 0) 341 goto errfin; 342 343 if ((compare_rpcent(rpc, rpc_model, NULL) != 0) && 344 (rpcent_check_ambiguity((struct rpcent_test_data *)mdata, rpc) 345 !=0)) 346 goto errfin; 347 348 for (alias = rpc_model->r_aliases; *alias; ++alias) { 349 rpc = getrpcbyname(*alias); 350 351 if (rpcent_test_correctness(rpc, NULL) != 0) 352 goto errfin; 353 354 if ((compare_rpcent(rpc, rpc_model, NULL) != 0) && 355 (rpcent_check_ambiguity( 356 (struct rpcent_test_data *)mdata, rpc) != 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 rpcent_test_getrpcbynumber(struct rpcent *rpc_model, void *mdata) 371 { 372 struct rpcent *rpc; 373 374 printf("testing getrpcbyport() with the following data...\n"); 375 dump_rpcent(rpc_model); 376 377 rpc = getrpcbynumber(rpc_model->r_number); 378 if (rpcent_test_correctness(rpc, NULL) != 0 || 379 (compare_rpcent(rpc, rpc_model, NULL) != 0 && 380 rpcent_check_ambiguity((struct rpcent_test_data *)mdata, rpc) 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 rpcent_test_getrpcent(struct rpcent *rpc, void *mdata __unused) 392 { 393 394 /* 395 * Only correctness can be checked when doing 1-pass test for 396 * getrpcent(). 397 */ 398 return (rpcent_test_correctness(rpc, NULL)); 399 } 400 401 static int 402 run_tests(const char *snapshot_file, enum test_methods method) 403 { 404 struct rpcent_test_data td, td_snap, td_2pass; 405 int rv; 406 407 TEST_DATA_INIT(rpcent, &td, clone_rpcent, free_rpcent); 408 TEST_DATA_INIT(rpcent, &td_snap, clone_rpcent, free_rpcent); 409 if (snapshot_file != NULL) { 410 if (access(snapshot_file, W_OK | R_OK) != 0) { 411 if (errno == ENOENT) 412 method = TEST_BUILD_SNAPSHOT; 413 else { 414 printf("can't access the file %s\n", 415 snapshot_file); 416 417 rv = -1; 418 goto fin; 419 } 420 } else { 421 if (method == TEST_BUILD_SNAPSHOT) { 422 rv = 0; 423 goto fin; 424 } 425 426 TEST_SNAPSHOT_FILE_READ(rpcent, snapshot_file, 427 &td_snap, rpcent_read_snapshot_func); 428 } 429 } 430 431 rv = rpcent_fill_test_data(&td); 432 if (rv == -1) 433 return (-1); 434 switch (method) { 435 case TEST_GETRPCBYNAME: 436 if (snapshot_file == NULL) 437 rv = DO_1PASS_TEST(rpcent, &td, 438 rpcent_test_getrpcbyname, (void *)&td); 439 else 440 rv = DO_1PASS_TEST(rpcent, &td_snap, 441 rpcent_test_getrpcbyname, (void *)&td_snap); 442 break; 443 case TEST_GETRPCBYNUMBER: 444 if (snapshot_file == NULL) 445 rv = DO_1PASS_TEST(rpcent, &td, 446 rpcent_test_getrpcbynumber, (void *)&td); 447 else 448 rv = DO_1PASS_TEST(rpcent, &td_snap, 449 rpcent_test_getrpcbynumber, (void *)&td_snap); 450 break; 451 case TEST_GETRPCENT: 452 if (snapshot_file == NULL) 453 rv = DO_1PASS_TEST(rpcent, &td, rpcent_test_getrpcent, 454 (void *)&td); 455 else 456 rv = DO_2PASS_TEST(rpcent, &td, &td_snap, 457 compare_rpcent, NULL); 458 break; 459 case TEST_GETRPCENT_2PASS: 460 TEST_DATA_INIT(rpcent, &td_2pass, clone_rpcent, free_rpcent); 461 rv = rpcent_fill_test_data(&td_2pass); 462 if (rv != -1) 463 rv = DO_2PASS_TEST(rpcent, &td, &td_2pass, 464 compare_rpcent, NULL); 465 TEST_DATA_DESTROY(rpcent, &td_2pass); 466 break; 467 case TEST_BUILD_SNAPSHOT: 468 if (snapshot_file != NULL) 469 rv = TEST_SNAPSHOT_FILE_WRITE(rpcent, snapshot_file, &td, 470 sdump_rpcent); 471 break; 472 default: 473 rv = 0; 474 break; 475 } 476 477 fin: 478 TEST_DATA_DESTROY(rpcent, &td_snap); 479 TEST_DATA_DESTROY(rpcent, &td); 480 481 return (rv); 482 } 483 484 #define SNAPSHOT_FILE "snapshot_rpc" 485 486 ATF_TC_WITHOUT_HEAD(build_snapshot); 487 ATF_TC_BODY(build_snapshot, tc) 488 { 489 490 ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0); 491 } 492 493 ATF_TC_WITHOUT_HEAD(getrpcbyname); 494 ATF_TC_BODY(getrpcbyname, tc) 495 { 496 497 ATF_REQUIRE(run_tests(NULL, TEST_GETRPCBYNAME) == 0); 498 } 499 500 ATF_TC_WITHOUT_HEAD(getrpcbyname_with_snapshot); 501 ATF_TC_BODY(getrpcbyname_with_snapshot, tc) 502 { 503 504 ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0); 505 ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETRPCBYNAME) == 0); 506 } 507 508 ATF_TC_WITHOUT_HEAD(getrpcbynumber); 509 ATF_TC_BODY(getrpcbynumber, tc) 510 { 511 512 ATF_REQUIRE(run_tests(NULL, TEST_GETRPCBYNUMBER) == 0); 513 } 514 515 ATF_TC_WITHOUT_HEAD(getrpcbynumber_with_snapshot); 516 ATF_TC_BODY(getrpcbynumber_with_snapshot, tc) 517 { 518 519 ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0); 520 ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETRPCBYNUMBER) == 0); 521 } 522 523 ATF_TC_WITHOUT_HEAD(getrpcbyent); 524 ATF_TC_BODY(getrpcbyent, tc) 525 { 526 527 ATF_REQUIRE(run_tests(NULL, TEST_GETRPCENT) == 0); 528 } 529 530 ATF_TC_WITHOUT_HEAD(getrpcbyent_with_snapshot); 531 ATF_TC_BODY(getrpcbyent_with_snapshot, tc) 532 { 533 534 ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0); 535 ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETRPCENT) == 0); 536 } 537 538 ATF_TC_WITHOUT_HEAD(getrpcbyent_with_two_pass); 539 ATF_TC_BODY(getrpcbyent_with_two_pass, tc) 540 { 541 542 ATF_REQUIRE(run_tests(NULL, TEST_GETRPCENT_2PASS) == 0); 543 } 544 545 ATF_TP_ADD_TCS(tp) 546 { 547 548 ATF_TP_ADD_TC(tp, build_snapshot); 549 ATF_TP_ADD_TC(tp, getrpcbyname); 550 ATF_TP_ADD_TC(tp, getrpcbyname_with_snapshot); 551 ATF_TP_ADD_TC(tp, getrpcbynumber); 552 ATF_TP_ADD_TC(tp, getrpcbynumber_with_snapshot); 553 ATF_TP_ADD_TC(tp, getrpcbyent); 554 ATF_TP_ADD_TC(tp, getrpcbyent_with_snapshot); 555 ATF_TP_ADD_TC(tp, getrpcbyent_with_two_pass); 556 557 return (atf_no_error()); 558 } 559