IA64: Move NPTL public headers to sysdeps/ia64/nptl/.
[platform/upstream/glibc.git] / posix / tst-dir.c
1 /* Copyright (C) 2000-2014 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Ulrich Drepper <drepper@redhat.com>, 2000.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <http://www.gnu.org/licenses/>.  */
18
19 #include <dirent.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <mcheck.h>
23 #include <stddef.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <sys/stat.h>
29
30
31 /* We expect four arguments:
32    - source directory name
33    - object directory
34    - common object directory
35    - the program name with path
36 */
37 int
38 main (int argc, char *argv[])
39 {
40   const char *srcdir;
41   const char *objdir;
42   const char *common_objdir;
43   const char *progpath;
44   struct stat64 st1;
45   struct stat64 st2;
46   struct stat64 st3;
47   DIR *dir1;
48   DIR *dir2;
49   int result = 0;
50   struct dirent64 *d;
51   union
52     {
53       struct dirent64 d;
54       char room [offsetof (struct dirent64, d_name[0]) + NAME_MAX + 1];
55     }
56     direntbuf;
57   char *objdir_copy1;
58   char *objdir_copy2;
59   char *buf;
60   int fd;
61
62   mtrace ();
63
64   if (argc < 5)
65     {
66       puts ("not enough parameters");
67       exit (1);
68     }
69
70   /* Make parameters available with nicer names.  */
71   srcdir = argv[1];
72   objdir = argv[2];
73   common_objdir = argv[3];
74   progpath = argv[4];
75
76   /* First test the current source dir.  We cannot really compare the
77      result of `getpwd' with the srcdir string but we have other means.  */
78   if (stat64 (".", &st1) < 0)
79     {
80       printf ("cannot stat starting directory: %m\n");
81       exit (1);
82     }
83
84   if (chdir (srcdir) < 0)
85     {
86       printf ("cannot change to source directory: %m\n");
87       exit (1);
88     }
89   if (stat64 (".", &st2) < 0)
90     {
91       printf ("cannot stat source directory: %m\n");
92       exit (1);
93     }
94
95   /* The two last stat64 calls better were for the same directory.  */
96   if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
97     {
98       printf ("stat of source directory failed: (%lld,%lld) vs (%lld,%lld)\n",
99               (long long int) st1.st_dev, (long long int) st1.st_ino,
100               (long long int) st2.st_dev, (long long int) st2.st_ino);
101       exit (1);
102     }
103
104   /* Change to the object directory.  */
105   if (chdir (objdir) < 0)
106     {
107       printf ("cannot change to object directory: %m\n");
108       exit (1);
109     }
110   if (stat64 (".", &st1) < 0)
111     {
112       printf ("cannot stat object directory: %m\n");
113       exit (1);
114     }
115   /* Is this the same we get as with the full path?  */
116   if (stat64 (objdir, &st2) < 0)
117     {
118       printf ("cannot stat object directory with full path: %m\n");
119       exit (1);
120     }
121   if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
122     {
123       printf ("stat of object directory failed: (%lld,%lld) vs (%lld,%lld)\n",
124               (long long int) st1.st_dev, (long long int) st1.st_ino,
125               (long long int) st2.st_dev, (long long int) st2.st_ino);
126       exit (1);
127     }
128
129   objdir_copy1 = getcwd (NULL, 0);
130   if (objdir_copy1 == NULL)
131     {
132       printf ("cannot get current directory name for object directory: %m\n");
133       result = 1;
134     }
135
136   /* First test: this directory must include our program.  */
137   if (stat64 (progpath, &st2) < 0)
138     {
139       printf ("cannot stat program: %m\n");
140       exit (1);
141     }
142
143   dir1 = opendir (".");
144   if (dir1 == NULL)
145     {
146       printf ("cannot open object directory: %m\n");
147       exit (1);
148     }
149
150   while ((d = readdir64 (dir1)) != NULL)
151     {
152 #ifdef _DIRENT_HAVE_D_TYPE
153       if (d->d_type != DT_UNKNOWN && d->d_type != DT_REG)
154         continue;
155 #endif
156
157       if (d->d_ino == st2.st_ino)
158         {
159           /* Might be it.  Test the device.  We could use the st_dev
160              element from st1 but what the heck, do more testing.  */
161           if (stat64 (d->d_name, &st3) < 0)
162             {
163               printf ("cannot stat entry from readdir: %m\n");
164               result = 1;
165               d = NULL;
166               break;
167             }
168
169           if (st3.st_dev == st2.st_dev)
170             break;
171         }
172     }
173
174   if (d == NULL)
175     {
176       puts ("haven't found program in object directory");
177       result = 1;
178     }
179
180   /* We leave dir1 open.  */
181
182   /* Stat using file descriptor.  */
183   if (fstat64 (dirfd (dir1), &st2) < 0)
184     {
185       printf ("cannot fstat object directory: %m\n");
186       result = 1;
187     }
188   if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
189     {
190       printf ("fstat of object directory failed: (%lld,%lld) vs (%lld,%lld)\n",
191               (long long int) st1.st_dev, (long long int) st1.st_ino,
192               (long long int) st2.st_dev, (long long int) st2.st_ino);
193       exit (1);
194     }
195
196   if (chdir ("..") < 0)
197     {
198       printf ("cannot go to common object directory with \"..\": %m\n");
199       exit (1);
200     }
201
202   if (stat64 (".", &st1) < 0)
203     {
204       printf ("cannot stat common object directory: %m\n");
205       exit (1);
206     }
207   /* Is this the same we get as with the full path?  */
208   if (stat64 (common_objdir, &st2) < 0)
209     {
210       printf ("cannot stat common object directory with full path: %m\n");
211       exit (1);
212     }
213   if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
214     {
215       printf ("stat of object directory failed: (%lld,%lld) vs (%lld,%lld)\n",
216               (long long int) st1.st_dev, (long long int) st1.st_ino,
217               (long long int) st2.st_dev, (long long int) st2.st_ino);
218       exit (1);
219     }
220
221   /* Stat using file descriptor.  */
222   if (fstat64 (dirfd (dir1), &st2) < 0)
223     {
224       printf ("cannot fstat object directory: %m\n");
225       result = 1;
226     }
227
228   dir2 = opendir (common_objdir);
229   if (dir2 == NULL)
230     {
231       printf ("cannot open common object directory: %m\n");
232       exit (1);
233     }
234
235   while ((d = readdir64 (dir2)) != NULL)
236     {
237 #ifdef _DIRENT_HAVE_D_TYPE
238       if (d->d_type != DT_UNKNOWN && d->d_type != DT_DIR)
239         continue;
240 #endif
241
242       if (d->d_ino == st2.st_ino)
243         {
244           /* Might be it.  Test the device.  We could use the st_dev
245              element from st1 but what the heck, do more testing.  */
246           if (stat64 (d->d_name, &st3) < 0)
247             {
248               printf ("cannot stat entry from readdir: %m\n");
249               result = 1;
250               d = NULL;
251               break;
252             }
253
254           if (st3.st_dev == st2.st_dev)
255             break;
256         }
257     }
258
259   /* This better should be the object directory again.  */
260   if (fchdir (dirfd (dir1)) < 0)
261     {
262       printf ("cannot fchdir to object directory: %m\n");
263       exit (1);
264     }
265
266   objdir_copy2 = getcwd (NULL, 0);
267   if (objdir_copy2 == NULL)
268     {
269       printf ("cannot get current directory name for object directory: %m\n");
270       result = 1;
271     }
272   if (strcmp (objdir_copy1, objdir_copy2) != 0)
273     {
274       puts ("getcwd returned a different string the second time");
275       result = 1;
276     }
277
278   /* This better should be the common object directory again.  */
279   if (fchdir (dirfd (dir2)) < 0)
280     {
281       printf ("cannot fchdir to common object directory: %m\n");
282       exit (1);
283     }
284
285   if (stat64 (".", &st2) < 0)
286     {
287       printf ("cannot stat common object directory: %m\n");
288       exit (1);
289     }
290   if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
291     {
292       printf ("stat of object directory failed: (%lld,%lld) vs (%lld,%lld)\n",
293               (long long int) st1.st_dev, (long long int) st1.st_ino,
294               (long long int) st2.st_dev, (long long int) st2.st_ino);
295       exit (1);
296     }
297
298   buf = (char *) malloc (strlen (objdir_copy1) + 1 + sizeof "tst-dir.XXXXXX");
299   if (buf == NULL)
300     {
301       printf ("cannot allocate buffer: %m");
302       exit (1);
303     }
304
305   stpcpy (stpcpy (stpcpy (buf, objdir_copy1), "/"), "tst-dir.XXXXXX");
306   if (mkdtemp (buf) == NULL)
307     {
308       printf ("cannot create test directory in object directory: %m\n");
309       exit (1);
310     }
311   if (stat64 (buf, &st1) < 0)
312     {
313       printf ("cannot stat new directory \"%s\": %m\n", buf);
314       exit (1);
315     }
316   if (chmod (buf, 0700) < 0)
317     {
318       printf ("cannot change mode of new directory: %m\n");
319       exit (1);
320     }
321
322   /* Try to find the new directory.  */
323   rewinddir (dir1);
324   while (readdir64_r (dir1, &direntbuf.d, &d) == 0 && d != NULL)
325     {
326 #ifdef _DIRENT_HAVE_D_TYPE
327       if (d->d_type != DT_UNKNOWN && d->d_type != DT_DIR)
328         continue;
329 #endif
330
331       if (d->d_ino == st1.st_ino)
332         {
333           /* Might be it.  Test the device.  We could use the st_dev
334              element from st1 but what the heck, do more testing.  */
335           size_t len = strlen (objdir) + 1 + _D_EXACT_NAMLEN (d) + 1;
336           char tmpbuf[len];
337
338           stpcpy (stpcpy (stpcpy (tmpbuf, objdir), "/"), d->d_name);
339
340           if (stat64 (tmpbuf, &st3) < 0)
341             {
342               printf ("cannot stat entry from readdir: %m\n");
343               result = 1;
344               d = NULL;
345               break;
346             }
347
348           if (st3.st_dev == st2.st_dev
349               && strcmp (d->d_name, buf + strlen (buf) - 14) == 0)
350             break;
351         }
352     }
353
354   if (d == NULL)
355     {
356       printf ("haven't found new directory \"%s\"\n", buf);
357       exit (1);
358     }
359
360   if (closedir (dir2) < 0)
361     {
362       printf ("closing dir2 failed: %m\n");
363       result = 1;
364     }
365
366   if (chdir (buf) < 0)
367     {
368       printf ("cannot change to new directory: %m\n");
369       exit (1);
370     }
371
372   dir2 = opendir (buf);
373   if (dir2 == NULL)
374     {
375       printf ("cannot open new directory: %m\n");
376       exit (1);
377     }
378
379   if (fstat64 (dirfd (dir2), &st2) < 0)
380     {
381       printf ("cannot fstat new directory \"%s\": %m\n", buf);
382       exit (1);
383     }
384   if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino)
385     {
386       printf ("stat of new directory failed: (%lld,%lld) vs (%lld,%lld)\n",
387               (long long int) st1.st_dev, (long long int) st1.st_ino,
388               (long long int) st2.st_dev, (long long int) st2.st_ino);
389       exit (1);
390     }
391
392   if (mkdir ("another-dir", 0777) < 0)
393     {
394       printf ("cannot create \"another-dir\": %m\n");
395       exit (1);
396     }
397   fd = open ("and-a-file", O_RDWR | O_CREAT | O_EXCL, 0666);
398   if (fd == -1)
399     {
400       printf ("cannot create \"and-a-file\": %m\n");
401       exit (1);
402     }
403   close (fd);
404
405   /* Some tests about error reporting.  */
406   errno = 0;
407   if (chdir ("and-a-file") >= 0)
408     {
409       printf ("chdir to \"and-a-file\" succeeded\n");
410       exit (1);
411     }
412   if (errno != ENOTDIR)
413     {
414       printf ("chdir to \"and-a-file\" didn't set correct error\n");
415       result = 1;
416     }
417
418   errno = 0;
419   if (chdir ("and-a-file/..") >= 0)
420     {
421       printf ("chdir to \"and-a-file/..\" succeeded\n");
422       exit (1);
423     }
424   if (errno != ENOTDIR)
425     {
426       printf ("chdir to \"and-a-file/..\" didn't set correct error\n");
427       result = 1;
428     }
429
430   errno = 0;
431   if (chdir ("another-dir/../and-a-file") >= 0)
432     {
433       printf ("chdir to \"another-dir/../and-a-file\" succeeded\n");
434       exit (1);
435     }
436   if (errno != ENOTDIR)
437     {
438       printf ("chdir to \"another-dir/../and-a-file\" didn't set correct error\n");
439       result = 1;
440     }
441
442   /* We now should have a directory and a file in the new directory.  */
443   rewinddir (dir2);
444   while (readdir64_r (dir2, &direntbuf.d, &d) == 0 && d != NULL)
445     {
446       if (strcmp (d->d_name, ".") == 0
447           || strcmp (d->d_name, "..") == 0
448           || strcmp (d->d_name, "another-dir") == 0)
449         {
450 #ifdef _DIRENT_HAVE_D_TYPE
451           if (d->d_type != DT_UNKNOWN && d->d_type != DT_DIR)
452             {
453               printf ("d_type for \"%s\" is wrong\n", d->d_name);
454               result = 1;
455             }
456 #endif
457           if (stat64 (d->d_name, &st3) < 0)
458             {
459               printf ("cannot stat \"%s\" is wrong\n", d->d_name);
460               result = 1;
461             }
462           else if (! S_ISDIR (st3.st_mode))
463             {
464               printf ("\"%s\" is no directory\n", d->d_name);
465               result = 1;
466             }
467         }
468       else if (strcmp (d->d_name, "and-a-file") == 0)
469         {
470 #ifdef _DIRENT_HAVE_D_TYPE
471           if (d->d_type != DT_UNKNOWN && d->d_type != DT_REG)
472             {
473               printf ("d_type for \"%s\" is wrong\n", d->d_name);
474               result = 1;
475             }
476 #endif
477           if (stat64 (d->d_name, &st3) < 0)
478             {
479               printf ("cannot stat \"%s\" is wrong\n", d->d_name);
480               result = 1;
481             }
482           else if (! S_ISREG (st3.st_mode))
483             {
484               printf ("\"%s\" is no regular file\n", d->d_name);
485               result = 1;
486             }
487         }
488       else
489         {
490           printf ("unexpected directory entry \"%s\"\n", d->d_name);
491           result = 1;
492         }
493     }
494
495   if (stat64 ("does-not-exist", &st1) >= 0)
496     {
497       puts ("stat for unexisting file did not fail");
498       result = 1;
499     }
500
501   /* Free all resources.  */
502
503   if (closedir (dir1) < 0)
504     {
505       printf ("closing dir1 failed: %m\n");
506       result = 1;
507     }
508   if (closedir (dir2) < 0)
509     {
510       printf ("second closing dir2 failed: %m\n");
511       result = 1;
512     }
513
514   if (rmdir ("another-dir") < 0)
515     {
516       printf ("cannot remove \"another-dir\": %m\n");
517       result = 1;
518     }
519
520   if (unlink ("and-a-file") < 0)
521     {
522       printf ("cannot remove \"and-a-file\": %m\n");
523       result = 1;
524     }
525
526   /* One more test before we leave: mkdir() is supposed to fail with
527      EEXIST if the named file is a symlink.  */
528   if (symlink ("a-symlink", "a-symlink") != 0)
529     {
530       printf ("cannot create symlink \"a-symlink\": %m\n");
531       result = 1;
532     }
533   else
534     {
535       if (mkdir ("a-symlink", 0666) == 0)
536         {
537           puts ("can make directory \"a-symlink\"");
538           result = 1;
539         }
540       else if (errno != EEXIST)
541         {
542           puts ("mkdir(\"a-symlink\") does not fail with EEXIST\n");
543           result = 1;
544         }
545       if (unlink ("a-symlink") < 0)
546         {
547           printf ("cannot unlink \"a-symlink\": %m\n");
548           result = 1;
549         }
550     }
551
552   if (chdir (srcdir) < 0)
553     {
554       printf ("cannot change back to source directory: %m\n");
555       exit (1);
556     }
557
558   if (rmdir (buf) < 0)
559     {
560       printf ("cannot remove \"%s\": %m\n", buf);
561       result = 1;
562     }
563   free (objdir_copy1);
564   free (objdir_copy2);
565
566   if (result == 0)
567     puts ("all OK");
568
569   return result;
570 }