• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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