1 /* 2 * Copyright (c) 2014 Fujitsu Ltd. 3 * Author: Xing Gu <gux.fnst (at) 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 <fcntl.h> 42 #include <unistd.h> 43 #include <sys/wait.h> 44 #include <stdlib.h> 45 #include <stdio.h> 46 #include <stdint.h> 47 #include <mntent.h> 48 49 #include "test.h" 50 #include "safe_macros.h" 51 #include "lapi/fcntl.h" 52 #include "openat.h" 53 54 #define TEST_APP "openat02_child" 55 56 #define TEST_FILE "test_file" 57 #define SFILE "sfile" 58 #define LARGE_FILE "large_file" 59 60 #define STR "abcdefg" 61 62 static void setup(void); 63 static void cleanup(void); 64 65 static void testfunc_append(void); 66 static void testfunc_cloexec(void); 67 static void testfunc_largefile(void); 68 static void testfunc_noatime(void); 69 static void testfunc_nofollow(void); 70 static void testfunc_trunc(void); 71 72 static void (*testfunc[])(void) = { 73 testfunc_append, 74 testfunc_cloexec, 75 testfunc_largefile, 76 testfunc_noatime, 77 testfunc_nofollow, 78 testfunc_trunc, 79 }; 80 81 char *TCID = "openat02"; 82 int TST_TOTAL = ARRAY_SIZE(testfunc); 83 84 int main(int ac, char **av) 85 { 86 int lc; 87 int i; 88 89 tst_parse_opts(ac, av, NULL, NULL); 90 91 setup(); 92 93 for (lc = 0; TEST_LOOPING(lc); lc++) { 94 tst_count = 0; 95 96 for (i = 0; i < TST_TOTAL; i++) 97 (*testfunc[i])(); 98 } 99 100 cleanup(); 101 tst_exit(); 102 } 103 104 void setup(void) 105 { 106 TEST_PAUSE; 107 108 tst_sig(FORK, DEF_HANDLER, cleanup); 109 110 tst_tmpdir(); 111 112 SAFE_FILE_PRINTF(cleanup, TEST_FILE, "test file"); 113 114 SAFE_SYMLINK(cleanup, TEST_FILE, SFILE); 115 } 116 117 void testfunc_append(void) 118 { 119 off_t file_offset; 120 121 SAFE_FILE_PRINTF(cleanup, TEST_FILE, "test file"); 122 123 TEST(openat(AT_FDCWD, TEST_FILE, O_APPEND | O_RDWR, 0777)); 124 125 if (TEST_RETURN == -1) { 126 tst_resm(TFAIL | TTERRNO, "openat failed"); 127 return; 128 } 129 130 SAFE_WRITE(cleanup, 1, TEST_RETURN, STR, sizeof(STR) - 1); 131 132 file_offset = SAFE_LSEEK(cleanup, TEST_RETURN, 0, SEEK_CUR); 133 134 if (file_offset > (off_t)(sizeof(STR) - 1)) 135 tst_resm(TPASS, "test O_APPEND for openat success"); 136 else 137 tst_resm(TFAIL, "test O_APPEND for openat failed"); 138 139 SAFE_CLOSE(cleanup, TEST_RETURN); 140 } 141 142 void testfunc_cloexec(void) 143 { 144 pid_t pid; 145 int status; 146 char buf[20]; 147 148 if ((tst_kvercmp(2, 6, 23)) < 0) { 149 tst_resm(TCONF, "test O_CLOEXEC flags for openat " 150 "needs kernel 2.6.23 or higher"); 151 return; 152 } 153 154 TEST(openat(AT_FDCWD, TEST_FILE, O_CLOEXEC | O_RDWR, 0777)); 155 156 if (TEST_RETURN == -1) { 157 tst_resm(TFAIL | TTERRNO, "openat failed"); 158 return; 159 } 160 161 sprintf(buf, "%ld", TEST_RETURN); 162 163 pid = tst_fork(); 164 165 if (pid < 0) 166 tst_brkm(TBROK | TERRNO, cleanup, "fork() failed"); 167 168 if (pid == 0) { 169 if (execlp(TEST_APP, TEST_APP, buf, NULL)) 170 exit(2); 171 } 172 173 SAFE_CLOSE(cleanup, TEST_RETURN); 174 175 if (wait(&status) == -1) 176 tst_brkm(TBROK | TERRNO, cleanup, "wait() failed"); 177 178 if (WIFEXITED(status)) { 179 switch ((int8_t)WEXITSTATUS(status)) { 180 case 0: 181 tst_resm(TPASS, "test O_CLOEXEC for openat success"); 182 break; 183 case 1: 184 tst_resm(TFAIL, "test O_CLOEXEC for openat failed"); 185 break; 186 default: 187 tst_brkm(TBROK, cleanup, "execlp() failed"); 188 } 189 } else { 190 tst_brkm(TBROK, cleanup, 191 "openat2_exec exits with unexpected error"); 192 } 193 } 194 195 void testfunc_largefile(void) 196 { 197 int fd; 198 off64_t offset; 199 200 fd = SAFE_OPEN(cleanup, LARGE_FILE, 201 O_LARGEFILE | O_RDWR | O_CREAT, 0777); 202 203 offset = lseek64(fd, 4.1*1024*1024*1024, SEEK_SET); 204 if (offset == -1) 205 tst_brkm(TBROK | TERRNO, cleanup, "lseek64 failed"); 206 207 SAFE_WRITE(cleanup, 1, fd, STR, sizeof(STR) - 1); 208 209 SAFE_CLOSE(cleanup, fd); 210 211 TEST(openat(AT_FDCWD, LARGE_FILE, O_LARGEFILE | O_RDONLY, 0777)); 212 213 if (TEST_RETURN == -1) { 214 tst_resm(TFAIL, "test O_LARGEFILE for openat failed"); 215 } else { 216 tst_resm(TPASS, "test O_LARGEFILE for openat success"); 217 SAFE_CLOSE(cleanup, TEST_RETURN); 218 } 219 } 220 221 void testfunc_noatime(void) 222 { 223 struct stat file_stat, file_newstat; 224 char buf; 225 const char *flags[] = {"noatime", "relatime", NULL}; 226 int ret; 227 228 if ((tst_kvercmp(2, 6, 8)) < 0) { 229 tst_resm(TCONF, "test O_NOATIME flags for openat " 230 "needs kernel 2.6.8 or higher"); 231 return; 232 } 233 234 ret = tst_path_has_mnt_flags(cleanup, NULL, flags); 235 if (ret > 0) { 236 tst_resm(TCONF, "test O_NOATIME flag for openat needs " 237 "filesystems which are mounted without " 238 "noatime and relatime"); 239 return; 240 } 241 242 SAFE_STAT(cleanup, TEST_FILE, &file_stat); 243 244 sleep(1); 245 246 TEST(openat(AT_FDCWD, TEST_FILE, O_NOATIME | O_RDONLY, 0777)); 247 248 if (TEST_RETURN == -1) { 249 tst_resm(TFAIL | TTERRNO, "openat failed"); 250 return; 251 } 252 253 SAFE_READ(cleanup, 1, TEST_RETURN, &buf, 1); 254 255 SAFE_CLOSE(cleanup, TEST_RETURN); 256 257 SAFE_STAT(cleanup, TEST_FILE, &file_newstat); 258 259 if (file_stat.st_atime == file_newstat.st_atime) 260 tst_resm(TPASS, "test O_NOATIME for openat success"); 261 else 262 tst_resm(TFAIL, "test O_NOATIME for openat failed"); 263 } 264 265 void testfunc_nofollow(void) 266 { 267 TEST(openat(AT_FDCWD, SFILE, O_NOFOLLOW | O_RDONLY, 0777)); 268 269 if (TEST_RETURN == -1 && TEST_ERRNO == ELOOP) { 270 tst_resm(TPASS, "test O_NOFOLLOW for openat success"); 271 } else { 272 tst_resm(TFAIL, "test O_NOFOLLOW for openat failed"); 273 SAFE_CLOSE(cleanup, TEST_RETURN); 274 } 275 } 276 277 void testfunc_trunc(void) 278 { 279 struct stat file_stat; 280 281 TEST(openat(AT_FDCWD, TEST_FILE, O_TRUNC | O_RDWR, 0777)); 282 283 if (TEST_RETURN == -1) { 284 tst_resm(TFAIL | TTERRNO, "openat failed"); 285 return; 286 } 287 288 SAFE_FSTAT(cleanup, TEST_RETURN, &file_stat); 289 290 if (file_stat.st_size == 0) 291 tst_resm(TPASS, "test O_TRUNC for openat success"); 292 else 293 tst_resm(TFAIL, "test O_TRUNC for openat failed"); 294 295 SAFE_CLOSE(cleanup, TEST_RETURN); 296 } 297 298 void cleanup(void) 299 { 300 tst_rmdir(); 301 } 302