1/****************************************************************************** 2 * 3 * Copyright (c) International Business Machines Corp., 2006 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 13 * the GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 * 19 * NAME 20 * symlinkat01.c 21 * 22 * DESCRIPTION 23 * This test case will verify basic function of symlinkat 24 * added by kernel 2.6.16 or up. 25 * 26 * Author 27 * Yi Yang <yyangcdl@cn.ibm.com> 28 * 29 * History 30 * 08/25/2006 Created first by Yi Yang <yyangcdl@cn.ibm.com> 31 * 32 *****************************************************************************/ 33 34#define _GNU_SOURCE 35 36#include <sys/types.h> 37#include <sys/stat.h> 38#include <sys/time.h> 39#include <fcntl.h> 40#include <stdlib.h> 41#include <errno.h> 42#include <string.h> 43#include <signal.h> 44#include "test.h" 45#include "safe_macros.h" 46#include "lapi/syscalls.h" 47 48#define MYRETCODE -999 49#ifndef AT_FDCWD 50#define AT_FDCWD -100 51#endif 52 53struct test_struct; 54static void setup(); 55static void cleanup(); 56static void setup_every_copy(); 57static void mysymlinkat_test(struct test_struct *desc); 58 59#define TEST_DIR1 "olddir" 60#define TEST_DIR2 "newdir" 61#define TEST_DIR3 "deldir" 62#define TEST_FILE1 "oldfile" 63#define TEST_FILE2 "newfile" 64#define TEST_FIFO "fifo" 65 66static char dpathname[256] = "%s/" TEST_DIR2 "/" TEST_FILE1; 67static int olddirfd, newdirfd = -1, cwd_fd = AT_FDCWD, stdinfd = 0, crapfd = 68 -1, deldirfd; 69 70struct test_struct { 71 const char *oldfn; 72 int *newfd; 73 const char *newfn; 74 const char *referencefn1; 75 const char *referencefn2; 76 int expected_errno; 77} test_desc[] = { 78 /* relative paths */ 79 { 80 "../" TEST_DIR1 "/" TEST_FILE1, &newdirfd, TEST_FILE1, 81 TEST_DIR1 "/" TEST_FILE1, TEST_DIR2 "/" TEST_FILE1, 0}, 82 /* abs path at dst */ 83 { 84 "../" TEST_DIR1 "/" TEST_FILE1, &newdirfd, dpathname, 85 TEST_DIR1 "/" TEST_FILE1, TEST_DIR2 "/" TEST_FILE1, 0}, 86 /* relative paths to cwd */ 87 { 88 "../" TEST_DIR1 "/" TEST_FILE1, &cwd_fd, 89 TEST_DIR2 "/" TEST_FILE1, TEST_DIR1 "/" TEST_FILE1, 90 TEST_DIR2 "/" TEST_FILE1, 0}, 91 /* abs path */ 92 { 93 "../" TEST_DIR1 "/" TEST_FILE1, &cwd_fd, dpathname, 94 TEST_DIR1 "/" TEST_FILE1, TEST_DIR2 "/" TEST_FILE1, 0}, 95 /* relative paths to invalid */ 96 { 97 "../" TEST_DIR1 "/" TEST_FILE1, &stdinfd, 98 TEST_DIR2 "/" TEST_FILE1, 0, 0, ENOTDIR}, 99 /* abs path at dst */ 100 { 101 "../" TEST_DIR1 "/" TEST_FILE1, &stdinfd, dpathname, 102 TEST_DIR1 "/" TEST_FILE1, TEST_DIR2 "/" TEST_FILE1, 0}, 103 /* relative paths to crap */ 104 { 105 "../" TEST_DIR1 "/" TEST_FILE1, &crapfd, 106 TEST_DIR2 "/" TEST_FILE1, 0, 0, EBADF}, 107 /* abs path at dst */ 108 { 109 "../" TEST_DIR1 "/" TEST_FILE1, &crapfd, dpathname, 110 TEST_DIR1 "/" TEST_FILE1, TEST_DIR2 "/" TEST_FILE1, 0}, 111 /* relative paths to deleted */ 112 { 113 "../" TEST_DIR1 "/" TEST_FILE1, &deldirfd, 114 TEST_DIR2 "/" TEST_FILE1, 0, 0, ENOENT}, 115 /* abs path at dst */ 116 { 117 "../" TEST_DIR1 "/" TEST_FILE1, &deldirfd, dpathname, 118 TEST_DIR1 "/" TEST_FILE1, TEST_DIR2 "/" TEST_FILE1, 0}, 119 /* fifo link */ 120 /* { TEST_FIFO, &newdirfd, TEST_FILE1, TEST_DIR1"/"TEST_FIFO, TEST_DIR2"/"TEST_FILE1, 0 }, */ 121}; 122 123char *TCID = "symlinkat01"; 124int TST_TOTAL = sizeof(test_desc) / sizeof(*test_desc); 125 126static int mysymlinkat(const char *oldfilename, 127 int newdirfd, const char *newfilename) 128{ 129 return tst_syscall(__NR_symlinkat, oldfilename, newdirfd, newfilename); 130} 131 132int main(int ac, char **av) 133{ 134 int lc; 135 int i; 136 137 tst_parse_opts(ac, av, NULL, NULL); 138 139 setup(); 140 141 for (lc = 0; TEST_LOOPING(lc); lc++) { 142 143 tst_count = 0; 144 145 for (i = 0; i < TST_TOTAL; i++) { 146 setup_every_copy(); 147 mysymlinkat_test(&test_desc[i]); 148 149 } 150 151 } 152 153 cleanup(); 154 tst_exit(); 155} 156 157static void setup_every_copy(void) 158{ 159 close(newdirfd); 160 unlink(dpathname); 161 rmdir(TEST_DIR2); 162 163 SAFE_MKDIR(cleanup, TEST_DIR2, 0700); 164 newdirfd = SAFE_OPEN(cleanup, TEST_DIR2, O_DIRECTORY); 165} 166 167static void mysymlinkat_test(struct test_struct *desc) 168{ 169 int fd; 170 171 TEST(mysymlinkat(desc->oldfn, *desc->newfd, desc->newfn)); 172 173 /* check return code */ 174 if (TEST_ERRNO == desc->expected_errno) { 175 if (TEST_RETURN == 0 && desc->referencefn1 != NULL) { 176 int tnum = rand(), vnum = ~tnum; 177 178 fd = SAFE_OPEN(cleanup, desc->referencefn1, O_RDWR); 179 SAFE_WRITE(cleanup, SAFE_WRITE_ALL, fd, &tnum, 180 sizeof(tnum)); 181 SAFE_CLOSE(cleanup, fd); 182 183 fd = SAFE_OPEN(cleanup, desc->referencefn2, O_RDONLY); 184 SAFE_READ(cleanup, 1, fd, &vnum, sizeof(vnum)); 185 SAFE_CLOSE(cleanup, fd); 186 187 if (tnum == vnum) 188 tst_resm(TPASS, "Test passed"); 189 else 190 tst_resm(TFAIL, 191 "The link file's content isn't as same as the original file's " 192 "although symlinkat returned 0"); 193 } else { 194 tst_resm(TPASS, 195 "symlinkat() returned the expected errno %d: %s", 196 TEST_ERRNO, strerror(TEST_ERRNO)); 197 } 198 } else { 199 tst_resm(TFAIL, 200 TEST_RETURN == 201 0 ? "symlinkat() surprisingly succeeded" : 202 "symlinkat() Failed, errno=%d : %s", TEST_ERRNO, 203 strerror(TEST_ERRNO)); 204 } 205} 206 207static void setup(void) 208{ 209 char *tmp; 210 int fd; 211 212 tst_sig(NOFORK, DEF_HANDLER, cleanup); 213 214 tst_tmpdir(); 215 216 SAFE_MKDIR(cleanup, TEST_DIR1, 0700); 217 SAFE_MKDIR(cleanup, TEST_DIR3, 0700); 218 olddirfd = SAFE_OPEN(cleanup, TEST_DIR1, O_DIRECTORY); 219 deldirfd = SAFE_OPEN(cleanup, TEST_DIR3, O_DIRECTORY); 220 SAFE_RMDIR(cleanup, TEST_DIR3); 221 fd = SAFE_OPEN(cleanup, TEST_DIR1 "/" TEST_FILE1, O_CREAT | O_EXCL, 0600); 222 SAFE_CLOSE(cleanup, fd); 223 224 /* gratuitous memory leak here */ 225 tmp = strdup(dpathname); 226 snprintf(dpathname, sizeof(dpathname), tmp, get_current_dir_name()); 227 228 TEST_PAUSE; 229} 230 231static void cleanup(void) 232{ 233 tst_rmdir(); 234} 235