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