getrpc_test.c revision 292323
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/lib/libc/tests/nss/getrpc_test.c 292323 2015-12-16 08:09:03Z 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
73static void usage(void)  __attribute__((__noreturn__));
74
75IMPLEMENT_TEST_DATA(rpcent)
76IMPLEMENT_TEST_FILE_SNAPSHOT(rpcent)
77IMPLEMENT_1PASS_TEST(rpcent)
78IMPLEMENT_2PASS_TEST(rpcent)
79
80static void
81clone_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
113static void
114free_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
127static  int
128compare_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
157errfin:
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
167static void
168sdump_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
198static int
199rpcent_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
263static void
264dump_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
274static int
275rpcent_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
291static int
292rpcent_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);
313errfin:
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 peice (these cases are usually marked as PROBLEM in
321 * /etc/peices. This functions is needed also when one peice+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 */
324static int
325rpcent_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
332static int
333rpcent_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
365errfin:
366	printf("not ok\n");
367
368	return (-1);
369}
370
371static int
372rpcent_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
392static int
393rpcent_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
403int
404run_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
479fin:
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
488ATF_TC_WITHOUT_HEAD(build_snapshot);
489ATF_TC_BODY(build_snapshot, tc)
490{
491
492	ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
493}
494
495ATF_TC_WITHOUT_HEAD(getrpcbyname);
496ATF_TC_BODY(getrpcbyname, tc)
497{
498
499	ATF_REQUIRE(run_tests(NULL, TEST_GETRPCBYNAME) == 0);
500}
501
502ATF_TC_WITHOUT_HEAD(getrpcbyname_with_snapshot);
503ATF_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
510ATF_TC_WITHOUT_HEAD(getrpcbynumber);
511ATF_TC_BODY(getrpcbynumber, tc)
512{
513
514	ATF_REQUIRE(run_tests(NULL, TEST_GETRPCBYNUMBER) == 0);
515}
516
517ATF_TC_WITHOUT_HEAD(getrpcbynumber_with_snapshot);
518ATF_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
525ATF_TC_WITHOUT_HEAD(getrpcbyent);
526ATF_TC_BODY(getrpcbyent, tc)
527{
528
529	ATF_REQUIRE(run_tests(NULL, TEST_GETRPCENT) == 0);
530}
531
532ATF_TC_WITHOUT_HEAD(getrpcbyent_with_snapshot);
533ATF_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
540ATF_TC_WITHOUT_HEAD(getrpcbyent_with_two_pass);
541ATF_TC_BODY(getrpcbyent_with_two_pass, tc)
542{
543
544	ATF_REQUIRE(run_tests(NULL, TEST_GETRPCENT_2PASS) == 0);
545}
546
547ATF_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