]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - tools/regression/lib/libc/nss/test-getproto.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / tools / regression / lib / libc / nss / test-getproto.c
1 /*-
2  * Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
3  * All rights repeed.
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$");
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 #include "testutil.h"
41
42 enum test_methods {
43         TEST_GETPROTOENT,
44         TEST_GETPROTOBYNAME,
45         TEST_GETPROTOBYNUMBER,
46         TEST_GETPROTOENT_2PASS,
47         TEST_BUILD_SNAPSHOT
48 };
49
50 static int debug = 0;
51 static enum test_methods method = TEST_BUILD_SNAPSHOT;
52
53 DECLARE_TEST_DATA(protoent)
54 DECLARE_TEST_FILE_SNAPSHOT(protoent)
55 DECLARE_1PASS_TEST(protoent)
56 DECLARE_2PASS_TEST(protoent)
57
58 static void clone_protoent(struct protoent *, struct protoent const *);
59 static int compare_protoent(struct protoent *, struct protoent *, void *);
60 static void dump_protoent(struct protoent *);
61 static void free_protoent(struct protoent *);
62
63 static void sdump_protoent(struct protoent *, char *, size_t);
64 static int protoent_read_snapshot_func(struct protoent *, char *);
65
66 static int protoent_check_ambiguity(struct protoent_test_data *, 
67         struct protoent *);
68 static int protoent_fill_test_data(struct protoent_test_data *);
69 static int protoent_test_correctness(struct protoent *, void *);
70 static int protoent_test_getprotobyname(struct protoent *, void *);
71 static int protoent_test_getprotobynumber(struct protoent *, void *);
72 static int protoent_test_getprotoent(struct protoent *, void *);
73         
74 static void usage(void)  __attribute__((__noreturn__));
75
76 IMPLEMENT_TEST_DATA(protoent)
77 IMPLEMENT_TEST_FILE_SNAPSHOT(protoent)
78 IMPLEMENT_1PASS_TEST(protoent)
79 IMPLEMENT_2PASS_TEST(protoent)
80
81 static void
82 clone_protoent(struct protoent *dest, struct protoent 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 protoent));
91         
92         if (src->p_name != NULL) {
93                 dest->p_name = strdup(src->p_name);
94                 assert(dest->p_name != NULL);
95         }
96         
97         dest->p_proto = src->p_proto;
98         
99         if (src->p_aliases != NULL) {
100                 aliases_num = 0;
101                 for (cp = src->p_aliases; *cp; ++cp)
102                         ++aliases_num;
103         
104                 dest->p_aliases = (char **)malloc((aliases_num+1) * (sizeof(char *)));
105                 assert(dest->p_aliases != NULL);
106                 memset(dest->p_aliases, 0, (aliases_num+1) * (sizeof(char *)));
107         
108                 for (cp = src->p_aliases; *cp; ++cp) {
109                         dest->p_aliases[cp - src->p_aliases] = strdup(*cp);
110                         assert(dest->p_aliases[cp - src->p_aliases] != NULL);
111                 }
112         }
113 }
114
115 static void 
116 free_protoent(struct protoent *pe)
117 {
118         char **cp;
119         
120         assert(pe != NULL);
121         
122         free(pe->p_name);
123         
124         for (cp = pe->p_aliases; *cp; ++cp)
125                 free(*cp);
126         free(pe->p_aliases);
127 }
128
129 static  int 
130 compare_protoent(struct protoent *pe1, struct protoent *pe2, void *mdata)
131 {
132         char **c1, **c2;
133         
134         if (pe1 == pe2)
135                 return 0;
136         
137         if ((pe1 == NULL) || (pe2 == NULL))
138                 goto errfin;
139         
140         if ((strcmp(pe1->p_name, pe2->p_name) != 0) ||
141                 (pe1->p_proto != pe2->p_proto))
142                         goto errfin;
143         
144         c1 = pe1->p_aliases;
145         c2 = pe2->p_aliases;
146         
147         if ((pe1->p_aliases == NULL) || (pe2->p_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         
159 errfin:
160         if ((debug) && (mdata == NULL)) {
161                 printf("following structures are not equal:\n");
162                 dump_protoent(pe1);
163                 dump_protoent(pe2);
164         }
165
166         return (-1);
167 }
168
169 static void
170 sdump_protoent(struct protoent *pe, char *buffer, size_t buflen)
171 {
172         char **cp;
173         int written;
174         
175         written = snprintf(buffer, buflen, "%s %d",
176                 pe->p_name, pe->p_proto);       
177         buffer += written;
178         if (written > buflen)
179                 return;
180         buflen -= written;
181                         
182         if (pe->p_aliases != NULL) {
183                 if (*(pe->p_aliases) != '\0') {
184                         for (cp = pe->p_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
200 static int
201 protoent_read_snapshot_func(struct protoent *pe, 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(pe, 0, sizeof(struct protoent));
214         while ( (s = strsep(&ps, " ")) != NULL) {
215                 switch (i) {
216                         case 0:
217                                 pe->p_name = strdup(s);
218                                 assert(pe->p_name != NULL);
219                         break;
220
221                         case 1:
222                                 pe->p_proto = (int)strtol(s, &ts, 10);
223                                 if (*ts != '\0') {
224                                         free(pe->p_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(pe->p_name);
254                 memset(pe, 0, sizeof(struct protoent));
255                 return (-1);
256         }
257         
258         sl_add(sl, NULL);
259         pe->p_aliases = sl->sl_str;
260
261         /* NOTE: is it a dirty hack or not? */
262         free(sl);       
263         return (0);
264 }
265
266 static void 
267 dump_protoent(struct protoent *result)
268 {
269         if (result != NULL) {
270                 char buffer[1024];
271                 sdump_protoent(result, buffer, sizeof(buffer));
272                 printf("%s\n", buffer);
273         } else
274                 printf("(null)\n");
275 }
276
277 static int
278 protoent_fill_test_data(struct protoent_test_data *td)
279 {
280         struct protoent *pe;
281                 
282         setprotoent(1);
283         while ((pe = getprotoent()) != NULL) {
284                 if (protoent_test_correctness(pe, NULL) == 0)
285                         TEST_DATA_APPEND(protoent, td, pe);
286                 else
287                         return (-1);
288         }
289         endprotoent();
290         
291         return (0);
292 }
293
294 static int
295 protoent_test_correctness(struct protoent *pe, void *mdata)
296 {
297         if (debug) {
298                 printf("testing correctness with the following data:\n");
299                 dump_protoent(pe);
300         }
301         
302         if (pe == NULL)
303                 goto errfin;
304         
305         if (pe->p_name == NULL)
306                 goto errfin;
307         
308         if (pe->p_proto < 0)
309                 goto errfin;
310         
311         if (pe->p_aliases == NULL)
312                 goto errfin;
313         
314         if (debug)
315                 printf("correct\n");
316         
317         return (0);     
318 errfin:
319         if (debug)
320                 printf("incorrect\n");
321         
322         return (-1);
323 }
324
325 /* protoent_check_ambiguity() is needed when one port+proto 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+proto is 
328  * associated with several ports. We have to check all the protoent structures
329  * to make sure that pe really exists and correct */
330 static int
331 protoent_check_ambiguity(struct protoent_test_data *td, struct protoent *pe)
332 {
333         
334         return (TEST_DATA_FIND(protoent, td, pe, compare_protoent,
335                 NULL) != NULL ? 0 : -1);
336 }
337
338 static int
339 protoent_test_getprotobyname(struct protoent *pe_model, void *mdata)
340 {
341         char **alias;
342         struct protoent *pe;
343                 
344         if (debug) {
345                 printf("testing getprotobyname() with the following data:\n");
346                 dump_protoent(pe_model);
347         }
348
349         pe = getprotobyname(pe_model->p_name);
350         if (protoent_test_correctness(pe, NULL) != 0)
351                 goto errfin;
352         
353         if ((compare_protoent(pe, pe_model, NULL) != 0) &&
354             (protoent_check_ambiguity((struct protoent_test_data *)mdata, pe) 
355             !=0))
356             goto errfin;
357         
358         for (alias = pe_model->p_aliases; *alias; ++alias) {
359                 pe = getprotobyname(*alias);
360                 
361                 if (protoent_test_correctness(pe, NULL) != 0)
362                         goto errfin;
363                 
364                 if ((compare_protoent(pe, pe_model, NULL) != 0) &&
365                     (protoent_check_ambiguity(
366                     (struct protoent_test_data *)mdata, pe) != 0))
367                     goto errfin;
368         }
369         
370         if (debug)
371                 printf("ok\n");
372         return (0);
373         
374 errfin:
375         if (debug)
376                 printf("not ok\n");
377         
378         return (-1);
379 }
380
381 static int
382 protoent_test_getprotobynumber(struct protoent *pe_model, void *mdata)
383 {
384         struct protoent *pe;
385                 
386         if (debug) {
387                 printf("testing getprotobyport() with the following data...\n");
388                 dump_protoent(pe_model);
389         }       
390         
391         pe = getprotobynumber(pe_model->p_proto);
392         if ((protoent_test_correctness(pe, NULL) != 0) || 
393             ((compare_protoent(pe, pe_model, NULL) != 0) &&
394             (protoent_check_ambiguity((struct protoent_test_data *)mdata, pe)
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
406 static int 
407 protoent_test_getprotoent(struct protoent *pe, void *mdata)
408 {
409         /* Only correctness can be checked when doing 1-pass test for
410          * getprotoent(). */
411         return (protoent_test_correctness(pe, NULL));
412 }
413
414 static void
415 usage(void)
416 {
417         (void)fprintf(stderr,
418             "Usage: %s -nve2 [-d] [-s <file>]\n",
419             getprogname());
420         exit(1);
421 }
422
423 int
424 main(int argc, char **argv)
425 {
426         struct protoent_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_GETPROTOBYNAME;
442                         break;
443                 case 'v':
444                         method = TEST_GETPROTOBYNUMBER;
445                         break;
446                 case 'e':
447                         method = TEST_GETPROTOENT;
448                         break;
449                 case '2':
450                         method = TEST_GETPROTOENT_2PASS;
451                         break;
452                 case 's':
453                         snapshot_file = strdup(optarg);
454                         break;
455                 default:
456                         usage();
457                 }
458         
459         TEST_DATA_INIT(protoent, &td, clone_protoent, free_protoent);
460         TEST_DATA_INIT(protoent, &td_snap, clone_protoent, free_protoent);
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(protoent, snapshot_file,
480                                 &td_snap, protoent_read_snapshot_func);
481                 }
482         }
483                 
484         rv = protoent_fill_test_data(&td);
485         if (rv == -1)
486                 return (-1);
487         switch (method) {
488         case TEST_GETPROTOBYNAME:
489                 if (snapshot_file == NULL)
490                         rv = DO_1PASS_TEST(protoent, &td,
491                                 protoent_test_getprotobyname, (void *)&td);
492                 else
493                         rv = DO_1PASS_TEST(protoent, &td_snap, 
494                                 protoent_test_getprotobyname, (void *)&td_snap);
495                 break;
496         case TEST_GETPROTOBYNUMBER:
497                 if (snapshot_file == NULL)
498                         rv = DO_1PASS_TEST(protoent, &td,
499                                 protoent_test_getprotobynumber, (void *)&td);
500                 else
501                         rv = DO_1PASS_TEST(protoent, &td_snap, 
502                                 protoent_test_getprotobynumber, (void *)&td_snap);
503                 break;
504         case TEST_GETPROTOENT:
505                 if (snapshot_file == NULL)
506                         rv = DO_1PASS_TEST(protoent, &td, 
507                                 protoent_test_getprotoent, (void *)&td);
508                 else
509                         rv = DO_2PASS_TEST(protoent, &td, &td_snap,
510                                 compare_protoent, NULL);
511                 break;
512         case TEST_GETPROTOENT_2PASS:
513                         TEST_DATA_INIT(protoent, &td_2pass, clone_protoent,
514                                 free_protoent);
515                         rv = protoent_fill_test_data(&td_2pass);
516                         if (rv != -1)
517                                 rv = DO_2PASS_TEST(protoent, &td, &td_2pass,
518                                         compare_protoent, NULL);
519                         TEST_DATA_DESTROY(protoent, &td_2pass);
520                 break;
521         case TEST_BUILD_SNAPSHOT:
522                 if (snapshot_file != NULL)
523                     rv = TEST_SNAPSHOT_FILE_WRITE(protoent, snapshot_file, &td, 
524                         sdump_protoent);
525                 break;
526         default:
527                 rv = 0;
528                 break;
529         };
530
531 fin:
532         TEST_DATA_DESTROY(protoent, &td_snap);
533         TEST_DATA_DESTROY(protoent, &td);
534         free(snapshot_file);    
535         return (rv);
536 }