2 * Copyright (c) 1995 - 2002, 2006 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>
56 static int verbose_flag
;
57 static FILE *verbose_fp
= NULL
;
60 initial_string (char **buf
, size_t *size
, size_t new_size
)
62 char *tmp
= malloc (new_size
);
72 expand_string (char **buf
, size_t *size
, size_t new_size
)
74 char *tmp
= realloc (*buf
, new_size
);
84 * Verify that the dynamically allocated string `buf' of length
85 * `size', has room for `len' bytes. Returns -1 if realloc fails.
89 guarantee_room (char **buf
, size_t *size
, size_t len
)
94 return expand_string (buf
, size
, min(*size
* 2, len
));
98 getcwd_classic (char *buf
, size_t size
)
101 struct stat root_sb
, dot_sb
, dotdot_sb
;
104 char slash_dot_dot
[] = "/..";
109 if (initial_string (&work_string
, &work_length
, MAXPATHLEN
) < 0)
114 if (initial_string (&buf
, &size
, MAXPATHLEN
) < 0) {
120 endp
= curp
= buf
+ size
- 1;
122 if (lstat (".", &dot_sb
) < 0)
124 if (lstat ("/", &root_sb
) < 0)
126 strcpy (work_string
, "..");
127 fprintf (verbose_fp
, "\".\" is (%u, %u), \"/\" is (%u, %u)\n",
128 (unsigned)dot_sb
.st_dev
, (unsigned)dot_sb
.st_ino
,
129 (unsigned)root_sb
.st_dev
, (unsigned)root_sb
.st_ino
);
131 while (dot_sb
.st_dev
!= root_sb
.st_dev
132 || dot_sb
.st_ino
!= root_sb
.st_ino
) {
136 int pattern_len
= strlen (work_string
);
138 if (lstat (work_string
, &dotdot_sb
) < 0)
140 fprintf (verbose_fp
, "\"..\" is (%u, %u)\n",
141 (unsigned)dotdot_sb
.st_dev
, (unsigned)dotdot_sb
.st_ino
);
142 if (dot_sb
.st_dev
!= dotdot_sb
.st_dev
)
144 dir
= opendir (work_string
);
147 while ((dp
= readdir (dir
)) != NULL
) {
148 size_t name_len
= strlen (dp
->d_name
);
153 if (guarantee_room (&work_string
, &work_length
,
154 pattern_len
+ name_len
+ 2) < 0) {
158 strcat (work_string
, "/");
159 strcat (work_string
, dp
->d_name
);
161 if (lstat (work_string
, &sb
) < 0) {
164 if (sb
.st_dev
== dot_sb
.st_dev
165 && sb
.st_ino
== dot_sb
.st_ino
) {
166 fprintf (verbose_fp
, "\"%s\" found\n", work_string
);
169 work_string
[pattern_len
] = '\0';
170 } else if (dp
->d_ino
== dot_sb
.st_ino
) {
171 fprintf (verbose_fp
, "\"%s\" found\n", dp
->d_name
);
176 while (buf
+ name_len
>= curp
) {
183 old_len
= endp
- curp
+ 1;
184 if (expand_string (&buf
, &size
, size
* 2) < 0)
186 memmove (buf
+ size
- old_len
,
187 buf
+ size
/ 2 - old_len
,
189 endp
= buf
+ size
- 1;
190 curp
= endp
- old_len
+ 1;
192 memcpy (curp
- name_len
, dp
->d_name
, name_len
);
193 curp
[-(name_len
+ 1)] = '/';
194 curp
-= name_len
+ 1;
205 if (guarantee_room (&work_string
, &work_length
,
206 pattern_len
+ strlen(slash_dot_dot
) + 1) < 0)
208 strcat (work_string
, slash_dot_dot
);
211 while (buf
>= curp
) {
216 if (expand_string (&buf
, &size
, size
* 2) < 0)
222 memmove (buf
, curp
, endp
- curp
+ 1);
238 getcwd_proc (char *buf
, size_t size
)
244 if (initial_string (&buf
, &size
, MAXPATHLEN
) < 0)
246 } else if (size
<= 1) {
254 ret
= readlink ("/proc/self/cwd", buf
, size
- 1);
262 if (buf
[ret
-1] != '\0' && ret
>= size
) {
267 if (expand_string (&buf
, &size
, size
* 2) < 0)
270 if (buf
[ret
- 1] != '\0')
284 test_1(char *(*func
)(char *, size_t), const char *func_name
, int init_size
)
287 char buf
[2048], buf3
[4711];
292 if (getcwd (real_buf
, sizeof(real_buf
)) == NULL
) {
293 fprintf (verbose_fp
, "getcwd(buf, %u) failed\n",
294 (unsigned)sizeof(real_buf
));
297 if (func (buf
, sizeof(buf
)) == NULL
) {
298 fprintf (verbose_fp
, "%s(buf, %u) failed\n", func_name
,
299 (unsigned)sizeof(buf
));
302 fprintf (verbose_fp
, "first *%s*\n", buf
);
303 if (strcmp (real_buf
, buf
) != 0) {
304 fprintf (verbose_fp
, "first comparison failed: *%s* != *%s*\n",
310 for (i
= init_size
; i
< sizeof(buf3
); ++i
) {
311 memset (buf3
, '\x01', sizeof(buf3
));
312 if (func (buf3
, i
) == NULL
) {
313 if (errno
!= ERANGE
) {
314 fprintf (verbose_fp
, "%s(buf,%u) call failed\n", func_name
, i
);
321 for (j
= i
; j
< sizeof(buf3
); ++j
)
322 if (buf3
[j
] != '\x01') {
323 fprintf (verbose_fp
, "buffer was overwritten at %d\n", j
);
332 fprintf (verbose_fp
, "third *%s*\n", buf3
);
333 if (strcmp (real_buf
, buf3
) != 0) {
334 fprintf (verbose_fp
, "third comparison failed: *%s* != *%s*\n",
337 } else if (strlen (buf3
) + 1 != i
338 && strlen (buf3
) + 1 >= init_size
) {
339 fprintf (verbose_fp
, "wrong len in third call: %d != %d\n",
340 (unsigned)strlen(buf3
) + 1, i
);
351 test_it(char *(*func
)(char *, size_t), const char *name
, int init_size
)
355 fprintf (verbose_fp
, "testing %s (initial size %d)\n", name
, init_size
);
356 ret
= test_1 (func
, name
, init_size
);
358 fprintf (verbose_fp
, "FAILED!\n");
360 fprintf (verbose_fp
, "passed\n");
365 #include <linux/unistd.h>
370 #define __NR_sys_getcwd __NR_getcwd
374 _syscall2(int, sys_getcwd
, char *, buf
, size_t, size
)
377 getcwd_syscall (char *buf
, size_t size
)
383 if (initial_string (&buf
, &size
, MAXPATHLEN
) < 0)
390 ret
= sys_getcwd (buf
, size
);
393 else if (errno
== ERANGE
) {
396 if (expand_string (&buf
, &size
, size
* 2) < 0)
404 getcwd_syscall (char *buf
, size_t size
)
412 static int help_flag
;
414 static struct agetargs args
[] = {
415 {"verbose", 'v', aarg_flag
, &verbose_flag
, "verbose", NULL
},
416 {"help", 0, aarg_flag
, &help_flag
, NULL
, NULL
},
417 {NULL
, 0, aarg_end
, NULL
, NULL
, NULL
}
423 aarg_printusage (args
, NULL
, "", AARG_GNUSTYLE
);
427 main(int argc
, char **argv
)
432 setprogname (argv
[0]);
434 verbose_flag
= getenv ("VERBOSE") != NULL
;
436 if (agetarg (args
, argc
, argv
, &optind
, AARG_GNUSTYLE
))
447 verbose_fp
= fdopen (4, "w");
448 if (verbose_fp
== NULL
) {
449 verbose_fp
= fopen ("/dev/null", "w");
450 if (verbose_fp
== NULL
)
454 ret
+= test_it (getcwd
, "getcwd", 3);
456 ret
+= test_it (getcwd_syscall
, "getcwd_syscall", 3);
458 ret
+= test_it (getcwd_classic
, "getcwd_classic", 0);
460 ret
+= test_it (getcwd_proc
, "getcwd_proc", 0);