1 /* 2 * Copyright (c) 2014 Fujitsu Ltd. 3 * Author: Xiaoguang Wang <wangxg.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 /* 19 * Description: 20 * Verify that, 21 * 1) mknod(2) returns -1 and sets errno to EROFS if pathname refers to 22 * a file on a read-only file system. 23 * 2) mknod(2) returns -1 and sets errno to ELOOP if Too many symbolic 24 * links were encountered in resolving pathname. 25 */ 26 27 #define _GNU_SOURCE 28 29 #include <sys/types.h> 30 #include <fcntl.h> 31 #include <sys/stat.h> 32 #include <stdlib.h> 33 #include <errno.h> 34 #include <string.h> 35 #include <signal.h> 36 #include <sys/mount.h> 37 38 #include "test.h" 39 #include "safe_macros.h" 40 #include "lapi/fcntl.h" 41 #include "mknodat.h" 42 43 static void setup(void); 44 static void cleanup(void); 45 46 #define DIR_MODE (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP| \ 47 S_IXGRP|S_IROTH|S_IXOTH) 48 #define MNT_POINT "mntpoint" 49 50 #define FIFOMODE (S_IFIFO | S_IRUSR | S_IRGRP | S_IROTH) 51 #define FREGMODE (S_IFREG | S_IRUSR | S_IRGRP | S_IROTH) 52 #define SOCKMODE (S_IFSOCK | S_IRUSR | S_IRGRP | S_IROTH) 53 54 static const char *device; 55 static int mount_flag; 56 57 static int dir_fd; 58 static int curfd = AT_FDCWD; 59 60 #define ELOPFILE "/test_eloop" 61 static char elooppathname[sizeof(ELOPFILE) * 43] = "."; 62 63 static struct test_case_t { 64 int *dir_fd; 65 char *pathname; 66 mode_t mode; 67 int exp_errno; 68 } test_cases[] = { 69 { &curfd, "tnode1", FIFOMODE, 0 }, 70 { &curfd, "tnode2", FREGMODE, 0 }, 71 { &curfd, "tnode3", SOCKMODE, 0 }, 72 { &dir_fd, "tnode4", FIFOMODE, EROFS }, 73 { &dir_fd, "tnode5", FREGMODE, EROFS }, 74 { &dir_fd, "tnode6", SOCKMODE, EROFS }, 75 { &curfd, elooppathname, FIFOMODE, ELOOP }, 76 { &curfd, elooppathname, FREGMODE, ELOOP }, 77 { &curfd, elooppathname, SOCKMODE, ELOOP }, 78 }; 79 80 static void mknodat_verify(struct test_case_t *tc); 81 82 char *TCID = "mknodat"; 83 int TST_TOTAL = ARRAY_SIZE(test_cases); 84 85 int main(int ac, char **av) 86 { 87 int lc, 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 mknodat_verify(&test_cases[i]); 98 } 99 100 cleanup(); 101 tst_exit(); 102 } 103 104 static void setup(void) 105 { 106 int i; 107 const char *fs_type; 108 109 if (tst_kvercmp(2, 6, 16) < 0) { 110 tst_brkm(TCONF, NULL, "This test can only run on kernels " 111 "that are 2.6.16 and higher"); 112 } 113 114 tst_require_root(); 115 116 tst_sig(NOFORK, DEF_HANDLER, cleanup); 117 118 tst_tmpdir(); 119 120 fs_type = tst_dev_fs_type(); 121 device = tst_acquire_device(cleanup); 122 123 if (!device) 124 tst_brkm(TCONF, cleanup, "Failed to acquire device"); 125 126 tst_mkfs(cleanup, device, fs_type, NULL, NULL); 127 128 TEST_PAUSE; 129 130 /* 131 * mount a read-only file system for EROFS test 132 */ 133 SAFE_MKDIR(cleanup, MNT_POINT, DIR_MODE); 134 if (mount(device, MNT_POINT, fs_type, MS_RDONLY, NULL) < 0) { 135 tst_brkm(TBROK | TERRNO, cleanup, 136 "mount device:%s failed", device); 137 } 138 mount_flag = 1; 139 dir_fd = SAFE_OPEN(cleanup, MNT_POINT, O_DIRECTORY); 140 141 /* 142 * NOTE: the ELOOP test is written based on that the consecutive 143 * symlinks limits in kernel is hardwired to 40. 144 */ 145 SAFE_MKDIR(cleanup, "test_eloop", DIR_MODE); 146 SAFE_SYMLINK(cleanup, "../test_eloop", "test_eloop/test_eloop"); 147 for (i = 0; i < 43; i++) 148 strcat(elooppathname, ELOPFILE); 149 } 150 151 static void mknodat_verify(struct test_case_t *tc) 152 { 153 int fd = *(tc->dir_fd); 154 char *pathname = tc->pathname; 155 mode_t mode = tc->mode; 156 157 TEST(mknodat(fd, pathname, mode, 0)); 158 159 if (TEST_ERRNO == tc->exp_errno) { 160 tst_resm(TPASS | TTERRNO, 161 "mknodat() returned the expected value"); 162 } else { 163 tst_resm(TFAIL | TTERRNO, 164 "mknodat() got unexpected return value; expected: " 165 "%d - %s", tc->exp_errno, 166 strerror(tc->exp_errno)); 167 } 168 169 if (TEST_ERRNO == 0 && 170 ltp_syscall(__NR_unlinkat, fd, pathname, 0) < 0) { 171 tst_brkm(TBROK | TERRNO, cleanup, "unlinkat(%d, %s) " 172 "failed.", fd, pathname); 173 } 174 } 175 176 static void cleanup(void) 177 { 178 if (dir_fd > 0 && close(dir_fd) < 0) 179 tst_resm(TWARN | TERRNO, "close(%d) failed", dir_fd); 180 if (mount_flag && tst_umount(MNT_POINT) < 0) 181 tst_resm(TWARN | TERRNO, "umount device:%s failed", device); 182 183 if (device) 184 tst_release_device(device); 185 186 tst_rmdir(); 187 } 188