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