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