*** empty log message ***
[arla.git] / tests / apwd.c
blobe3163142a29e1fbafeb4ddfdff79f2c76be75569
1 /*
2 * Copyright (c) 1995 - 2002, 2006 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.
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
31 * SUCH DAMAGE.
34 #ifdef HAVE_CONFIG_H
35 #include <config.h>
36 #endif
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <errno.h>
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <fcntl.h>
46 #include <unistd.h>
47 #include <dirent.h>
49 #include <err.h>
50 #include <agetarg.h>
52 #include <roken.h>
54 RCSID("$Id$");
56 static int verbose_flag;
57 static FILE *verbose_fp = NULL;
59 static int
60 initial_string (char **buf, size_t *size, size_t new_size)
62 char *tmp = malloc (new_size);
64 if (tmp == NULL)
65 return -1;
66 *buf = tmp;
67 *size = new_size;
68 return 0;
71 static int
72 expand_string (char **buf, size_t *size, size_t new_size)
74 char *tmp = realloc (*buf, new_size);
76 if (tmp == NULL)
77 return -1;
78 *buf = tmp;
79 *size = new_size;
80 return 0;
84 * Verify that the dynamically allocated string `buf' of length
85 * `size', has room for `len' bytes. Returns -1 if realloc fails.
88 static int
89 guarantee_room (char **buf, size_t *size, size_t len)
91 if (*size > len)
92 return 0;
94 return expand_string (buf, size, min(*size * 2, len));
97 static char *
98 getcwd_classic (char *buf, size_t size)
100 int dynamic_buf = 0;
101 struct stat root_sb, dot_sb, dotdot_sb;
102 char *work_string;
103 size_t work_length;
104 char slash_dot_dot[] = "/..";
105 char *curp;
106 char *endp;
107 DIR *dir = NULL;
109 if (initial_string (&work_string, &work_length, MAXPATHLEN) < 0)
110 return NULL;
112 if (buf == NULL) {
113 dynamic_buf = 1;
114 if (initial_string (&buf, &size, MAXPATHLEN) < 0) {
115 free (work_string);
116 return NULL;
120 endp = curp = buf + size - 1;
122 if (lstat (".", &dot_sb) < 0)
123 goto err_ret;
124 if (lstat ("/", &root_sb) < 0)
125 goto err_ret;
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) {
133 struct dirent *dp;
134 int found = 0;
135 int change_dev = 0;
136 int pattern_len = strlen (work_string);
138 if (lstat (work_string, &dotdot_sb) < 0)
139 goto err_ret;
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)
143 change_dev = 1;
144 dir = opendir (work_string);
145 if (dir == NULL)
146 goto err_ret;
147 while ((dp = readdir (dir)) != NULL) {
148 size_t name_len = strlen (dp->d_name);
150 if (change_dev) {
151 struct stat sb;
153 if (guarantee_room (&work_string, &work_length,
154 pattern_len + name_len + 2) < 0) {
155 goto err_ret;
158 strcat (work_string, "/");
159 strcat (work_string, dp->d_name);
161 if (lstat (work_string, &sb) < 0) {
162 goto err_ret;
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);
167 found = 1;
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);
172 found = 1;
175 if (found) {
176 while (buf + name_len >= curp) {
177 size_t old_len;
179 if (!dynamic_buf) {
180 errno = ERANGE;
181 goto err_ret;
183 old_len = endp - curp + 1;
184 if (expand_string (&buf, &size, size * 2) < 0)
185 goto err_ret;
186 memmove (buf + size - old_len,
187 buf + size / 2 - old_len,
188 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;
195 break;
198 closedir (dir);
199 dir = NULL;
201 if (!found)
202 goto err_ret;
204 dot_sb = dotdot_sb;
205 if (guarantee_room (&work_string, &work_length,
206 pattern_len + strlen(slash_dot_dot) + 1) < 0)
207 goto err_ret;
208 strcat (work_string, slash_dot_dot);
210 if (curp == endp) {
211 while (buf >= curp) {
212 if (!dynamic_buf) {
213 errno = ERANGE;
214 goto err_ret;
216 if (expand_string (&buf, &size, size * 2) < 0)
217 goto err_ret;
219 *--curp = '/';
221 *endp = '\0';
222 memmove (buf, curp, endp - curp + 1);
223 free (work_string);
224 return buf;
226 err_ret:
227 if (dir)
228 closedir (dir);
229 if (dynamic_buf)
230 free (buf);
231 free (work_string);
232 return NULL;
235 #if linux
237 static char *
238 getcwd_proc (char *buf, size_t size)
240 int dynamic_buf = 0;
242 if (buf == NULL) {
243 dynamic_buf = 1;
244 if (initial_string (&buf, &size, MAXPATHLEN) < 0)
245 return NULL;
246 } else if (size <= 1) {
247 errno = ERANGE;
248 return NULL;
251 for (;;) {
252 int ret;
254 ret = readlink ("/proc/self/cwd", buf, size - 1);
255 if (ret == -1)
256 goto err_ret;
257 buf[ret] = '\0';
258 if (buf[0] != '/') {
259 errno = EINVAL;
260 goto err_ret;
262 if (buf[ret-1] != '\0' && ret >= size) {
263 if (!dynamic_buf) {
264 errno = ERANGE;
265 goto err_ret;
267 if (expand_string (&buf, &size, size * 2) < 0)
268 goto err_ret;
269 } else {
270 if (buf[ret - 1] != '\0')
271 buf[ret] = '\0';
272 return buf;
275 err_ret:
276 if (dynamic_buf)
277 free (buf);
278 return NULL;
281 #endif /* linux */
283 static int
284 test_1(char *(*func)(char *, size_t), const char *func_name, int init_size)
286 char real_buf[2048];
287 char buf[2048], buf3[4711];
288 int i;
289 int ret = 0;
290 int three_done = 1;
292 if (getcwd (real_buf, sizeof(real_buf)) == NULL) {
293 fprintf (verbose_fp, "getcwd(buf, %u) failed\n",
294 (unsigned)sizeof(real_buf));
295 ret = 1;
297 if (func (buf, sizeof(buf)) == NULL) {
298 fprintf (verbose_fp, "%s(buf, %u) failed\n", func_name,
299 (unsigned)sizeof(buf));
300 ret = 1;
301 } else {
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",
305 real_buf, buf);
306 ret = 1;
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);
315 three_done = 0;
316 break;
318 } else {
319 int j;
321 for (j = i; j < sizeof(buf3); ++j)
322 if (buf3[j] != '\x01') {
323 fprintf (verbose_fp, "buffer was overwritten at %d\n", j);
324 three_done = 0;
325 break;
327 break;
331 if (three_done) {
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",
335 real_buf, buf3);
336 ret = 1;
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);
341 ret = 1;
343 } else {
344 ret = 1;
347 return ret;
350 static int
351 test_it(char *(*func)(char *, size_t), const char *name, int init_size)
353 int ret;
355 fprintf (verbose_fp, "testing %s (initial size %d)\n", name, init_size);
356 ret = test_1 (func, name, init_size);
357 if (ret)
358 fprintf (verbose_fp, "FAILED!\n");
359 else
360 fprintf (verbose_fp, "passed\n");
361 return ret;
364 #ifdef linux
365 #include <linux/unistd.h>
366 #endif
368 #ifdef __NR_getcwd
370 #define __NR_sys_getcwd __NR_getcwd
372 #ifdef _syscall2
373 static
374 _syscall2(int, sys_getcwd, char *, buf, size_t, size)
376 static char *
377 getcwd_syscall (char *buf, size_t size)
379 int dynamic_buf = 0;
381 if (buf == NULL) {
382 dynamic_buf = 1;
383 if (initial_string (&buf, &size, MAXPATHLEN) < 0)
384 return NULL;
387 for (;;) {
388 int ret;
390 ret = sys_getcwd (buf, size);
391 if (ret >= 0)
392 return buf;
393 else if (errno == ERANGE) {
394 if (!dynamic_buf)
395 return NULL;
396 if (expand_string (&buf, &size, size * 2) < 0)
397 return NULL;
398 } else
399 return NULL;
402 #else
403 static char *
404 getcwd_syscall (char *buf, size_t size)
406 return NULL;
408 #endif
410 #endif
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}
420 static void
421 usage (int exit_val)
423 aarg_printusage (args, NULL, "", AARG_GNUSTYLE);
427 main(int argc, char **argv)
429 int ret = 0;
430 int optind = 0;
432 setprogname (argv[0]);
434 verbose_flag = getenv ("VERBOSE") != NULL;
436 if (agetarg (args, argc, argv, &optind, AARG_GNUSTYLE))
437 usage (1);
439 argc -= optind;
440 argv += optind;
442 if (argc != 0)
443 usage (1);
444 if (help_flag)
445 usage (0);
447 verbose_fp = fdopen (4, "w");
448 if (verbose_fp == NULL) {
449 verbose_fp = fopen ("/dev/null", "w");
450 if (verbose_fp == NULL)
451 err (1, "fopen");
454 ret += test_it (getcwd, "getcwd", 3);
455 #ifdef __NR_getcwd
456 ret += test_it (getcwd_syscall, "getcwd_syscall", 3);
457 #endif
458 ret += test_it (getcwd_classic, "getcwd_classic", 0);
459 #if linux
460 ret += test_it (getcwd_proc, "getcwd_proc", 0);
461 #endif
462 return ret;