Import Upstream version 1.8.5
[hcoop/debian/openafs.git] / src / tests / apwd.c
1 /*
2 * Copyright (c) 1995 - 2001 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #ifdef HAVE_CONFIG_H
35 #include <config.h>
36 #endif
37
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <errno.h>
42
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <fcntl.h>
46 #include <unistd.h>
47 #include <dirent.h>
48
49 #include <err.h>
50
51 #ifndef MAXPATHLEN
52 #ifdef PATH_MAX
53 #define MAXPATHLEN PATH_MAX
54 #else
55 #define MAXPATHLEN 4096
56 #endif
57 #endif
58
59
60 static int verbose_flag;
61 static FILE *verbose_fp = NULL;
62
63 static int
64 initial_string(char **buf, size_t * size, size_t new_size)
65 {
66 char *tmp = malloc(new_size);
67
68 if (tmp == NULL)
69 return -1;
70 *buf = tmp;
71 *size = new_size;
72 return 0;
73 }
74
75 static int
76 expand_string(char **buf, size_t * size, size_t new_size)
77 {
78 char *tmp = realloc(*buf, new_size);
79
80 if (tmp == NULL)
81 return -1;
82 *buf = tmp;
83 *size = new_size;
84 return 0;
85 }
86
87 /*
88 * Verify that the dynamically allocated string `buf' of length
89 * `size', has room for `len' bytes. Returns -1 if realloc fails.
90 */
91
92 static int
93 guarantee_room(char **buf, size_t * size, size_t len)
94 {
95 if (*size > len)
96 return 0;
97
98 return expand_string(buf, size, min(*size * 2, len));
99 }
100
101 static char *
102 getcwd_classic(char *buf, size_t size)
103 {
104 int dynamic_buf = 0;
105 struct stat root_sb, dot_sb, dotdot_sb;
106 char *work_string;
107 size_t work_length;
108 char slash_dot_dot[] = "/..";
109 char *curp;
110 char *endp;
111 DIR *dir = NULL;
112
113 if (initial_string(&work_string, &work_length, MAXPATHLEN) < 0)
114 return NULL;
115
116 if (buf == NULL) {
117 dynamic_buf = 1;
118 if (initial_string(&buf, &size, MAXPATHLEN) < 0) {
119 free(work_string);
120 return NULL;
121 }
122 }
123
124 endp = curp = buf + size - 1;
125
126 if (lstat(".", &dot_sb) < 0)
127 goto err_ret;
128 if (lstat("/", &root_sb) < 0)
129 goto err_ret;
130 strcpy(work_string, "..");
131 fprintf(verbose_fp, "\".\" is (%u, %u), \"/\" is (%u, %u)\n",
132 (unsigned)dot_sb.st_dev, (unsigned)dot_sb.st_ino,
133 (unsigned)root_sb.st_dev, (unsigned)root_sb.st_ino);
134
135 while (dot_sb.st_dev != root_sb.st_dev || dot_sb.st_ino != root_sb.st_ino) {
136 struct dirent *dp;
137 int found = 0;
138 int change_dev = 0;
139 int pattern_len = strlen(work_string);
140
141 if (lstat(work_string, &dotdot_sb) < 0)
142 goto err_ret;
143 fprintf(verbose_fp, "\"..\" is (%u, %u)\n",
144 (unsigned)dotdot_sb.st_dev, (unsigned)dotdot_sb.st_ino);
145 if (dot_sb.st_dev != dotdot_sb.st_dev)
146 change_dev = 1;
147 dir = opendir(work_string);
148 if (dir == NULL)
149 goto err_ret;
150 while ((dp = readdir(dir)) != NULL) {
151 size_t name_len = strlen(dp->d_name);
152
153 if (change_dev) {
154 struct stat sb;
155
156 if (guarantee_room
157 (&work_string, &work_length,
158 pattern_len + name_len + 2) < 0) {
159 goto err_ret;
160 }
161
162 strcat(work_string, "/");
163 strcat(work_string, dp->d_name);
164
165 if (lstat(work_string, &sb) < 0) {
166 goto err_ret;
167 }
168 if (sb.st_dev == dot_sb.st_dev && sb.st_ino == dot_sb.st_ino) {
169 fprintf(verbose_fp, "\"%s\" found\n", work_string);
170 found = 1;
171 }
172 work_string[pattern_len] = '\0';
173 } else if (dp->d_ino == dot_sb.st_ino) {
174 fprintf(verbose_fp, "\"%s\" found\n", dp->d_name);
175 found = 1;
176 }
177
178 if (found) {
179 while (buf + name_len >= curp) {
180 size_t old_len;
181
182 if (!dynamic_buf) {
183 errno = ERANGE;
184 goto err_ret;
185 }
186 old_len = endp - curp + 1;
187 if (expand_string(&buf, &size, size * 2) < 0)
188 goto err_ret;
189 memmove(buf + size - old_len, buf + size / 2 - old_len,
190 old_len);
191 endp = buf + size - 1;
192 curp = endp - old_len + 1;
193 }
194 memcpy(curp - name_len, dp->d_name, name_len);
195 curp[-(name_len + 1)] = '/';
196 curp -= name_len + 1;
197 break;
198 }
199 }
200 closedir(dir);
201 dir = NULL;
202
203 if (!found)
204 goto err_ret;
205
206 dot_sb = dotdot_sb;
207 if (guarantee_room
208 (&work_string, &work_length,
209 pattern_len + strlen(slash_dot_dot) + 1) < 0)
210 goto err_ret;
211 strcat(work_string, slash_dot_dot);
212 }
213 if (curp == endp) {
214 while (buf >= curp) {
215 if (!dynamic_buf) {
216 errno = ERANGE;
217 goto err_ret;
218 }
219 if (expand_string(&buf, &size, size * 2) < 0)
220 goto err_ret;
221 }
222 *--curp = '/';
223 }
224 *endp = '\0';
225 memmove(buf, curp, endp - curp + 1);
226 free(work_string);
227 return buf;
228
229 err_ret:
230 if (dir)
231 closedir(dir);
232 if (dynamic_buf)
233 free(buf);
234 free(work_string);
235 return NULL;
236 }
237
238 #if linux
239
240 static char *
241 getcwd_proc(char *buf, size_t size)
242 {
243 int dynamic_buf = 0;
244
245 if (buf == NULL) {
246 dynamic_buf = 1;
247 if (initial_string(&buf, &size, MAXPATHLEN) < 0)
248 return NULL;
249 } else if (size <= 1) {
250 errno = ERANGE;
251 return NULL;
252 }
253
254 for (;;) {
255 int ret;
256
257 ret = readlink("/proc/self/cwd", buf, size);
258 if (ret == -1)
259 goto err_ret;
260 if (buf[0] != '/') {
261 errno = EINVAL;
262 goto err_ret;
263 }
264 if (buf[ret - 1] != '\0' && ret >= size) {
265 if (!dynamic_buf) {
266 errno = ERANGE;
267 goto err_ret;
268 }
269 if (expand_string(&buf, &size, size * 2) < 0)
270 goto err_ret;
271 } else {
272 if (buf[ret - 1] != '\0')
273 buf[ret] = '\0';
274 return buf;
275 }
276 }
277 err_ret:
278 if (dynamic_buf)
279 free(buf);
280 return NULL;
281 }
282
283 #endif /* linux */
284
285 static int
286 test_1(char *(*func) (char *, size_t), const char *func_name, int init_size)
287 {
288 char real_buf[2048];
289 char buf[2048], *buf2, buf3[4711];
290 int i;
291 int ret = 0;
292 int three_done = 1;
293
294 if (getcwd(real_buf, sizeof(real_buf)) == NULL) {
295 fprintf(verbose_fp, "getcwd(buf, %u) failed\n",
296 (unsigned)sizeof(real_buf));
297 ret = 1;
298 }
299 if (func(buf, sizeof(buf)) == NULL) {
300 fprintf(verbose_fp, "%s(buf, %u) failed\n", func_name,
301 (unsigned)sizeof(buf));
302 ret = 1;
303 } else {
304 fprintf(verbose_fp, "first *%s*\n", buf);
305 if (strcmp(real_buf, buf) != 0) {
306 fprintf(verbose_fp, "first comparison failed: *%s* != *%s*\n",
307 real_buf, buf);
308 ret = 1;
309 }
310 }
311
312 buf2 = func(NULL, 0);
313 if (buf2 == NULL) {
314 fprintf(verbose_fp, "%s(NULL, 0) failed\n", func_name);
315 ret = 1;
316 } else {
317 fprintf(verbose_fp, "second *%s*\n", buf2);
318 if (strcmp(real_buf, buf2) != 0) {
319 fprintf(verbose_fp, "second comparison failed: *%s* != *%s*\n",
320 real_buf, buf2);
321 ret = 1;
322 }
323 free(buf2);
324 }
325
326 for (i = init_size; i < sizeof(buf3); ++i) {
327 memset(buf3, '\x01', sizeof(buf3));
328 if (func(buf3, i) == NULL) {
329 if (errno != ERANGE) {
330 fprintf(verbose_fp, "%s(buf,%u) call failed\n", func_name, i);
331 three_done = 0;
332 break;
333 }
334 } else {
335 int j;
336
337 for (j = i; j < sizeof(buf3); ++j)
338 if (buf3[j] != '\x01') {
339 fprintf(verbose_fp, "buffer was overwritten at %d\n", j);
340 three_done = 0;
341 break;
342 }
343 break;
344 }
345 }
346
347 if (three_done) {
348 fprintf(verbose_fp, "third *%s*\n", buf3);
349 if (strcmp(real_buf, buf3) != 0) {
350 fprintf(verbose_fp, "third comparison failed: *%s* != *%s*\n",
351 real_buf, buf3);
352 ret = 1;
353 } else if (strlen(buf3) + 1 != i && strlen(buf3) + 1 >= init_size) {
354 fprintf(verbose_fp, "wrong len in third call: %d != %d\n",
355 (unsigned)strlen(buf3) + 1, i);
356 ret = 1;
357 }
358 } else {
359 ret = 1;
360 }
361
362 return ret;
363 }
364
365 static int
366 test_it(char *(*func) (char *, size_t), const char *name, int init_size)
367 {
368 int ret;
369
370 fprintf(verbose_fp, "testing %s (initial size %d)\n", name, init_size);
371 ret = test_1(func, name, init_size);
372 if (ret)
373 fprintf(verbose_fp, "FAILED!\n");
374 else
375 fprintf(verbose_fp, "passed\n");
376 return ret;
377 }
378
379 #ifdef linux
380 #include <linux/unistd.h>
381 #endif
382
383 #ifdef __NR_getcwd
384
385 #define __NR_sys_getcwd __NR_getcwd
386
387 static
388 _syscall2(int, sys_getcwd, char *, buf, size_t, size)
389
390 static char *getcwd_syscall(char *buf, size_t size)
391 {
392 int dynamic_buf = 0;
393
394 if (buf == NULL) {
395 dynamic_buf = 1;
396 if (initial_string(&buf, &size, MAXPATHLEN) < 0)
397 return NULL;
398 }
399
400 for (;;) {
401 int ret;
402
403 ret = sys_getcwd(buf, size);
404 if (ret >= 0)
405 return buf;
406 else if (errno == ERANGE) {
407 if (!dynamic_buf)
408 return NULL;
409 if (expand_string(&buf, &size, size * 2) < 0)
410 return NULL;
411 } else
412 return NULL;
413 }
414 }
415
416 #endif
417
418 static int help_flag;
419
420 static struct agetargs args[] = {
421 {"verbose", 'v', aarg_flag, &verbose_flag, "verbose", NULL},
422 {"help", 0, aarg_flag, &help_flag, NULL, NULL},
423 {NULL, 0, aarg_end, NULL, NULL, NULL}
424 };
425
426 static void
427 usage(int exit_val)
428 {
429 aarg_printusage(args, NULL, "", AARG_GNUSTYLE);
430 }
431
432 int
433 main(int argc, char **argv)
434 {
435 int ret = 0;
436 int optind = 0;
437
438
439 verbose_flag = getenv("VERBOSE") != NULL;
440
441 if (agetarg(args, argc, argv, &optind, AARG_GNUSTYLE))
442 usage(1);
443
444 argc -= optind;
445 argv += optind;
446
447 if (argc != 0)
448 usage(1);
449 if (help_flag)
450 usage(0);
451
452 verbose_fp = fdopen(4, "w");
453 if (verbose_fp == NULL) {
454 verbose_fp = fopen("/dev/null", "w");
455 if (verbose_fp == NULL)
456 err(1, "fopen");
457 }
458
459 ret += test_it(getcwd, "getcwd", 3);
460 #ifdef __NR_getcwd
461 ret += test_it(getcwd_syscall, "getcwd_syscall", 3);
462 #endif
463 ret += test_it(getcwd_classic, "getcwd_classic", 0);
464 #if linux
465 ret += test_it(getcwd_proc, "getcwd_proc", 0);
466 #endif
467 return ret;
468 }