xref: /aosp_15_r20/external/ltp/testcases/kernel/syscalls/openat/openat02.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
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