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 if (wait(&status) == -1)
176 tst_brkm(TBROK | TERRNO, cleanup, "wait() failed");
177
178 if (WIFEXITED(status)) {
179 switch ((int8_t)WEXITSTATUS(status)) {
180 case 0:
181 tst_resm(TPASS, "test O_CLOEXEC for openat success");
182 break;
183 case 1:
184 tst_resm(TFAIL, "test O_CLOEXEC for openat failed");
185 break;
186 default:
187 tst_brkm(TBROK, cleanup, "execlp() failed");
188 }
189 } else {
190 tst_brkm(TBROK, cleanup,
191 "openat2_exec exits with unexpected error");
192 }
193 }
194
testfunc_largefile(void)195 void testfunc_largefile(void)
196 {
197 int fd;
198 off64_t offset;
199
200 fd = SAFE_OPEN(cleanup, LARGE_FILE,
201 O_LARGEFILE | O_RDWR | O_CREAT, 0777);
202
203 offset = lseek64(fd, 4.1*1024*1024*1024, SEEK_SET);
204 if (offset == -1)
205 tst_brkm(TBROK | TERRNO, cleanup, "lseek64 failed");
206
207 SAFE_WRITE(cleanup, 1, fd, STR, sizeof(STR) - 1);
208
209 SAFE_CLOSE(cleanup, fd);
210
211 TEST(openat(AT_FDCWD, LARGE_FILE, O_LARGEFILE | O_RDONLY, 0777));
212
213 if (TEST_RETURN == -1) {
214 tst_resm(TFAIL, "test O_LARGEFILE for openat failed");
215 } else {
216 tst_resm(TPASS, "test O_LARGEFILE for openat success");
217 SAFE_CLOSE(cleanup, TEST_RETURN);
218 }
219 }
220
testfunc_noatime(void)221 void testfunc_noatime(void)
222 {
223 struct stat file_stat, file_newstat;
224 char buf;
225 const char *flags[] = {"noatime", "relatime", NULL};
226 int ret;
227
228 if ((tst_kvercmp(2, 6, 8)) < 0) {
229 tst_resm(TCONF, "test O_NOATIME flags for openat "
230 "needs kernel 2.6.8 or higher");
231 return;
232 }
233
234 ret = tst_path_has_mnt_flags(cleanup, NULL, flags);
235 if (ret > 0) {
236 tst_resm(TCONF, "test O_NOATIME flag for openat needs "
237 "filesystems which are mounted without "
238 "noatime and relatime");
239 return;
240 }
241
242 SAFE_STAT(cleanup, TEST_FILE, &file_stat);
243
244 sleep(1);
245
246 TEST(openat(AT_FDCWD, TEST_FILE, O_NOATIME | O_RDONLY, 0777));
247
248 if (TEST_RETURN == -1) {
249 tst_resm(TFAIL | TTERRNO, "openat failed");
250 return;
251 }
252
253 SAFE_READ(cleanup, 1, TEST_RETURN, &buf, 1);
254
255 SAFE_CLOSE(cleanup, TEST_RETURN);
256
257 SAFE_STAT(cleanup, TEST_FILE, &file_newstat);
258
259 if (file_stat.st_atime == file_newstat.st_atime)
260 tst_resm(TPASS, "test O_NOATIME for openat success");
261 else
262 tst_resm(TFAIL, "test O_NOATIME for openat failed");
263 }
264
testfunc_nofollow(void)265 void testfunc_nofollow(void)
266 {
267 TEST(openat(AT_FDCWD, SFILE, O_NOFOLLOW | O_RDONLY, 0777));
268
269 if (TEST_RETURN == -1 && TEST_ERRNO == ELOOP) {
270 tst_resm(TPASS, "test O_NOFOLLOW for openat success");
271 } else {
272 tst_resm(TFAIL, "test O_NOFOLLOW for openat failed");
273 SAFE_CLOSE(cleanup, TEST_RETURN);
274 }
275 }
276
testfunc_trunc(void)277 void testfunc_trunc(void)
278 {
279 struct stat file_stat;
280
281 TEST(openat(AT_FDCWD, TEST_FILE, O_TRUNC | O_RDWR, 0777));
282
283 if (TEST_RETURN == -1) {
284 tst_resm(TFAIL | TTERRNO, "openat failed");
285 return;
286 }
287
288 SAFE_FSTAT(cleanup, TEST_RETURN, &file_stat);
289
290 if (file_stat.st_size == 0)
291 tst_resm(TPASS, "test O_TRUNC for openat success");
292 else
293 tst_resm(TFAIL, "test O_TRUNC for openat failed");
294
295 SAFE_CLOSE(cleanup, TEST_RETURN);
296 }
297
cleanup(void)298 void cleanup(void)
299 {
300 tst_rmdir();
301 }
302