2 * Copyright (c) 1995 - 2001 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
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.
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
43 #include <sys/types.h>
53 #define MAXPATHLEN PATH_MAX
55 #define MAXPATHLEN 4096
61 static int verbose_flag;
62 static FILE *verbose_fp = NULL;
65 initial_string(char **buf, size_t * size, size_t new_size)
67 char *tmp = malloc(new_size);
77 expand_string(char **buf, size_t * size, size_t new_size)
79 char *tmp = realloc(*buf, new_size);
89 * Verify that the dynamically allocated string `buf' of length
90 * `size', has room for `len' bytes. Returns -1 if realloc fails.
94 guarantee_room(char **buf, size_t * size, size_t len)
99 return expand_string(buf, size, min(*size * 2, len));
103 getcwd_classic(char *buf, size_t size)
106 struct stat root_sb, dot_sb, dotdot_sb;
109 char slash_dot_dot[] = "/..";
114 if (initial_string(&work_string, &work_length, MAXPATHLEN) < 0)
119 if (initial_string(&buf, &size, MAXPATHLEN) < 0) {
125 endp = curp = buf + size - 1;
127 if (lstat(".", &dot_sb) < 0)
129 if (lstat("/", &root_sb) < 0)
131 strcpy(work_string, "..");
132 fprintf(verbose_fp, "\".\" is (%u, %u), \"/\" is (%u, %u)\n",
133 (unsigned)dot_sb.st_dev, (unsigned)dot_sb.st_ino,
134 (unsigned)root_sb.st_dev, (unsigned)root_sb.st_ino);
136 while (dot_sb.st_dev != root_sb.st_dev || dot_sb.st_ino != root_sb.st_ino) {
140 int pattern_len = strlen(work_string);
142 if (lstat(work_string, &dotdot_sb) < 0)
144 fprintf(verbose_fp, "\"..\" is (%u, %u)\n",
145 (unsigned)dotdot_sb.st_dev, (unsigned)dotdot_sb.st_ino);
146 if (dot_sb.st_dev != dotdot_sb.st_dev)
148 dir = opendir(work_string);
151 while ((dp = readdir(dir)) != NULL) {
152 size_t name_len = strlen(dp->d_name);
158 (&work_string, &work_length,
159 pattern_len + name_len + 2) < 0) {
163 strcat(work_string, "/");
164 strcat(work_string, dp->d_name);
166 if (lstat(work_string, &sb) < 0) {
169 if (sb.st_dev == dot_sb.st_dev && sb.st_ino == dot_sb.st_ino) {
170 fprintf(verbose_fp, "\"%s\" found\n", work_string);
173 work_string[pattern_len] = '\0';
174 } else if (dp->d_ino == dot_sb.st_ino) {
175 fprintf(verbose_fp, "\"%s\" found\n", dp->d_name);
180 while (buf + name_len >= curp) {
187 old_len = endp - curp + 1;
188 if (expand_string(&buf, &size, size * 2) < 0)
190 memmove(buf + size - old_len, buf + size / 2 - old_len,
192 endp = buf + size - 1;
193 curp = endp - old_len + 1;
195 memcpy(curp - name_len, dp->d_name, name_len);
196 curp[-(name_len + 1)] = '/';
197 curp -= name_len + 1;
209 (&work_string, &work_length,
210 pattern_len + strlen(slash_dot_dot) + 1) < 0)
212 strcat(work_string, slash_dot_dot);
215 while (buf >= curp) {
220 if (expand_string(&buf, &size, size * 2) < 0)
226 memmove(buf, curp, endp - curp + 1);
242 getcwd_proc(char *buf, size_t size)
248 if (initial_string(&buf, &size, MAXPATHLEN) < 0)
250 } else if (size <= 1) {
258 ret = readlink("/proc/self/cwd", buf, size);
265 if (buf[ret - 1] != '\0' && ret >= size) {
270 if (expand_string(&buf, &size, size * 2) < 0)
273 if (buf[ret - 1] != '\0')
287 test_1(char *(*func) (char *, size_t), const char *func_name, int init_size)
290 char buf[2048], *buf2, buf3[4711];
295 if (getcwd(real_buf, sizeof(real_buf)) == NULL) {
296 fprintf(verbose_fp, "getcwd(buf, %u) failed\n",
297 (unsigned)sizeof(real_buf));
300 if (func(buf, sizeof(buf)) == NULL) {
301 fprintf(verbose_fp, "%s(buf, %u) failed\n", func_name,
302 (unsigned)sizeof(buf));
305 fprintf(verbose_fp, "first *%s*\n", buf);
306 if (strcmp(real_buf, buf) != 0) {
307 fprintf(verbose_fp, "first comparison failed: *%s* != *%s*\n",
313 buf2 = func(NULL, 0);
315 fprintf(verbose_fp, "%s(NULL, 0) failed\n", func_name);
318 fprintf(verbose_fp, "second *%s*\n", buf2);
319 if (strcmp(real_buf, buf2) != 0) {
320 fprintf(verbose_fp, "second comparison failed: *%s* != *%s*\n",
327 for (i = init_size; i < sizeof(buf3); ++i) {
328 memset(buf3, '\x01', sizeof(buf3));
329 if (func(buf3, i) == NULL) {
330 if (errno != ERANGE) {
331 fprintf(verbose_fp, "%s(buf,%u) call failed\n", func_name, i);
338 for (j = i; j < sizeof(buf3); ++j)
339 if (buf3[j] != '\x01') {
340 fprintf(verbose_fp, "buffer was overwritten at %d\n", j);
349 fprintf(verbose_fp, "third *%s*\n", buf3);
350 if (strcmp(real_buf, buf3) != 0) {
351 fprintf(verbose_fp, "third comparison failed: *%s* != *%s*\n",
354 } else if (strlen(buf3) + 1 != i && strlen(buf3) + 1 >= init_size) {
355 fprintf(verbose_fp, "wrong len in third call: %d != %d\n",
356 (unsigned)strlen(buf3) + 1, i);
367 test_it(char *(*func) (char *, size_t), const char *name, int init_size)
371 fprintf(verbose_fp, "testing %s (initial size %d)\n", name, init_size);
372 ret = test_1(func, name, init_size);
374 fprintf(verbose_fp, "FAILED!\n");
376 fprintf(verbose_fp, "passed\n");
381 #include <linux/unistd.h>
386 #define __NR_sys_getcwd __NR_getcwd
389 _syscall2(int, sys_getcwd, char *, buf, size_t, size)
391 static char *getcwd_syscall(char *buf, size_t size)
397 if (initial_string(&buf, &size, MAXPATHLEN) < 0)
404 ret = sys_getcwd(buf, size);
407 else if (errno == ERANGE) {
410 if (expand_string(&buf, &size, size * 2) < 0)
419 static int help_flag;
421 static struct agetargs args[] = {
422 {"verbose", 'v', aarg_flag, &verbose_flag, "verbose", NULL},
423 {"help", 0, aarg_flag, &help_flag, NULL, NULL},
424 {NULL, 0, aarg_end, NULL, NULL, NULL}
430 aarg_printusage(args, NULL, "", AARG_GNUSTYLE);
434 main(int argc, char **argv)
440 verbose_flag = getenv("VERBOSE") != NULL;
442 if (agetarg(args, argc, argv, &optind, AARG_GNUSTYLE))
453 verbose_fp = fdopen(4, "w");
454 if (verbose_fp == NULL) {
455 verbose_fp = fopen("/dev/null", "w");
456 if (verbose_fp == NULL)
460 ret += test_it(getcwd, "getcwd", 3);
462 ret += test_it(getcwd_syscall, "getcwd_syscall", 3);
464 ret += test_it(getcwd_classic, "getcwd_classic", 0);
466 ret += test_it(getcwd_proc, "getcwd_proc", 0);