Remove 'grp' and merge into 'nss' and 'posix'
[platform/upstream/glibc.git] / stdlib / test-canon.c
1 /* Test program for returning the canonical absolute name of a given file.
2    Copyright (C) 1996-2023 Free Software Foundation, Inc.
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 /* This file must be run from within a directory called "stdlib".  */
20
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <sys/param.h>
28 #include <sys/stat.h>
29
30 #include <support/xunistd.h>
31
32 /* Prototype for our test function.  */
33 extern int do_test (int argc, char *argv[]);
34 #include <test-skeleton.c>
35
36 #ifndef PATH_MAX
37 # define PATH_MAX 4096
38 #endif
39 static char     cwd[PATH_MAX];
40 static size_t   cwd_len;
41
42 struct {
43   const char *  name;
44   const char *  value;
45 } symlinks[] = {
46   {"SYMLINK_LOOP",      "SYMLINK_LOOP"},
47   {"SYMLINK_1",         "."},
48   {"SYMLINK_2",         "//////./../../etc"},
49   {"SYMLINK_3",         "SYMLINK_1"},
50   {"SYMLINK_4",         "SYMLINK_2"},
51   {"SYMLINK_5",         "doesNotExist"},
52 };
53
54 struct {
55   const char * in, * out, * resolved;
56   int error;
57 } tests[] = {
58   /*  0 */
59   {"/",                                 "/"},
60   {"/////////////////////////////////", "/"},
61   {"/.././.././.././..///",             "/"},
62   {"/etc",                              "/etc"},
63   {"/etc/../etc",                       "/etc"},
64   /*  5 */
65   {"/doesNotExist/../etc",              0, "/doesNotExist", ENOENT},
66   {"./././././././././.",               "."},
67   {"/etc/.//doesNotExist",              0, "/etc/doesNotExist", ENOENT},
68   {"./doesExist",                       "./doesExist"},
69   {"./doesExist/",                      "./doesExist"},
70   /* 10 */
71   {"./doesExist/../doesExist",          "./doesExist"},
72   {"foobar",                            0, "./foobar", ENOENT},
73   {".",                                 "."},
74   {"./foobar",                          0, "./foobar", ENOENT},
75   {"SYMLINK_LOOP",                      0, "./SYMLINK_LOOP", ELOOP},
76   /* 15 */
77   {"./SYMLINK_LOOP",                    0, "./SYMLINK_LOOP", ELOOP},
78   {"SYMLINK_1",                         "."},
79   {"SYMLINK_1/foobar",                  0, "./foobar", ENOENT},
80   {"SYMLINK_2",                         "/etc"},
81   {"SYMLINK_3",                         "."},
82   /* 20 */
83   {"SYMLINK_4",                         "/etc"},
84   {"../stdlib/SYMLINK_1",               "."},
85   {"../stdlib/SYMLINK_2",               "/etc"},
86   {"../stdlib/SYMLINK_3",               "."},
87   {"../stdlib/SYMLINK_4",               "/etc"},
88   /* 25 */
89   {"./SYMLINK_5",                       0, "./doesNotExist", ENOENT},
90   {"SYMLINK_5",                         0, "./doesNotExist", ENOENT},
91   {"SYMLINK_5/foobar",                  0, "./doesNotExist", ENOENT},
92   {"doesExist/../../stdlib/doesExist",  "./doesExist"},
93   {"doesExist/.././../stdlib/.",        "."},
94   /* 30 */
95   {"./doesExist/someFile/",             0, "./doesExist/someFile", ENOTDIR},
96   {"./doesExist/someFile/..",           0, "./doesExist/someFile", ENOTDIR},
97 };
98
99
100 static int
101 check_path (const char * result, const char * expected)
102 {
103   int good;
104
105   if (!result)
106     return (expected == NULL);
107
108   if (!expected)
109     return 0;
110
111   if (expected[0] == '.' && (expected[1] == '/' || expected[1] == '\0'))
112     good = (strncmp (result, cwd, cwd_len) == 0
113             && strcmp (result + cwd_len, expected + 1) == 0);
114   else
115     good = (strcmp (expected, result) == 0);
116
117   return good;
118 }
119
120
121 int
122 do_test (int argc, char ** argv)
123 {
124   char * result;
125   int i, errors = 0;
126   char buf[PATH_MAX];
127
128   if (getcwd (cwd, sizeof (buf)))
129     cwd_len = strlen (cwd);
130   else
131     {
132       printf ("%s: current working directory couldn't be retrieved\n", argv[0]);
133       ++errors;
134     }
135
136   errno = 0;
137   if (realpath (NULL, buf) != NULL || errno != EINVAL)
138     {
139       printf ("%s: expected return value NULL and errno set to EINVAL"
140               " for realpath(NULL,...)\n", argv[0]);
141       ++errors;
142     }
143
144 #if 0
145   /* This is now allowed.  The test is invalid.  */
146   errno = 0;
147   if (realpath ("/", NULL) != NULL || errno != EINVAL)
148     {
149       printf ("%s: expected return value NULL and errno set to EINVAL"
150               " for realpath(...,NULL)\n", argv[0]);
151       ++errors;
152     }
153 #endif
154
155   errno = 0;
156   if (realpath ("", buf) != NULL || errno != ENOENT)
157     {
158       printf ("%s: expected return value NULL and set errno to ENOENT"
159               " for realpath(\"\",...)\n", argv[0]);
160       ++errors;
161     }
162
163   for (i = 0; i < (int) (sizeof (symlinks) / sizeof (symlinks[0])); ++i)
164     xsymlink (symlinks[i].value, symlinks[i].name);
165
166   int has_dir = mkdir ("doesExist", 0777) == 0;
167
168   int fd = has_dir ? creat ("doesExist/someFile", 0777) : -1;
169
170   for (i = 0; i < (int) (sizeof (tests) / sizeof (tests[0])); ++i)
171     {
172       buf[0] = '\0';
173       result = realpath (tests[i].in, buf);
174
175       if (!check_path (result, tests[i].out))
176         {
177           printf ("%s: flunked test %d (expected `%s', got `%s')\n",
178                   argv[0], i, tests[i].out ? tests[i].out : "NULL",
179                   result ? result : "NULL");
180           ++errors;
181           continue;
182         }
183
184       /* Verify buf contents if the call succeeded or failed with ENOENT.  */
185       if ((result != NULL || errno == ENOENT)
186           && !check_path (buf, tests[i].out ? tests[i].out : tests[i].resolved))
187         {
188           printf ("%s: flunked test %d (expected resolved `%s', got `%s')\n",
189                   argv[0], i, tests[i].out ? tests[i].out : tests[i].resolved,
190                   buf);
191           ++errors;
192           continue;
193         }
194
195       if (!tests[i].out && errno != tests[i].error)
196         {
197           printf ("%s: flunked test %d (expected errno %d, got %d)\n",
198                   argv[0], i, tests[i].error, errno);
199           ++errors;
200           continue;
201         }
202
203       char *result2 = realpath (tests[i].in, NULL);
204       if ((result2 == NULL && result != NULL)
205           || (result2 != NULL && strcmp (result, result2) != 0))
206         {
207           printf ("\
208 %s: realpath(..., NULL) produced different result than realpath(..., buf): '%s' vs '%s'\n",
209                   argv[0], result2, result);
210           ++errors;
211         }
212       free (result2);
213     }
214
215   if (!getcwd (buf, sizeof (buf)))
216     {
217       printf ("%s: current working directory couldn't be retrieved\n", argv[0]);
218       ++errors;
219     }
220
221   if (strcmp (buf, cwd))
222     {
223       printf ("%s: current working directory changed from %s to %s\n",
224               argv[0], cwd, buf);
225       ++errors;
226     }
227
228   if (fd >= 0)
229     {
230       close (fd);
231       unlink ("doesExist/someFile");
232     }
233
234   if (has_dir)
235     rmdir ("doesExist");
236
237   for (i = 0; i < (int) (sizeof (symlinks) / sizeof (symlinks[0])); ++i)
238     unlink (symlinks[i].name);
239
240   if (errors != 0)
241     {
242       printf ("%d errors.\n", errors);
243       return EXIT_FAILURE;
244     }
245
246   puts ("No errors.");
247   return EXIT_SUCCESS;
248 }