1 /*
2 * Copyright (c) 2014 Fujitsu Ltd.
3 * Author: Xing Gu <gux.fnst@cn.fujitsu.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 */
17 /*
18 * Description:
19 * Verify that,
20 * 1)openat() succeeds to open a file in append mode, when
21 * 'flags' is set to O_APPEND.
22 * 2)openat() succeeds to enable the close-on-exec flag for a
23 * file descriptor, when 'flags' is set to O_CLOEXEC.
24 * 3)openat() succeeds to allow files whose sizes cannot be
25 * represented in an off_t but can be represented in an off64_t
26 * to be opened, when 'flags' is set to O_LARGEFILE.
27 * 4)openat() succeeds to not update the file last access time
28 * (st_atime in the inode) when the file is read, when 'flags'
29 * is set to O_NOATIME.
30 * 5)openat() succeeds to open the file failed if the file is a
31 * symbolic link, when 'flags' is set to O_NOFOLLOW.
32 * 6)openat() succeeds to truncate the file to length 0 if the file
33 * already exists and is a regular file and the open mode allows
34 * writing, when 'flags' is set to O_TRUNC.
35 */
36
37 #define _GNU_SOURCE
38
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <fcntl.h>
42 #include <unistd.h>
43 #include <sys/wait.h>
44 #include <stdlib.h>
45 #include <stdio.h>
46 #include <stdint.h>
47 #include <mntent.h>
48
49 #include "test.h"
50 #include "safe_macros.h"
51 #include "lapi/fcntl.h"
52 #include "openat.h"
53
54 #define TEST_APP "openat02_child"
55
56 #define TEST_FILE "test_file"
57 #define SFILE "sfile"
58 #define LARGE_FILE "large_file"
59
60 #define STR "abcdefg"
61
62 static void setup(void);
63 static void cleanup(void);
64
65 static void testfunc_append(void);
66 static void testfunc_cloexec(void);
67 static void testfunc_largefile(void);
68 static void testfunc_noatime(void);
69 static void testfunc_nofollow(void);
70 static void testfunc_trunc(void);
71
72 static void (*testfunc[])(void) = {
73 testfunc_append,
74 testfunc_cloexec,
75 testfunc_largefile,
76 testfunc_noatime,
77 testfunc_nofollow,
78 testfunc_trunc,
79 };
80
81 char *TCID = "openat02";
82 int TST_TOTAL = ARRAY_SIZE(testfunc);
83
main(int ac,char ** av)84 int main(int ac, char **av)
85 {
86 int lc;
87 int i;
88
89 tst_parse_opts(ac, av, NULL, NULL);
90
91 setup();
92
93 for (lc = 0; TEST_LOOPING(lc); lc++) {
94 tst_count = 0;
95
96 for (i = 0; i < TST_TOTAL; i++)
97 (*testfunc[i])();
98 }
99
100 cleanup();
101 tst_exit();
102 }
103
setup(void)104 void setup(void)
105 {
106 TEST_PAUSE;
107
108 tst_sig(FORK, DEF_HANDLER, cleanup);
109
110 tst_tmpdir();
111
112 SAFE_FILE_PRINTF(cleanup, TEST_FILE, "test file");
113
114 SAFE_SYMLINK(cleanup, TEST_FILE, SFILE);
115 }
116
testfunc_append(void)117 void testfunc_append(void)
118 {
119 off_t file_offset;
120
121 SAFE_FILE_PRINTF(cleanup, TEST_FILE, "test file");
122
123 TEST(openat(AT_FDCWD, TEST_FILE, O_APPEND | O_RDWR, 0777));
124
125 if (TEST_RETURN == -1) {
126 tst_resm(TFAIL | TTERRNO, "openat failed");
127 return;
128 }
129
130 SAFE_WRITE(cleanup, 1, TEST_RETURN, STR, sizeof(STR) - 1);
131
132 file_offset = SAFE_LSEEK(cleanup, TEST_RETURN, 0, SEEK_CUR);
133
134 if (file_offset > (off_t)(sizeof(STR) - 1))
135 tst_resm(TPASS, "test O_APPEND for openat success");
136 else
137 tst_resm(TFAIL, "test O_APPEND for openat failed");
138
139 SAFE_CLOSE(cleanup, TEST_RETURN);
140 }
141
testfunc_cloexec(void)142 void testfunc_cloexec(void)
143 {
144 pid_t pid;
145 int status;
146 char buf[20];
147
148 if ((tst_kvercmp(2, 6, 23)) < 0) {
149 tst_resm(TCONF, "test O_CLOEXEC flags for openat "
150 "needs kernel 2.6.23 or higher");
151 return;
152 }
153
154 TEST(openat(AT_FDCWD, TEST_FILE, O_CLOEXEC | O_RDWR, 0777));
155
156 if (TEST_RETURN == -1) {
157 tst_resm(TFAIL | TTERRNO, "openat failed");
158 return;
159 }
160
161 sprintf(buf, "%ld", TEST_RETURN);
162
163 pid = tst_fork();
164
165 if (pid < 0)
166 tst_brkm(TBROK | TERRNO, cleanup, "fork() failed");
167
168 if (pid == 0) {
169 if (execlp(TEST_APP, TEST_APP, buf, NULL))
170 exit(2);
171 }
172
173 SAFE_CLOSE(cleanup, TEST_RETURN);
174
175 SAFE_WAIT(cleanup, &status);
176
177 if (WIFEXITED(status)) {
178 switch ((int8_t)WEXITSTATUS(status)) {
179 case 0:
180 tst_resm(TPASS, "test O_CLOEXEC for openat success");
181 break;
182 case 1:
183 tst_resm(TFAIL, "test O_CLOEXEC for openat failed");
184 break;
185 default:
186 tst_brkm(TBROK, cleanup, "execlp() failed");
187 }
188 } else {
189 tst_brkm(TBROK, cleanup,
190 "openat2_exec exits with unexpected error");
191 }
192 }
193
testfunc_largefile(void)194 void testfunc_largefile(void)
195 {
196 int fd;
197 off64_t offset;
198
199 fd = SAFE_OPEN(cleanup, LARGE_FILE,
200 O_LARGEFILE | O_RDWR | O_CREAT, 0777);
201
202 offset = lseek64(fd, 4.1*1024*1024*1024, SEEK_SET);
203 if (offset == -1)
204 tst_brkm(TBROK | TERRNO, cleanup, "lseek64 failed");
205
206 SAFE_WRITE(cleanup, 1, fd, STR, sizeof(STR) - 1);
207
208 SAFE_CLOSE(cleanup, fd);
209
210 TEST(openat(AT_FDCWD, LARGE_FILE, O_LARGEFILE | O_RDONLY, 0777));
211
212 if (TEST_RETURN == -1) {
213 tst_resm(TFAIL, "test O_LARGEFILE for openat failed");
214 } else {
215 tst_resm(TPASS, "test O_LARGEFILE for openat success");
216 SAFE_CLOSE(cleanup, TEST_RETURN);
217 }
218 }
219
testfunc_noatime(void)220 void testfunc_noatime(void)
221 {
222 struct stat file_stat, file_newstat;
223 char buf;
224 const char *flags[] = {"noatime", "relatime", NULL};
225 int ret;
226
227 if ((tst_kvercmp(2, 6, 8)) < 0) {
228 tst_resm(TCONF, "test O_NOATIME flags for openat "
229 "needs kernel 2.6.8 or higher");
230 return;
231 }
232
233 ret = tst_path_has_mnt_flags(cleanup, NULL, flags);
234 if (ret > 0) {
235 tst_resm(TCONF, "test O_NOATIME flag for openat needs "
236 "filesystems which are mounted without "
237 "noatime and relatime");
238 return;
239 }
240
241 SAFE_STAT(cleanup, TEST_FILE, &file_stat);
242
243 sleep(1);
244
245 TEST(openat(AT_FDCWD, TEST_FILE, O_NOATIME | O_RDONLY, 0777));
246
247 if (TEST_RETURN == -1) {
248 tst_resm(TFAIL | TTERRNO, "openat failed");
249 return;
250 }
251
252 SAFE_READ(cleanup, 1, TEST_RETURN, &buf, 1);
253
254 SAFE_CLOSE(cleanup, TEST_RETURN);
255
256 SAFE_STAT(cleanup, TEST_FILE, &file_newstat);
257
258 if (file_stat.st_atime == file_newstat.st_atime)
259 tst_resm(TPASS, "test O_NOATIME for openat success");
260 else
261 tst_resm(TFAIL, "test O_NOATIME for openat failed");
262 }
263
testfunc_nofollow(void)264 void testfunc_nofollow(void)
265 {
266 TEST(openat(AT_FDCWD, SFILE, O_NOFOLLOW | O_RDONLY, 0777));
267
268 if (TEST_RETURN == -1 && TEST_ERRNO == ELOOP) {
269 tst_resm(TPASS, "test O_NOFOLLOW for openat success");
270 } else {
271 tst_resm(TFAIL, "test O_NOFOLLOW for openat failed");
272 SAFE_CLOSE(cleanup, TEST_RETURN);
273 }
274 }
275
testfunc_trunc(void)276 void testfunc_trunc(void)
277 {
278 struct stat file_stat;
279
280 TEST(openat(AT_FDCWD, TEST_FILE, O_TRUNC | O_RDWR, 0777));
281
282 if (TEST_RETURN == -1) {
283 tst_resm(TFAIL | TTERRNO, "openat failed");
284 return;
285 }
286
287 SAFE_FSTAT(cleanup, TEST_RETURN, &file_stat);
288
289 if (file_stat.st_size == 0)
290 tst_resm(TPASS, "test O_TRUNC for openat success");
291 else
292 tst_resm(TFAIL, "test O_TRUNC for openat failed");
293
294 SAFE_CLOSE(cleanup, TEST_RETURN);
295 }
296
cleanup(void)297 void cleanup(void)
298 {
299 tst_rmdir();
300 }
301