1 /*
2 * Copyright (c) 2014 Fujitsu Ltd.
3 * Author: Xing Gu <[email protected]>
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 off_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, SAFE_WRITE_ALL, 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 TEST(openat(AT_FDCWD, TEST_FILE, O_CLOEXEC | O_RDWR, 0777));
148
149 if (TEST_RETURN == -1) {
150 tst_resm(TFAIL | TTERRNO, "openat failed");
151 return;
152 }
153
154 sprintf(buf, "%ld", TEST_RETURN);
155
156 pid = tst_fork();
157
158 if (pid < 0)
159 tst_brkm(TBROK | TERRNO, cleanup, "fork() failed");
160
161 if (pid == 0) {
162 if (execlp(TEST_APP, TEST_APP, buf, NULL))
163 exit(2);
164 }
165
166 SAFE_CLOSE(cleanup, TEST_RETURN);
167
168 SAFE_WAIT(cleanup, &status);
169
170 if (WIFEXITED(status)) {
171 switch ((int8_t)WEXITSTATUS(status)) {
172 case 0:
173 tst_resm(TPASS, "test O_CLOEXEC for openat success");
174 break;
175 case 1:
176 tst_resm(TFAIL, "test O_CLOEXEC for openat failed");
177 break;
178 default:
179 tst_brkm(TBROK, cleanup, "execlp() failed");
180 }
181 } else {
182 tst_brkm(TBROK, cleanup,
183 "openat2_exec exits with unexpected error");
184 }
185 }
186
testfunc_largefile(void)187 void testfunc_largefile(void)
188 {
189 int fd;
190 off_t offset;
191
192 fd = SAFE_OPEN(cleanup, LARGE_FILE,
193 O_LARGEFILE | O_RDWR | O_CREAT, 0777);
194
195 offset = lseek(fd, 4.1*1024*1024*1024, SEEK_SET);
196 if (offset == -1)
197 tst_brkm(TBROK | TERRNO, cleanup, "lseek64 failed");
198
199 SAFE_WRITE(cleanup, SAFE_WRITE_ALL, fd, STR, sizeof(STR) - 1);
200
201 SAFE_CLOSE(cleanup, fd);
202
203 TEST(openat(AT_FDCWD, LARGE_FILE, O_LARGEFILE | O_RDONLY, 0777));
204
205 if (TEST_RETURN == -1) {
206 tst_resm(TFAIL, "test O_LARGEFILE for openat failed");
207 } else {
208 tst_resm(TPASS, "test O_LARGEFILE for openat success");
209 SAFE_CLOSE(cleanup, TEST_RETURN);
210 }
211 }
212
testfunc_noatime(void)213 void testfunc_noatime(void)
214 {
215 struct stat file_stat, file_newstat;
216 char buf;
217 const char *flags[] = {"noatime", "relatime", NULL};
218 int ret;
219
220 ret = tst_path_has_mnt_flags(cleanup, NULL, flags);
221 if (ret > 0) {
222 tst_resm(TCONF, "test O_NOATIME flag for openat needs "
223 "filesystems which are mounted without "
224 "noatime and relatime");
225 return;
226 }
227
228 SAFE_STAT(cleanup, TEST_FILE, &file_stat);
229
230 sleep(1);
231
232 TEST(openat(AT_FDCWD, TEST_FILE, O_NOATIME | O_RDONLY, 0777));
233
234 if (TEST_RETURN == -1) {
235 tst_resm(TFAIL | TTERRNO, "openat failed");
236 return;
237 }
238
239 SAFE_READ(cleanup, 1, TEST_RETURN, &buf, 1);
240
241 SAFE_CLOSE(cleanup, TEST_RETURN);
242
243 SAFE_STAT(cleanup, TEST_FILE, &file_newstat);
244
245 if (file_stat.st_atime == file_newstat.st_atime)
246 tst_resm(TPASS, "test O_NOATIME for openat success");
247 else
248 tst_resm(TFAIL, "test O_NOATIME for openat failed");
249 }
250
testfunc_nofollow(void)251 void testfunc_nofollow(void)
252 {
253 TEST(openat(AT_FDCWD, SFILE, O_NOFOLLOW | O_RDONLY, 0777));
254
255 if (TEST_RETURN == -1 && TEST_ERRNO == ELOOP) {
256 tst_resm(TPASS, "test O_NOFOLLOW for openat success");
257 } else {
258 tst_resm(TFAIL, "test O_NOFOLLOW for openat failed");
259 SAFE_CLOSE(cleanup, TEST_RETURN);
260 }
261 }
262
testfunc_trunc(void)263 void testfunc_trunc(void)
264 {
265 struct stat file_stat;
266
267 TEST(openat(AT_FDCWD, TEST_FILE, O_TRUNC | O_RDWR, 0777));
268
269 if (TEST_RETURN == -1) {
270 tst_resm(TFAIL | TTERRNO, "openat failed");
271 return;
272 }
273
274 SAFE_FSTAT(cleanup, TEST_RETURN, &file_stat);
275
276 if (file_stat.st_size == 0)
277 tst_resm(TPASS, "test O_TRUNC for openat success");
278 else
279 tst_resm(TFAIL, "test O_TRUNC for openat failed");
280
281 SAFE_CLOSE(cleanup, TEST_RETURN);
282 }
283
cleanup(void)284 void cleanup(void)
285 {
286 tst_rmdir();
287 }
288