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 SAFE_WAIT(cleanup, &status); 176 177 if (WIFEXITED(status)) { 178 switch ((int8_t)WEXITSTATUS(status)) { 179 case 0: 180 tst_resm(TPASS, "test O_CLOEXEC for openat success"); 181 break; 182 case 1: 183 tst_resm(TFAIL, "test O_CLOEXEC for openat failed"); 184 break; 185 default: 186 tst_brkm(TBROK, cleanup, "execlp() failed"); 187 } 188 } else { 189 tst_brkm(TBROK, cleanup, 190 "openat2_exec exits with unexpected error"); 191 } 192 } 193 194 void testfunc_largefile(void) 195 { 196 int fd; 197 off64_t offset; 198 199 fd = SAFE_OPEN(cleanup, LARGE_FILE, 200 O_LARGEFILE | O_RDWR | O_CREAT, 0777); 201 202 offset = lseek64(fd, 4.1*1024*1024*1024, SEEK_SET); 203 if (offset == -1) 204 tst_brkm(TBROK | TERRNO, cleanup, "lseek64 failed"); 205 206 SAFE_WRITE(cleanup, 1, fd, STR, sizeof(STR) - 1); 207 208 SAFE_CLOSE(cleanup, fd); 209 210 TEST(openat(AT_FDCWD, LARGE_FILE, O_LARGEFILE | O_RDONLY, 0777)); 211 212 if (TEST_RETURN == -1) { 213 tst_resm(TFAIL, "test O_LARGEFILE for openat failed"); 214 } else { 215 tst_resm(TPASS, "test O_LARGEFILE for openat success"); 216 SAFE_CLOSE(cleanup, TEST_RETURN); 217 } 218 } 219 220 void testfunc_noatime(void) 221 { 222 struct stat file_stat, file_newstat; 223 char buf; 224 const char *flags[] = {"noatime", "relatime", NULL}; 225 int ret; 226 227 if ((tst_kvercmp(2, 6, 8)) < 0) { 228 tst_resm(TCONF, "test O_NOATIME flags for openat " 229 "needs kernel 2.6.8 or higher"); 230 return; 231 } 232 233 ret = tst_path_has_mnt_flags(cleanup, NULL, flags); 234 if (ret > 0) { 235 tst_resm(TCONF, "test O_NOATIME flag for openat needs " 236 "filesystems which are mounted without " 237 "noatime and relatime"); 238 return; 239 } 240 241 SAFE_STAT(cleanup, TEST_FILE, &file_stat); 242 243 sleep(1); 244 245 TEST(openat(AT_FDCWD, TEST_FILE, O_NOATIME | O_RDONLY, 0777)); 246 247 if (TEST_RETURN == -1) { 248 tst_resm(TFAIL | TTERRNO, "openat failed"); 249 return; 250 } 251 252 SAFE_READ(cleanup, 1, TEST_RETURN, &buf, 1); 253 254 SAFE_CLOSE(cleanup, TEST_RETURN); 255 256 SAFE_STAT(cleanup, TEST_FILE, &file_newstat); 257 258 if (file_stat.st_atime == file_newstat.st_atime) 259 tst_resm(TPASS, "test O_NOATIME for openat success"); 260 else 261 tst_resm(TFAIL, "test O_NOATIME for openat failed"); 262 } 263 264 void testfunc_nofollow(void) 265 { 266 TEST(openat(AT_FDCWD, SFILE, O_NOFOLLOW | O_RDONLY, 0777)); 267 268 if (TEST_RETURN == -1 && TEST_ERRNO == ELOOP) { 269 tst_resm(TPASS, "test O_NOFOLLOW for openat success"); 270 } else { 271 tst_resm(TFAIL, "test O_NOFOLLOW for openat failed"); 272 SAFE_CLOSE(cleanup, TEST_RETURN); 273 } 274 } 275 276 void testfunc_trunc(void) 277 { 278 struct stat file_stat; 279 280 TEST(openat(AT_FDCWD, TEST_FILE, O_TRUNC | O_RDWR, 0777)); 281 282 if (TEST_RETURN == -1) { 283 tst_resm(TFAIL | TTERRNO, "openat failed"); 284 return; 285 } 286 287 SAFE_FSTAT(cleanup, TEST_RETURN, &file_stat); 288 289 if (file_stat.st_size == 0) 290 tst_resm(TPASS, "test O_TRUNC for openat success"); 291 else 292 tst_resm(TFAIL, "test O_TRUNC for openat failed"); 293 294 SAFE_CLOSE(cleanup, TEST_RETURN); 295 } 296 297 void cleanup(void) 298 { 299 tst_rmdir(); 300 } 301