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 * Test that linkat() fails and sets the proper errno values. 18 */ 19 20#define _GNU_SOURCE 21 22#include <sys/types.h> 23#include <sys/stat.h> 24#include <fcntl.h> 25#include <unistd.h> 26#include <error.h> 27#include <stdlib.h> 28#include <errno.h> 29#include <string.h> 30#include <signal.h> 31#include <pwd.h> 32#include <sys/mount.h> 33 34#include "test.h" 35#include "linux_syscall_numbers.h" 36#include "safe_macros.h" 37#include "lapi/fcntl.h" 38 39#define DIR_MODE (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP| \ 40 S_IXGRP|S_IROTH|S_IXOTH) 41#define TEST_FILE "testfile" 42#define TEST_EXIST "testexist" 43#define TEST_ELOOP "testeloop" 44#define TEST_EACCES "./tmp/testeeacces" 45#define TEST_EACCES2 "./tmp/testeeacces2" 46#define TEST_EROFS "mntpoint" 47#define TEST_EROFS2 "mntpoint/testerofs2" 48#define TEST_EMLINK "emlink_dir/testfile0" 49#define TEST_EMLINK2 "emlink_dir/testfile" 50#define BASENAME "mntpoint/basename" 51 52static char nametoolong[PATH_MAX+2]; 53static const char *device; 54static int mount_flag; 55static int max_hardlinks; 56static const char *fs_type; 57 58static void setup(void); 59static void cleanup(void); 60static void setup_eacces(void); 61static void cleanup_eacces(void); 62static void setup_erofs(void); 63 64static struct test_struct { 65 const char *oldfname; 66 const char *newfname; 67 int flags; 68 int expected_errno; 69 void (*setupfunc) (void); 70 void (*cleanfunc) (void); 71} test_cases[] = { 72 {TEST_FILE, nametoolong, 0, ENAMETOOLONG, NULL, NULL}, 73 {nametoolong, TEST_FILE, 0, ENAMETOOLONG, NULL, NULL}, 74 {TEST_EXIST, TEST_EXIST, 0, EEXIST, NULL, NULL}, 75 {TEST_ELOOP, TEST_FILE, AT_SYMLINK_FOLLOW, ELOOP, NULL, NULL}, 76 {TEST_EACCES, TEST_EACCES2, 0, EACCES, setup_eacces, cleanup_eacces}, 77 {TEST_EROFS, TEST_EROFS2, 0, EROFS, setup_erofs, NULL}, 78 {TEST_EMLINK, TEST_EMLINK2, 0, EMLINK, NULL, NULL}, 79}; 80 81char *TCID = "linkat02"; 82int TST_TOTAL = ARRAY_SIZE(test_cases); 83 84static struct passwd *ltpuser; 85static void linkat_verify(const struct test_struct *); 86 87int main(int ac, char **av) 88{ 89 int lc; 90 int i; 91 92 tst_parse_opts(ac, av, NULL, NULL); 93 94 setup(); 95 96 for (lc = 0; TEST_LOOPING(lc); lc++) { 97 tst_count = 0; 98 for (i = 0; i < TST_TOTAL; i++) 99 linkat_verify(&test_cases[i]); 100 } 101 102 cleanup(); 103 tst_exit(); 104} 105 106static void linkat_verify(const struct test_struct *desc) 107{ 108 if (desc->expected_errno == EMLINK && max_hardlinks == 0) { 109 tst_resm(TCONF, "EMLINK test is not appropriate"); 110 return; 111 } 112 113 if (desc->setupfunc != NULL) { 114 desc->setupfunc(); 115 } 116 117 TEST(ltp_syscall(__NR_linkat, AT_FDCWD, desc->oldfname, 118 AT_FDCWD, desc->newfname, desc->flags)); 119 120 if (desc->cleanfunc != NULL) 121 desc->cleanfunc(); 122 123 if (TEST_RETURN != -1) { 124 tst_resm(TFAIL, 125 "linkat(""AT_FDCWD"", %s, ""AT_FDCWD"", %s, %d)" 126 "succeeded unexpectedly", desc->oldfname, 127 desc->newfname, desc->flags); 128 return; 129 } 130 131 if (TEST_ERRNO == desc->expected_errno) { 132 tst_resm(TPASS | TTERRNO, "linkat failed as expected"); 133 } else { 134 tst_resm(TFAIL | TTERRNO, 135 "linkat failed unexpectedly; expected: " 136 "%d - %s", desc->expected_errno, 137 strerror(desc->expected_errno)); 138 } 139} 140 141static void setup(void) 142{ 143 if ((tst_kvercmp(2, 6, 16)) < 0) 144 tst_brkm(TCONF, NULL, "This test needs kernel 2.6.16 or newer"); 145 146 tst_require_root(); 147 148 tst_sig(NOFORK, DEF_HANDLER, cleanup); 149 150 tst_tmpdir(); 151 152 fs_type = tst_dev_fs_type(); 153 device = tst_acquire_device(cleanup); 154 155 if (!device) 156 tst_brkm(TCONF, cleanup, "Failed to acquire device"); 157 158 TEST_PAUSE; 159 160 ltpuser = SAFE_GETPWNAM(cleanup, "nobody"); 161 162 SAFE_TOUCH(cleanup, TEST_FILE, 0644, NULL); 163 164 memset(nametoolong, 'a', PATH_MAX+1); 165 166 SAFE_TOUCH(cleanup, TEST_EXIST, 0644, NULL); 167 168 SAFE_SYMLINK(cleanup, TEST_ELOOP, "test_file_eloop2"); 169 SAFE_SYMLINK(cleanup, "test_file_eloop2", TEST_ELOOP); 170 171 SAFE_MKDIR(cleanup, "./tmp", DIR_MODE); 172 SAFE_TOUCH(cleanup, TEST_EACCES, 0666, NULL); 173 174 tst_mkfs(cleanup, device, fs_type, NULL, NULL); 175 SAFE_MKDIR(cleanup, "mntpoint", DIR_MODE); 176 177 if (mount(device, "mntpoint", fs_type, 0, NULL) < 0) { 178 tst_brkm(TBROK | TERRNO, cleanup, 179 "mount device:%s failed", device); 180 } 181 mount_flag = 1; 182 183 max_hardlinks = tst_fs_fill_hardlinks(cleanup, "emlink_dir"); 184} 185 186static void setup_eacces(void) 187{ 188 SAFE_SETEUID(cleanup, ltpuser->pw_uid); 189} 190 191static void cleanup_eacces(void) 192{ 193 SAFE_SETEUID(cleanup, 0); 194} 195 196static void setup_erofs(void) 197{ 198 if (mount(device, "mntpoint", fs_type, 199 MS_REMOUNT | MS_RDONLY, NULL) < 0) { 200 tst_brkm(TBROK | TERRNO, cleanup, "remount device:%s failed", 201 device); 202 } 203 mount_flag = 1; 204} 205 206static void cleanup(void) 207{ 208 if (mount_flag && tst_umount("mntpoint") < 0) 209 tst_resm(TWARN | TERRNO, "umount device:%s failed", device); 210 211 if (device) 212 tst_release_device(device); 213 214 tst_rmdir(); 215} 216