1 /* Test continue and merge NSS actions for getaddrinfo.
2    Copyright The GNU Toolchain Authors.
3    This file is part of the GNU C Library.
4 
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <https://www.gnu.org/licenses/>.  */
18 
19 #include <dlfcn.h>
20 #include <gnu/lib-names.h>
21 #include <nss.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 
26 #include <support/check.h>
27 #include <support/format_nss.h>
28 #include <support/support.h>
29 #include <support/xstdio.h>
30 #include <support/xunistd.h>
31 
32 enum
33 {
34   ACTION_MERGE = 0,
35   ACTION_CONTINUE,
36 };
37 
38 static const char *
family_str(int family)39 family_str (int family)
40 {
41   switch (family)
42     {
43     case AF_UNSPEC:
44       return "AF_UNSPEC";
45     case AF_INET:
46       return "AF_INET";
47     default:
48       __builtin_unreachable ();
49     }
50 }
51 
52 static const char *
action_str(int action)53 action_str (int action)
54 {
55   switch (action)
56     {
57     case ACTION_MERGE:
58       return "merge";
59     case ACTION_CONTINUE:
60       return "continue";
61     default:
62       __builtin_unreachable ();
63     }
64 }
65 
66 static void
do_one_test(int action,int family,bool canon)67 do_one_test (int action, int family, bool canon)
68 {
69   struct addrinfo hints =
70     {
71       .ai_family = family,
72     };
73 
74   struct addrinfo *ai;
75 
76   if (canon)
77     hints.ai_flags = AI_CANONNAME;
78 
79   printf ("***** Testing \"files [SUCCESS=%s] files\" for family %s, %s\n",
80 	  action_str (action), family_str (family),
81 	  canon ? "AI_CANONNAME" : "");
82 
83   int ret = getaddrinfo ("example.org", "80", &hints, &ai);
84 
85   switch (action)
86     {
87     case ACTION_MERGE:
88       if (ret == 0)
89 	{
90 	  char *formatted = support_format_addrinfo (ai, ret);
91 
92 	  printf ("merge unexpectedly succeeded:\n %s\n", formatted);
93 	  support_record_failure ();
94 	  free (formatted);
95 	}
96       else
97 	return;
98     case ACTION_CONTINUE:
99 	{
100 	  char *formatted = support_format_addrinfo (ai, ret);
101 
102 	  /* Verify that the result appears exactly once.  */
103 	  const char *expected = "address: STREAM/TCP 192.0.0.1 80\n"
104 	    "address: DGRAM/UDP 192.0.0.1 80\n"
105 	    "address: RAW/IP 192.0.0.1 80\n";
106 
107 	  const char *contains = strstr (formatted, expected);
108 	  const char *contains2 = NULL;
109 
110 	  if (contains != NULL)
111 	    contains2 = strstr (contains + strlen (expected), expected);
112 
113 	  if (contains == NULL || contains2 != NULL)
114 	    {
115 	      printf ("continue failed:\n%s\n", formatted);
116 	      support_record_failure ();
117 	    }
118 
119 	  free (formatted);
120 	  break;
121 	}
122     default:
123       __builtin_unreachable ();
124     }
125 }
126 
127 static void
do_one_test_set(int action)128 do_one_test_set (int action)
129 {
130   char buf[32];
131 
132   snprintf (buf, sizeof (buf), "files [SUCCESS=%s] files",
133 	    action_str (action));
134   __nss_configure_lookup ("hosts", buf);
135 
136   do_one_test (action, AF_UNSPEC, false);
137   do_one_test (action, AF_INET, false);
138   do_one_test (action, AF_INET, true);
139 }
140 
141 static int
do_test(void)142 do_test (void)
143 {
144   do_one_test_set (ACTION_CONTINUE);
145   do_one_test_set (ACTION_MERGE);
146   return 0;
147 }
148 
149 #include <support/test-driver.c>
150