1 /*
2 * Check decoding of getdents and getdents64 syscalls.
3 *
4 * Copyright (c) 2015-2020 Dmitry V. Levin <ldv@strace.io>
5 * All rights reserved.
6 *
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
10 #include <dirent.h>
11 #include <fcntl.h>
12 #include <stdio.h>
13 #include <unistd.h>
14 #include <sys/stat.h>
15 #include "kernel_dirent.h"
16 #include "print_fields.h"
17
18 #if VERBOSE
19 static const char *
20 str_d_type(const unsigned char d_type)
21 {
22 switch (d_type) {
23 case DT_DIR:
24 return "DT_DIR";
25 case DT_REG:
26 return "DT_REG";
27 default:
28 return "DT_UNKNOWN";
29 }
30 }
31
32 static void
33 print_dirent(const kernel_dirent_type *d);
34 #endif
35
36 static const char *errstr;
37
38 static long
39 k_getdents(const unsigned int fd,
40 const void *dirp,
41 const unsigned int count)
42 {
43 const kernel_ulong_t fill = (kernel_ulong_t) 0xdefaced00000000ULL;
44 const kernel_ulong_t bad = (kernel_ulong_t) 0xbadc0dedbadc0dedULL;
45 const kernel_ulong_t arg1 = fill | fd;
46 const kernel_ulong_t arg2 = (uintptr_t) dirp;
47 const kernel_ulong_t arg3 = fill | count;
48 const long rc = syscall(NR_getdents, arg1, arg2, arg3, bad, bad, bad);
49 errstr = sprintrc(rc);
50 return rc;
51 }
52
53 static void
54 ls(int fd, char *buf, unsigned int size)
55 {
56 long rc;
57 while ((rc = k_getdents(fd, buf, size))) {
58 if (rc < 0)
59 perror_msg_and_skip(STR_getdents);
60 printf("%s(%d, ", STR_getdents, fd);
61 #if VERBOSE
62 printf("[");
63 #else
64 unsigned long entries = 0;
65 #endif
66 kernel_dirent_type *d;
67 for (long i = 0; i < rc; i += d->d_reclen) {
68 d = (kernel_dirent_type *) &buf[i];
69 #if VERBOSE
70 if (i)
71 printf(", ");
72 print_dirent(d);
73 #else
74 ++entries;
75 #endif
76 }
77 #if VERBOSE
78 printf("]");
79 #else
80 printf("%p /* %lu entries */", buf, entries);
81 #endif
82 printf(", %u) = %ld\n", size, rc);
83 }
84 #if VERBOSE
85 printf("%s(%d, [], %u) = 0\n", STR_getdents, fd, size);
86 #else
87 printf("%s(%d, %p /* 0 entries */, %u) = 0\n",
88 STR_getdents, fd, buf, size);
89 #endif
90 }
91
92 int
93 main(void)
94 {
95 static const char dot[] = ".";
96 static const char dot_dot[] = "..";
97 static const char dname[] = STR_getdents
98 #if VERBOSE
99 "-v"
100 #endif
101 ".test.tmp.dir";
102 static const char fname[] =
103 "A\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\n"
104 "A\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\n"
105 "A\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\n"
106 "A\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\n"
107 "A\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\n"
108 "A\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\n"
109 "A\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\n"
110 "A\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nA\nZ";
111
112 if (mkdir(dname, 0700))
113 perror_msg_and_fail("mkdir: %s", dname);
114 if (chdir(dname))
115 perror_msg_and_fail("chdir: %s", dname);
116 int fd = creat(fname, 0600);
117 if (fd < 0)
118 perror_msg_and_fail("creat: %s", fname);
119 if (close(fd))
120 perror_msg_and_fail("close: %s", fname);
121 fd = open(dot, O_RDONLY | O_DIRECTORY);
122 if (fd < 0)
123 perror_msg_and_fail("open: %s", dot);
124
125 unsigned int count = 0xdeadbeefU;
126 k_getdents(-1U, NULL, count);
127 printf("%s(-1, NULL, %u) = %s\n", STR_getdents, count, errstr);
128
129 static char buf[8192];
130 ls(fd, buf, sizeof(buf));
131
132 if (unlink(fname))
133 perror_msg_and_fail("unlink: %s", fname);
134 if (chdir(dot_dot))
135 perror_msg_and_fail("chdir: %s", dot_dot);
136 if (rmdir(dname))
137 perror_msg_and_fail("rmdir: %s", dname);
138
139 puts("+++ exited with 0 +++");
140 return 0;
141 }