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