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
60 static int verbose_flag
;
61 static FILE *verbose_fp
= NULL
;
64 initial_string(char **buf
, size_t * size
, size_t new_size
)
66 char *tmp
= malloc(new_size
);
76 expand_string(char **buf
, size_t * size
, size_t new_size
)
78 char *tmp
= realloc(*buf
, new_size
);
88 * Verify that the dynamically allocated string `buf' of length
89 * `size', has room for `len' bytes. Returns -1 if realloc fails.
93 guarantee_room(char **buf
, size_t * size
, size_t len
)
98 return expand_string(buf
, size
, min(*size
* 2, len
));
102 getcwd_classic(char *buf
, size_t size
)
105 struct stat root_sb
, dot_sb
, dotdot_sb
;
108 char slash_dot_dot
[] = "/..";
113 if (initial_string(&work_string
, &work_length
, MAXPATHLEN
) < 0)
118 if (initial_string(&buf
, &size
, MAXPATHLEN
) < 0) {
124 endp
= curp
= buf
+ size
- 1;
126 if (lstat(".", &dot_sb
) < 0)
128 if (lstat("/", &root_sb
) < 0)
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
);
135 while (dot_sb
.st_dev
!= root_sb
.st_dev
|| dot_sb
.st_ino
!= root_sb
.st_ino
) {
139 int pattern_len
= strlen(work_string
);
141 if (lstat(work_string
, &dotdot_sb
) < 0)
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
)
147 dir
= opendir(work_string
);
150 while ((dp
= readdir(dir
)) != NULL
) {
151 size_t name_len
= strlen(dp
->d_name
);
157 (&work_string
, &work_length
,
158 pattern_len
+ name_len
+ 2) < 0) {
162 strcat(work_string
, "/");
163 strcat(work_string
, dp
->d_name
);
165 if (lstat(work_string
, &sb
) < 0) {
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
);
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
);
179 while (buf
+ name_len
>= curp
) {
186 old_len
= endp
- curp
+ 1;
187 if (expand_string(&buf
, &size
, size
* 2) < 0)
189 memmove(buf
+ size
- old_len
, buf
+ size
/ 2 - old_len
,
191 endp
= buf
+ size
- 1;
192 curp
= endp
- old_len
+ 1;
194 memcpy(curp
- name_len
, dp
->d_name
, name_len
);
195 curp
[-(name_len
+ 1)] = '/';
196 curp
-= name_len
+ 1;
208 (&work_string
, &work_length
,
209 pattern_len
+ strlen(slash_dot_dot
) + 1) < 0)
211 strcat(work_string
, slash_dot_dot
);
214 while (buf
>= curp
) {
219 if (expand_string(&buf
, &size
, size
* 2) < 0)
225 memmove(buf
, curp
, endp
- curp
+ 1);
241 getcwd_proc(char *buf
, size_t size
)
247 if (initial_string(&buf
, &size
, MAXPATHLEN
) < 0)
249 } else if (size
<= 1) {
257 ret
= readlink("/proc/self/cwd", buf
, size
);
264 if (buf
[ret
- 1] != '\0' && ret
>= size
) {
269 if (expand_string(&buf
, &size
, size
* 2) < 0)
272 if (buf
[ret
- 1] != '\0')
286 test_1(char *(*func
) (char *, size_t), const char *func_name
, int init_size
)
289 char buf
[2048], *buf2
, buf3
[4711];
294 if (getcwd(real_buf
, sizeof(real_buf
)) == NULL
) {
295 fprintf(verbose_fp
, "getcwd(buf, %u) failed\n",
296 (unsigned)sizeof(real_buf
));
299 if (func(buf
, sizeof(buf
)) == NULL
) {
300 fprintf(verbose_fp
, "%s(buf, %u) failed\n", func_name
,
301 (unsigned)sizeof(buf
));
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",
312 buf2
= func(NULL
, 0);
314 fprintf(verbose_fp
, "%s(NULL, 0) failed\n", func_name
);
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",
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
);
337 for (j
= i
; j
< sizeof(buf3
); ++j
)
338 if (buf3
[j
] != '\x01') {
339 fprintf(verbose_fp
, "buffer was overwritten at %d\n", j
);
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",
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
);
366 test_it(char *(*func
) (char *, size_t), const char *name
, int init_size
)
370 fprintf(verbose_fp
, "testing %s (initial size %d)\n", name
, init_size
);
371 ret
= test_1(func
, name
, init_size
);
373 fprintf(verbose_fp
, "FAILED!\n");
375 fprintf(verbose_fp
, "passed\n");
380 #include <linux/unistd.h>
385 #define __NR_sys_getcwd __NR_getcwd
388 _syscall2(int, sys_getcwd
, char *, buf
, size_t, size
)
390 static char *getcwd_syscall(char *buf
, size_t size
)
396 if (initial_string(&buf
, &size
, MAXPATHLEN
) < 0)
403 ret
= sys_getcwd(buf
, size
);
406 else if (errno
== ERANGE
) {
409 if (expand_string(&buf
, &size
, size
* 2) < 0)
418 static int help_flag
;
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
}
429 aarg_printusage(args
, NULL
, "", AARG_GNUSTYLE
);
433 main(int argc
, char **argv
)
439 verbose_flag
= getenv("VERBOSE") != NULL
;
441 if (agetarg(args
, argc
, argv
, &optind
, AARG_GNUSTYLE
))
452 verbose_fp
= fdopen(4, "w");
453 if (verbose_fp
== NULL
) {
454 verbose_fp
= fopen("/dev/null", "w");
455 if (verbose_fp
== NULL
)
459 ret
+= test_it(getcwd
, "getcwd", 3);
461 ret
+= test_it(getcwd_syscall
, "getcwd_syscall", 3);
463 ret
+= test_it(getcwd_classic
, "getcwd_classic", 0);
465 ret
+= test_it(getcwd_proc
, "getcwd_proc", 0);