xref: /openbsd-src/regress/sys/kern/realpath/realpathtest.c (revision 083f366943f7a82b707b57acbfd98ac3ebb3dd8a)
1 /*	$OpenBSD: realpathtest.c,v 1.7 2019/05/29 13:53:59 beck Exp $ */
2 
3 /*
4  * Copyright (c) 2019 Bob Beck <beck@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 
22 #include <stdio.h>
23 #include <limits.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <err.h>
28 #include <errno.h>
29 
30 /*
31  * Reference copy of userland realpath(3) implementation.
32  * Assumed to be correct.
33  */
34 extern char *realpath3(const char *pathname, char *resolved);
35 
36 struct rp_compare {
37 	char * resolv2;
38 	char * resolv3;
39 	char * r2;
40 	char * r3;
41 	int e2;
42 	int e3;
43 };
44 
45 static struct rp_compare
46 rpcompare(const char *pathname, char *resolv2,
47     char *resolv3) {
48 	struct rp_compare ret = {0};
49 
50 	errno = 0;
51 	ret.r2 = realpath(pathname, resolv2);
52 	ret.e2 = errno;
53 	ret.resolv2 = resolv2;
54 	errno = 0;
55 	ret.r3 = realpath3(pathname, resolv3);
56 	ret.e3 = errno;
57 	ret.resolv3 = resolv3;
58 	errno = 0;
59 	return ret;
60 }
61 
62 #define RP_SHOULD_SUCCEED(A, B, C) do {					\
63 	struct rp_compare rc = rpcompare(A, B, C);			\
64 	if (rc.r2 == NULL)  {						\
65 		errno = rc.e2;						\
66 		err(1, "%s:%d - realpath of '%s' failed", __FILE__, 	\
67 		    __LINE__, (A));					\
68 	} 								\
69 	if (rc.r3 == NULL)  {						\
70 		errno = rc.e3;						\
71 		err(1, "%s:%d - realpath3 of '%s' failed", __FILE__,	\
72 		    __LINE__, (A));					\
73 	}								\
74 	if (strcmp(rc.r2, rc.r3) != 0)					\
75 		errx(1, "%s:%d - realpath of '%s' result '%s',"		\
76 		    "expected '%s", __FILE__, __LINE__, (A), rc.r2,	\
77 		    rc.r3);						\
78 } while(0);
79 
80 #define RP_SHOULD_FAIL(A, B, C) do {					\
81 	struct rp_compare rc = rpcompare(A, B, C); 			\
82 	if (rc.r2 != NULL) 						\
83 		errx(1, "%s:%d - realpath of '%s' should have failed,"	\
84 		    "returned '%s'", __FILE__, __LINE__, (A), rc.r2); 	\
85 	if (rc.r3 != NULL) 						\
86 		errx(1, "%s:%d - realpath3 of '%s' should have failed,"	\
87 		    "returned '%s'", __FILE__, __LINE__, (A), rc.r3); 	\
88 	if (rc.e2 != rc.e3) 						\
89 		errx(1, "%s:%d - realpath of '%s' errno %d does not "	\
90 		    "match realpath3 errno %d", __FILE__, __LINE__, (A),\
91 		    rc.e2, rc.e3 );					\
92 } while(0);
93 
94 int
95 main(int argc, char *argv[])
96 {
97 	int i, j;
98 	char big[PATH_MAX+PATH_MAX];
99 	char r2[PATH_MAX];
100 	char r3[PATH_MAX];
101 
102 	/* some basics */
103 	RP_SHOULD_SUCCEED("/bin/c++", NULL, NULL);
104 	RP_SHOULD_SUCCEED("/tmp", NULL, NULL);
105 	RP_SHOULD_SUCCEED("/tmp/noreallydoesntexist", NULL, NULL);
106 	RP_SHOULD_FAIL("/tmp/noreallydoesntexist/stillnope", NULL, NULL);
107 	RP_SHOULD_SUCCEED("/bin", NULL, NULL);
108 	RP_SHOULD_SUCCEED("/bin/herp", NULL, NULL);
109 	RP_SHOULD_SUCCEED("////usr/bin", NULL, NULL);
110 	RP_SHOULD_SUCCEED("//.//usr/bin/.././../herp", r2, r3);
111 	RP_SHOULD_SUCCEED("/usr/include/machine/setjmp.h", r2, r3);
112 	RP_SHOULD_FAIL("//.//usr/bin/.././../herp/derp", r2, r3);
113 	RP_SHOULD_FAIL("/../.../usr/bin", r2, r3);
114 	RP_SHOULD_FAIL("/bsd/herp", r2, r3);
115 
116 	/* relative paths */
117 	if (mkdir("hoobla", 0755) == -1) {
118 		if (errno != EEXIST)
119 			err(1, "mkdir");
120 	}
121 	RP_SHOULD_SUCCEED("hoobla", r2, r3);
122 	RP_SHOULD_SUCCEED("hoobla/porkrind", r2, r3); /* XXX posix */
123 	RP_SHOULD_FAIL("hoobla/porkrind/peepee", r2, r3);
124 
125 	/* total size */
126 	memset(big, '/', PATH_MAX + 1);
127 	RP_SHOULD_FAIL(big, r2, r3);
128 
129 	/* component size */
130 	memset(big, 'a', PATH_MAX + 1);
131 	big[0] = '/';
132 	big[NAME_MAX+1] = '\0';
133 	RP_SHOULD_SUCCEED(big, r2, r3);
134 	memset(big, 'a', PATH_MAX + 1);
135 	big[0] = '/';
136 	big[NAME_MAX+2] = '\0';
137 	RP_SHOULD_FAIL(big, r2, r3);
138 
139 	/* long relatives back to root */
140 	for (i = 0; i < (PATH_MAX - 4); i += 3) {
141 		big[i] = '.';
142 		big[i+1] = '.';
143 		big[i+2] = '/';
144 	}
145 	i-= 3;
146 	strlcpy(big+i, "bsd", 4);
147 	RP_SHOULD_SUCCEED(big, r2, r3);
148 
149 	for (i = 0; i < (PATH_MAX - 5); i += 3) {
150 		big[i] = '.';
151 		big[i+1] = '.';
152 		big[i+2] = '/';
153 	}
154 	i-= 3;
155 	strlcpy(big+i, "bsd/", 5);
156 	RP_SHOULD_SUCCEED(big, r2, r3);	/* XXX This is wrong by posix */
157 
158 	for (i = 0; i < (PATH_MAX - 5); i += 3) {
159 		big[i] = '.';
160 		big[i+1] = '.';
161 		big[i+2] = '/';
162 	}
163 	i-= 3;
164 	strlcpy(big+i, "derp", 5);
165 	RP_SHOULD_SUCCEED(big, r2, r3);	/* XXX this is wrong by posix */
166 
167 	for (i = 0; i < (PATH_MAX - 6); i += 3) {
168 		big[i] = '.';
169 		big[i+1] = '.';
170 		big[i+2] = '/';
171 	}
172 	i-= 3;
173 	strlcpy(big+i, "derp/", 6);
174 	RP_SHOULD_FAIL(big, r2, r3);	/* XXX this is correct by posix */
175 
176 	for (i = 0; i < (PATH_MAX - 4); i += 3) {
177 		big[i] = '.';
178 		big[i+1] = '.';
179 		big[i+2] = '/';
180 	}
181 	i-= 3;
182 	strlcpy(big+i, "xxx", 4);
183 	RP_SHOULD_SUCCEED(big, r2, r3);
184 
185 	for (i = 0; i < (PATH_MAX - 8); i += 3) {
186 		big[i] = '.';
187 		big[i+1] = '.';
188 		big[i+2] = '/';
189 	}
190 	i-= 3;
191 	strlcpy(big+i, "xxx/../", 8);
192 	RP_SHOULD_FAIL(big, r2, r3);
193 
194 	return (0);
195 }
196