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 <unistd.h>
42 #include <sys/wait.h>
43 #include <stdlib.h>
44 #include <stdio.h>
45 #include <stdint.h>
46 #include <mntent.h>
47
48 #include "test.h"
49 #include "safe_macros.h"
50 #include "lapi/fcntl.h"
51 #include "openat.h"
52
53 #define TEST_APP "openat02_child"
54
55 #define TEST_FILE "test_file"
56 #define SFILE "sfile"
57 #define LARGE_FILE "large_file"
58
59 #define STR "abcdefg"
60
61 static void setup(void);
62 static void cleanup(void);
63
64 static void testfunc_append(void);
65 static void testfunc_cloexec(void);
66 static void testfunc_largefile(void);
67 static void testfunc_noatime(void);
68 static void testfunc_nofollow(void);
69 static void testfunc_trunc(void);
70
71 static void (*testfunc[])(void) = {
72 testfunc_append,
73 testfunc_cloexec,
74 testfunc_largefile,
75 testfunc_noatime,
76 testfunc_nofollow,
77 testfunc_trunc,
78 };
79
80 char *TCID = "openat02";
81 int TST_TOTAL = ARRAY_SIZE(testfunc);
82
main(int ac,char ** av)83 int main(int ac, char **av)
84 {
85 int lc;
86 int i;
87
88 tst_parse_opts(ac, av, NULL, NULL);
89
90 setup();
91
92 for (lc = 0; TEST_LOOPING(lc); lc++) {
93 tst_count = 0;
94
95 for (i = 0; i < TST_TOTAL; i++)
96 (*testfunc[i])();
97 }
98
99 cleanup();
100 tst_exit();
101 }
102
setup(void)103 void setup(void)
104 {
105 TEST_PAUSE;
106
107 tst_sig(FORK, DEF_HANDLER, cleanup);
108
109 tst_tmpdir();
110
111 SAFE_FILE_PRINTF(cleanup, TEST_FILE, "test file");
112
113 SAFE_SYMLINK(cleanup, TEST_FILE, SFILE);
114 }
115
testfunc_append(void)116 void testfunc_append(void)
117 {
118 off_t file_offset;
119
120 SAFE_FILE_PRINTF(cleanup, TEST_FILE, "test file");
121
122 TEST(openat(AT_FDCWD, TEST_FILE, O_APPEND | O_RDWR, 0777));
123
124 if (TEST_RETURN == -1) {
125 tst_resm(TFAIL | TTERRNO, "openat failed");
126 return;
127 }
128
129 SAFE_WRITE(cleanup, 1, TEST_RETURN, STR, sizeof(STR) - 1);
130
131 file_offset = SAFE_LSEEK(cleanup, TEST_RETURN, 0, SEEK_CUR);
132
133 if (file_offset > (off_t)(sizeof(STR) - 1))
134 tst_resm(TPASS, "test O_APPEND for openat success");
135 else
136 tst_resm(TFAIL, "test O_APPEND for openat failed");
137
138 SAFE_CLOSE(cleanup, TEST_RETURN);
139 }
140
testfunc_cloexec(void)141 void testfunc_cloexec(void)
142 {
143 pid_t pid;
144 int status;
145 char buf[20];
146
147 if ((tst_kvercmp(2, 6, 23)) < 0) {
148 tst_resm(TCONF, "test O_CLOEXEC flags for openat "
149 "needs kernel 2.6.23 or higher");
150 return;
151 }
152
153 TEST(openat(AT_FDCWD, TEST_FILE, O_CLOEXEC | O_RDWR, 0777));
154
155 if (TEST_RETURN == -1) {
156 tst_resm(TFAIL | TTERRNO, "openat failed");
157 return;
158 }
159
160 sprintf(buf, "%ld", TEST_RETURN);
161
162 pid = tst_fork();
163
164 if (pid < 0)
165 tst_brkm(TBROK | TERRNO, cleanup, "fork() failed");
166
167 if (pid == 0) {
168 if (execlp(TEST_APP, TEST_APP, buf, NULL))
169 exit(2);
170 }
171
172 SAFE_CLOSE(cleanup, TEST_RETURN);
173
174 SAFE_WAIT(cleanup, &status);
175
176 if (WIFEXITED(status)) {
177 switch ((int8_t)WEXITSTATUS(status)) {
178 case 0:
179 tst_resm(TPASS, "test O_CLOEXEC for openat success");
180 break;
181 case 1:
182 tst_resm(TFAIL, "test O_CLOEXEC for openat failed");
183 break;
184 default:
185 tst_brkm(TBROK, cleanup, "execlp() failed");
186 }
187 } else {
188 tst_brkm(TBROK, cleanup,
189 "openat2_exec exits with unexpected error");
190 }
191 }
192
testfunc_largefile(void)193 void testfunc_largefile(void)
194 {
195 int fd;
196 off64_t offset;
197
198 fd = SAFE_OPEN(cleanup, LARGE_FILE,
199 O_LARGEFILE | O_RDWR | O_CREAT, 0777);
200
201 offset = lseek64(fd, 4.1*1024*1024*1024, SEEK_SET);
202 if (offset == -1)
203 tst_brkm(TBROK | TERRNO, cleanup, "lseek64 failed");
204
205 SAFE_WRITE(cleanup, 1, fd, STR, sizeof(STR) - 1);
206
207 SAFE_CLOSE(cleanup, fd);
208
209 TEST(openat(AT_FDCWD, LARGE_FILE, O_LARGEFILE | O_RDONLY, 0777));
210
211 if (TEST_RETURN == -1) {
212 tst_resm(TFAIL, "test O_LARGEFILE for openat failed");
213 } else {
214 tst_resm(TPASS, "test O_LARGEFILE for openat success");
215 SAFE_CLOSE(cleanup, TEST_RETURN);
216 }
217 }
218
testfunc_noatime(void)219 void testfunc_noatime(void)
220 {
221 struct stat file_stat, file_newstat;
222 char buf;
223 const char *flags[] = {"noatime", "relatime", NULL};
224 int ret;
225
226 if ((tst_kvercmp(2, 6, 8)) < 0) {
227 tst_resm(TCONF, "test O_NOATIME flags for openat "
228 "needs kernel 2.6.8 or higher");
229 return;
230 }
231
232 ret = tst_path_has_mnt_flags(cleanup, NULL, flags);
233 if (ret > 0) {
234 tst_resm(TCONF, "test O_NOATIME flag for openat needs "
235 "filesystems which are mounted without "
236 "noatime and relatime");
237 return;
238 }
239
240 SAFE_STAT(cleanup, TEST_FILE, &file_stat);
241
242 sleep(1);
243
244 TEST(openat(AT_FDCWD, TEST_FILE, O_NOATIME | O_RDONLY, 0777));
245
246 if (TEST_RETURN == -1) {
247 tst_resm(TFAIL | TTERRNO, "openat failed");
248 return;
249 }
250
251 SAFE_READ(cleanup, 1, TEST_RETURN, &buf, 1);
252
253 SAFE_CLOSE(cleanup, TEST_RETURN);
254
255 SAFE_STAT(cleanup, TEST_FILE, &file_newstat);
256
257 if (file_stat.st_atime == file_newstat.st_atime)
258 tst_resm(TPASS, "test O_NOATIME for openat success");
259 else
260 tst_resm(TFAIL, "test O_NOATIME for openat failed");
261 }
262
testfunc_nofollow(void)263 void testfunc_nofollow(void)
264 {
265 TEST(openat(AT_FDCWD, SFILE, O_NOFOLLOW | O_RDONLY, 0777));
266
267 if (TEST_RETURN == -1 && TEST_ERRNO == ELOOP) {
268 tst_resm(TPASS, "test O_NOFOLLOW for openat success");
269 } else {
270 tst_resm(TFAIL, "test O_NOFOLLOW for openat failed");
271 SAFE_CLOSE(cleanup, TEST_RETURN);
272 }
273 }
274
testfunc_trunc(void)275 void testfunc_trunc(void)
276 {
277 struct stat file_stat;
278
279 TEST(openat(AT_FDCWD, TEST_FILE, O_TRUNC | O_RDWR, 0777));
280
281 if (TEST_RETURN == -1) {
282 tst_resm(TFAIL | TTERRNO, "openat failed");
283 return;
284 }
285
286 SAFE_FSTAT(cleanup, TEST_RETURN, &file_stat);
287
288 if (file_stat.st_size == 0)
289 tst_resm(TPASS, "test O_TRUNC for openat success");
290 else
291 tst_resm(TFAIL, "test O_TRUNC for openat failed");
292
293 SAFE_CLOSE(cleanup, TEST_RETURN);
294 }
295
cleanup(void)296 void cleanup(void)
297 {
298 tst_rmdir();
299 }
300