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