getrpc_test.c revision 319299
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: stable/11/lib/libc/tests/nss/getrpc_test.c 319299 2017-05-31 08:32:05Z ngie $");
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
44enum test_methods {
45	TEST_GETRPCENT,
46	TEST_GETRPCBYNAME,
47	TEST_GETRPCBYNUMBER,
48	TEST_GETRPCENT_2PASS,
49	TEST_BUILD_SNAPSHOT
50};
51
52DECLARE_TEST_DATA(rpcent)
53DECLARE_TEST_FILE_SNAPSHOT(rpcent)
54DECLARE_1PASS_TEST(rpcent)
55DECLARE_2PASS_TEST(rpcent)
56
57static void clone_rpcent(struct rpcent *, struct rpcent const *);
58static int compare_rpcent(struct rpcent *, struct rpcent *, void *);
59static void dump_rpcent(struct rpcent *);
60static void free_rpcent(struct rpcent *);
61
62static void sdump_rpcent(struct rpcent *, char *, size_t);
63static int rpcent_read_snapshot_func(struct rpcent *, char *);
64
65static int rpcent_check_ambiguity(struct rpcent_test_data *,
66	struct rpcent *);
67static int rpcent_fill_test_data(struct rpcent_test_data *);
68static int rpcent_test_correctness(struct rpcent *, void *);
69static int rpcent_test_getrpcbyname(struct rpcent *, void *);
70static int rpcent_test_getrpcbynumber(struct rpcent *, void *);
71static int rpcent_test_getrpcent(struct rpcent *, void *);
72
73IMPLEMENT_TEST_DATA(rpcent)
74IMPLEMENT_TEST_FILE_SNAPSHOT(rpcent)
75IMPLEMENT_1PASS_TEST(rpcent)
76IMPLEMENT_2PASS_TEST(rpcent)
77
78static void
79clone_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
111static void
112free_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
125static  int
126compare_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 != '\0') || (*c2 != '\0'))
151		goto errfin;
152
153	return 0;
154
155errfin:
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
165static void
166sdump_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) != '\0') {
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
196static int
197rpcent_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
261static void
262dump_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
272static int
273rpcent_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
289static int
290rpcent_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);
311errfin:
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 */
322static int
323rpcent_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
330static int
331rpcent_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
363errfin:
364	printf("not ok\n");
365
366	return (-1);
367}
368
369static int
370rpcent_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
390static int
391rpcent_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
401static int
402run_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
477fin:
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
486ATF_TC_WITHOUT_HEAD(build_snapshot);
487ATF_TC_BODY(build_snapshot, tc)
488{
489
490	ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
491}
492
493ATF_TC_WITHOUT_HEAD(getrpcbyname);
494ATF_TC_BODY(getrpcbyname, tc)
495{
496
497	ATF_REQUIRE(run_tests(NULL, TEST_GETRPCBYNAME) == 0);
498}
499
500ATF_TC_WITHOUT_HEAD(getrpcbyname_with_snapshot);
501ATF_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
508ATF_TC_WITHOUT_HEAD(getrpcbynumber);
509ATF_TC_BODY(getrpcbynumber, tc)
510{
511
512	ATF_REQUIRE(run_tests(NULL, TEST_GETRPCBYNUMBER) == 0);
513}
514
515ATF_TC_WITHOUT_HEAD(getrpcbynumber_with_snapshot);
516ATF_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
523ATF_TC_WITHOUT_HEAD(getrpcbyent);
524ATF_TC_BODY(getrpcbyent, tc)
525{
526
527	ATF_REQUIRE(run_tests(NULL, TEST_GETRPCENT) == 0);
528}
529
530ATF_TC_WITHOUT_HEAD(getrpcbyent_with_snapshot);
531ATF_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
538ATF_TC_WITHOUT_HEAD(getrpcbyent_with_two_pass);
539ATF_TC_BODY(getrpcbyent_with_two_pass, tc)
540{
541
542	ATF_REQUIRE(run_tests(NULL, TEST_GETRPCENT_2PASS) == 0);
543}
544
545ATF_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