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