1 /* 2 * Copyright (c) Crackerjack Project., 2007 ,Hitachi, Ltd 3 * Author(s): Takahiro Yasui <takahiro.yasui.mp (at) hitachi.com> 4 * Ported to LTP: Manas Kumar Nayak maknayak (at) in.ibm.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 14 * the GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software Foundation, 18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 */ 20 /* 21 * Description: 22 * Verify that, 23 * 1) utimes() returns -1 and sets errno to EACCES if times 24 * is NULL, the caller's effective user ID does not match 25 * the owner of the file, the caller does not have write 26 * access to the file, and the caller is not privileged. 27 * 2) utimes() returns -1 and sets errno to ENOENT if filename 28 * does not exist. 29 * 3) utimes() returns -1 and sets errno to EFAULT if filename 30 * is NULL. 31 * 4) utimes() returns -1 and sets errno to EPERM if times is 32 * not NULL, the caller's effective UID does not match the 33 * owner of the file, and the caller is not privileged. 34 * 5) utimes() returns -1 and sets errno to EROFS if path resides 35 * on a read-only file system. 36 */ 37 38 #include <sys/types.h> 39 #include <sys/stat.h> 40 #include <sys/time.h> 41 #include <dirent.h> 42 #include <unistd.h> 43 #include <getopt.h> 44 #include <string.h> 45 #include <stdlib.h> 46 #include <errno.h> 47 #include <stdio.h> 48 #include <pwd.h> 49 #include <sys/mount.h> 50 51 #include "test.h" 52 #include "safe_macros.h" 53 #include "linux_syscall_numbers.h" 54 55 #define MNTPOINT "mntpoint" 56 #define TESTFILE1 "testfile1" 57 #define TESTFILE2 "testfile2" 58 #define TESTFILE3 "mntpoint/testfile" 59 #define FILE_MODE (S_IRWXU | S_IRGRP | S_IXGRP | \ 60 S_IROTH | S_IXOTH) 61 #define DIR_MODE (S_IRWXU | S_IRWXG | S_IRWXO) 62 63 #define LTPUSER1 "nobody" 64 #define LTPUSER2 "bin" 65 66 static const char *device; 67 static int mount_flag; 68 69 static struct timeval a_tv[2] = { {0, 0}, {1000, 0} }; 70 static struct timeval m_tv[2] = { {1000, 0}, {0, 0} }; 71 static struct timeval tv[2] = { {1000, 0}, {2000, 0} }; 72 73 static struct test_case_t { 74 char *pathname; 75 struct timeval *times; 76 int exp_errno; 77 } test_cases[] = { 78 { TESTFILE1, a_tv, 0 }, 79 { TESTFILE1, m_tv, 0 }, 80 { TESTFILE2, NULL, EACCES }, 81 { "notexistfile", tv, ENOENT }, 82 { NULL, tv, EFAULT }, 83 { TESTFILE2, tv, EPERM }, 84 { TESTFILE3, tv, EROFS }, 85 }; 86 87 static void setup(void); 88 static void cleanup(void); 89 static void utimes_verify(const struct test_case_t *); 90 91 char *TCID = "utimes01"; 92 int TST_TOTAL = ARRAY_SIZE(test_cases); 93 94 int main(int ac, char **av) 95 { 96 int i, lc; 97 98 tst_parse_opts(ac, av, NULL, NULL); 99 100 setup(); 101 102 for (lc = 0; TEST_LOOPING(lc); ++lc) { 103 tst_count = 0; 104 105 for (i = 0; i < TST_TOTAL; i++) 106 utimes_verify(&test_cases[i]); 107 } 108 109 cleanup(); 110 tst_exit(); 111 } 112 113 static void setup(void) 114 { 115 struct passwd *ltpuser; 116 const char *fs_type; 117 118 tst_require_root(); 119 120 tst_sig(NOFORK, DEF_HANDLER, cleanup); 121 122 TEST_PAUSE; 123 124 tst_tmpdir(); 125 126 fs_type = tst_dev_fs_type(); 127 device = tst_acquire_device(cleanup); 128 129 if (!device) 130 tst_brkm(TCONF, cleanup, "Failed to obtain block device"); 131 132 SAFE_TOUCH(cleanup, TESTFILE1, FILE_MODE, NULL); 133 ltpuser = SAFE_GETPWNAM(cleanup, LTPUSER1); 134 SAFE_CHOWN(cleanup, TESTFILE1, ltpuser->pw_uid, 135 ltpuser->pw_gid); 136 137 SAFE_TOUCH(cleanup, TESTFILE2, FILE_MODE, NULL); 138 ltpuser = SAFE_GETPWNAM(cleanup, LTPUSER2); 139 SAFE_CHOWN(cleanup, TESTFILE2, ltpuser->pw_uid, 140 ltpuser->pw_gid); 141 142 tst_mkfs(cleanup, device, fs_type, NULL, NULL); 143 SAFE_MKDIR(cleanup, MNTPOINT, DIR_MODE); 144 if (mount(device, MNTPOINT, fs_type, 0, NULL) == -1) { 145 tst_brkm(TBROK | TERRNO, cleanup, 146 "mount device:%s failed", device); 147 } 148 mount_flag = 1; 149 SAFE_TOUCH(cleanup, TESTFILE3, FILE_MODE, NULL); 150 ltpuser = SAFE_GETPWNAM(cleanup, LTPUSER1); 151 SAFE_CHOWN(cleanup, TESTFILE3, ltpuser->pw_uid, 152 ltpuser->pw_gid); 153 if (mount(device, MNTPOINT, fs_type, 154 MS_REMOUNT | MS_RDONLY, NULL) == -1) { 155 tst_brkm(TBROK | TERRNO, cleanup, 156 "mount device:%s failed", device); 157 } 158 159 ltpuser = SAFE_GETPWNAM(cleanup, LTPUSER1); 160 SAFE_SETEUID(cleanup, ltpuser->pw_uid); 161 } 162 163 static void utimes_verify(const struct test_case_t *tc) 164 { 165 struct stat st; 166 struct timeval tmp_tv[2]; 167 168 if (tc->exp_errno == 0) { 169 SAFE_STAT(cleanup, tc->pathname, &st); 170 171 tmp_tv[0].tv_sec = st.st_atime; 172 tmp_tv[0].tv_usec = 0; 173 tmp_tv[1].tv_sec = st.st_mtime; 174 tmp_tv[1].tv_usec = 0; 175 } 176 177 TEST(utimes(tc->pathname, tc->times)); 178 179 if (TEST_ERRNO == tc->exp_errno) { 180 tst_resm(TPASS | TTERRNO, "utimes() worked as expected"); 181 } else { 182 tst_resm(TFAIL | TTERRNO, 183 "utimes() failed unexpectedly; expected: %d - %s", 184 tc->exp_errno, strerror(tc->exp_errno)); 185 } 186 187 if (TEST_ERRNO == 0 && utimes(tc->pathname, tmp_tv) == -1) 188 tst_brkm(TBROK | TERRNO, cleanup, "utimes() failed."); 189 } 190 191 static void cleanup(void) 192 { 193 if (seteuid(0) == -1) 194 tst_resm(TWARN | TERRNO, "seteuid(0) failed"); 195 196 if (mount_flag && tst_umount(MNTPOINT) == -1) 197 tst_resm(TWARN | TERRNO, "umount %s failed", MNTPOINT); 198 199 200 if (device) 201 tst_release_device(device); 202 203 tst_rmdir(); 204 } 205