• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2014 Fujitsu Ltd.
3  * Author: Zeng Linggang <zenglg.jy@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.
15  */
16 /*
17  * DESCRIPTION
18  *	This test case will verify basic function of open(2) with the flags
19  *	O_APPEND, O_NOATIME, O_CLOEXEC and O_LARGEFILE.
20  */
21 
22 #define _GNU_SOURCE
23 
24 #include <stdio.h>
25 #include <sys/types.h>
26 #include <sys/wait.h>
27 #include <sys/mount.h>
28 #include <unistd.h>
29 #include <mntent.h>
30 #include <errno.h>
31 #include "test.h"
32 #include "safe_macros.h"
33 #include "lapi/fcntl.h"
34 #include "lapi/mount.h"
35 
36 #define MNTPOINT	"mntpoint"
37 #define TEST_FILE	MNTPOINT"/test_file"
38 #define LARGE_FILE	"large_file"
39 
40 #define DIR_MODE 0755
41 
42 char *TCID = "open12";
43 
44 static const char *device;
45 static unsigned int mount_flag, skip_noatime;
46 
47 static void setup(void);
48 static void cleanup(void);
49 static void test_append(void);
50 static void test_noatime(void);
51 static void test_cloexec(void);
52 static void test_largefile(void);
53 
54 static void (*test_func[])(void) = { test_append, test_noatime, test_cloexec,
55 				     test_largefile };
56 
57 int TST_TOTAL = ARRAY_SIZE(test_func);
58 
main(int argc,char ** argv)59 int main(int argc, char **argv)
60 {
61 	int lc;
62 	int i;
63 
64 	tst_parse_opts(argc, argv, NULL, NULL);
65 
66 	setup();
67 
68 	for (lc = 0; TEST_LOOPING(lc); lc++) {
69 		tst_count = 0;
70 		for (i = 0; i < TST_TOTAL; i++)
71 			(*test_func[i])();
72 	}
73 
74 	cleanup();
75 	tst_exit();
76 }
77 
setup(void)78 static void setup(void)
79 {
80 	const char *mount_flags[] = {"noatime", "relatime", NULL};
81 
82 	TEST_PAUSE;
83 
84 	tst_sig(FORK, DEF_HANDLER, cleanup);
85 
86 	tst_tmpdir();
87 
88 	SAFE_MKDIR(cleanup, MNTPOINT, DIR_MODE);
89 
90 	if (tst_path_has_mnt_flags(cleanup, NULL, mount_flags)) {
91 		const char *fs_type;
92 
93 		if ((tst_kvercmp(2, 6, 30)) < 0) {
94 			tst_resm(TCONF,
95 				"MS_STRICTATIME flags for mount(2) needs kernel 2.6.30 "
96 				"or higher");
97 			skip_noatime = 1;
98 			return;
99 		}
100 
101 		fs_type = tst_dev_fs_type();
102 		device = tst_acquire_device(cleanup);
103 
104 		if (!device) {
105 			tst_resm(TINFO, "Failed to obtain block device");
106 			skip_noatime = 1;
107 			goto end;
108 		}
109 
110 		tst_mkfs(cleanup, device, fs_type, NULL, NULL);
111 
112 		SAFE_MOUNT(cleanup, device, MNTPOINT, fs_type, MS_STRICTATIME, NULL);
113 		mount_flag = 1;
114 	}
115 
116 end:
117 	SAFE_FILE_PRINTF(cleanup, TEST_FILE, TEST_FILE);
118 }
119 
test_append(void)120 static void test_append(void)
121 {
122 	off_t len1, len2;
123 
124 	TEST(open(TEST_FILE, O_RDWR | O_APPEND, 0777));
125 
126 	if (TEST_RETURN == -1) {
127 		tst_resm(TFAIL | TTERRNO, "open failed");
128 		return;
129 	}
130 
131 	len1 = SAFE_LSEEK(cleanup, TEST_RETURN, 0, SEEK_CUR);
132 	SAFE_WRITE(cleanup, 1, TEST_RETURN, TEST_FILE, sizeof(TEST_FILE));
133 	len2 = SAFE_LSEEK(cleanup, TEST_RETURN, 0, SEEK_CUR);
134 	SAFE_CLOSE(cleanup, TEST_RETURN);
135 
136 	if (len2 > len1)
137 		tst_resm(TPASS, "test O_APPEND for open success");
138 	else
139 		tst_resm(TFAIL, "test O_APPEND for open failed");
140 }
141 
test_noatime(void)142 static void test_noatime(void)
143 {
144 	char read_buf;
145 	struct stat old_stat, new_stat;
146 
147 	if ((tst_kvercmp(2, 6, 8)) < 0) {
148 		tst_resm(TCONF,
149 			 "O_NOATIME flags test for open(2) needs kernel 2.6.8 "
150 			 "or higher");
151 		return;
152 	}
153 
154 	if (skip_noatime) {
155 		tst_resm(TCONF,
156 		         "test O_NOATIME flag for open needs filesystems which "
157 		         "is mounted without noatime and relatime");
158 		return;
159 	}
160 
161 	SAFE_STAT(cleanup, TEST_FILE, &old_stat);
162 
163 	sleep(1);
164 
165 	TEST(open(TEST_FILE, O_RDONLY | O_NOATIME, 0777));
166 
167 	if (TEST_RETURN == -1) {
168 		tst_resm(TFAIL | TTERRNO, "open failed");
169 		return;
170 	}
171 	SAFE_READ(cleanup, 1, TEST_RETURN, &read_buf, 1);
172 	SAFE_CLOSE(cleanup, TEST_RETURN);
173 	SAFE_STAT(cleanup, TEST_FILE, &new_stat);
174 
175 	if (old_stat.st_atime == new_stat.st_atime)
176 		tst_resm(TPASS, "test O_NOATIME for open success");
177 	else
178 		tst_resm(TFAIL, "test O_NOATIME for open failed");
179 }
180 
test_cloexec(void)181 static void test_cloexec(void)
182 {
183 	pid_t pid;
184 	int status;
185 	char buf[20];
186 
187 	if ((tst_kvercmp(2, 6, 23)) < 0) {
188 		tst_resm(TCONF,
189 			 "O_CLOEXEC flags test for open(2) needs kernel 2.6.23 "
190 			 "or higher");
191 		return;
192 	}
193 
194 	TEST(open(TEST_FILE, O_RDWR | O_APPEND | O_CLOEXEC, 0777));
195 
196 	if (TEST_RETURN == -1) {
197 		tst_resm(TFAIL | TTERRNO, "open failed");
198 		return;
199 	}
200 
201 	sprintf(buf, "%ld", TEST_RETURN);
202 
203 	pid = tst_fork();
204 	if (pid < 0)
205 		tst_brkm(TBROK | TERRNO, cleanup, "fork() failed");
206 
207 	if (pid == 0) {
208 		if (execlp("open12_child", "open12_child", buf, NULL))
209 			exit(2);
210 	}
211 
212 	SAFE_CLOSE(cleanup, TEST_RETURN);
213 
214 	if (wait(&status) != pid)
215 		tst_brkm(TBROK | TERRNO, cleanup, "wait() failed");
216 
217 	if (WIFEXITED(status)) {
218 		switch ((int8_t)WEXITSTATUS(status)) {
219 		case 0:
220 			tst_resm(TPASS, "test O_CLOEXEC for open success");
221 		break;
222 		case 1:
223 			tst_resm(TFAIL, "test O_CLOEXEC for open failed");
224 		break;
225 		default:
226 			tst_brkm(TBROK, cleanup, "execlp() failed");
227 		}
228 	} else {
229 		tst_brkm(TBROK, cleanup,
230 				 "open12_child exits with unexpected error");
231 	}
232 }
233 
test_largefile(void)234 static void test_largefile(void)
235 {
236 	int fd;
237 	off64_t offset;
238 
239 	fd = SAFE_OPEN(cleanup, LARGE_FILE,
240 				O_LARGEFILE | O_RDWR | O_CREAT, 0777);
241 
242 	offset = lseek64(fd, 4.1*1024*1024*1024, SEEK_SET);
243 	if (offset == -1)
244 		tst_brkm(TBROK | TERRNO, cleanup, "lseek64 failed");
245 
246 	SAFE_WRITE(cleanup, 1, fd, LARGE_FILE, sizeof(LARGE_FILE));
247 
248 	SAFE_CLOSE(cleanup, fd);
249 
250 	TEST(open(LARGE_FILE, O_LARGEFILE | O_RDONLY, 0777));
251 
252 	if (TEST_RETURN == -1) {
253 		tst_resm(TFAIL, "test O_LARGEFILE for open failed");
254 	} else {
255 		tst_resm(TPASS, "test O_LARGEFILE for open success");
256 		SAFE_CLOSE(cleanup, TEST_RETURN);
257 	}
258 }
259 
cleanup(void)260 static void cleanup(void)
261 {
262 	if (mount_flag && tst_umount(MNTPOINT) == -1)
263 		tst_brkm(TWARN | TERRNO, NULL, "umount(2) failed");
264 
265 	if (device)
266 		tst_release_device(device);
267 
268 	tst_rmdir();
269 }
270