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