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