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 42char *TCID = "open12"; 43 44static const char *device; 45static unsigned int mount_flag, skip_noatime; 46 47static void setup(void); 48static void cleanup(void); 49static void test_append(void); 50static void test_noatime(void); 51static void test_cloexec(void); 52static void test_largefile(void); 53 54static void (*test_func[])(void) = { test_append, test_noatime, test_cloexec, 55 test_largefile }; 56 57int TST_TOTAL = ARRAY_SIZE(test_func); 58 59int 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 78static 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 116end: 117 SAFE_FILE_PRINTF(cleanup, TEST_FILE, TEST_FILE); 118} 119 120static 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 142static 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 181static 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 234static 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 260static 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