1 1.2 msaitoh /* $NetBSD: t_rwtoro.c,v 1.2 2020/05/14 08:34:18 msaitoh Exp $ */ 2 1.1 hannken 3 1.1 hannken /*- 4 1.1 hannken * Copyright (c) 2017 The NetBSD Foundation, Inc. 5 1.1 hannken * All rights reserved. 6 1.1 hannken * 7 1.1 hannken * Redistribution and use in source and binary forms, with or without 8 1.1 hannken * modification, are permitted provided that the following conditions 9 1.1 hannken * are met: 10 1.1 hannken * 1. Redistributions of source code must retain the above copyright 11 1.1 hannken * notice, this list of conditions and the following disclaimer. 12 1.1 hannken * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 hannken * notice, this list of conditions and the following disclaimer in the 14 1.1 hannken * documentation and/or other materials provided with the distribution. 15 1.1 hannken * 16 1.1 hannken * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 1.1 hannken * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 1.1 hannken * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 1.1 hannken * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 1.1 hannken * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 1.1 hannken * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 1.1 hannken * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 1.1 hannken * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 1.1 hannken * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 1.1 hannken * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 1.1 hannken * POSSIBILITY OF SUCH DAMAGE. 27 1.1 hannken */ 28 1.1 hannken 29 1.1 hannken #include <sys/types.h> 30 1.1 hannken #include <sys/mount.h> 31 1.1 hannken #include <sys/stat.h> 32 1.1 hannken #include <sys/statvfs.h> 33 1.1 hannken 34 1.1 hannken #include <atf-c.h> 35 1.1 hannken #include <fcntl.h> 36 1.1 hannken #include <libgen.h> 37 1.1 hannken #include <stdlib.h> 38 1.1 hannken #include <unistd.h> 39 1.1 hannken 40 1.1 hannken #include <rump/rump_syscalls.h> 41 1.1 hannken #include <rump/rump.h> 42 1.1 hannken 43 1.1 hannken #include <miscfs/nullfs/null.h> 44 1.1 hannken #include <fs/tmpfs/tmpfs_args.h> 45 1.1 hannken 46 1.1 hannken #include "../common/h_fsmacros.h" 47 1.1 hannken #include "../../h_macros.h" 48 1.1 hannken 49 1.1 hannken static const char *unsupported = "fs does not support r/o remount"; 50 1.1 hannken static char file_path[MAXPATHLEN]; 51 1.1 hannken static int file_fd; 52 1.1 hannken 53 1.1 hannken /* 54 1.1 hannken * Remount the filesystem read-only and test errno. 55 1.1 hannken * Skip filesystems that don't implement read-write -> read-only. 56 1.1 hannken */ 57 1.1 hannken static void 58 1.1 hannken remount_ro(const atf_tc_t *tc, const char *mp, int expected_errno) 59 1.1 hannken { 60 1.1 hannken int error; 61 1.1 hannken union { 62 1.1 hannken struct tmpfs_args tmpfs; 63 1.1 hannken char data[4095]; 64 1.1 hannken } mount_args; 65 1.1 hannken int mount_args_length; 66 1.1 hannken struct statvfs sbuf; 67 1.1 hannken 68 1.1 hannken if (FSTYPE_ZFS(tc)) 69 1.1 hannken atf_tc_skip("%s", unsupported); 70 1.1 hannken 71 1.1 hannken /* Prepare mount arguments. */ 72 1.1 hannken RL(rump_sys_statvfs1(mp, &sbuf, ST_WAIT)); 73 1.1 hannken mount_args_length = sizeof(mount_args); 74 1.1 hannken memset(&mount_args, 0, mount_args_length); 75 1.1 hannken if (FSTYPE_TMPFS(tc)) 76 1.1 hannken mount_args.tmpfs.ta_version = TMPFS_ARGS_VERSION; 77 1.1 hannken mount_args_length = rump_sys_mount(sbuf.f_fstypename, mp, MNT_GETARGS, 78 1.1 hannken &mount_args, mount_args_length); 79 1.1 hannken ATF_CHECK(mount_args_length >= 0); 80 1.1 hannken 81 1.1 hannken /* Remount and test result. */ 82 1.1 hannken error = rump_sys_mount(sbuf.f_fstypename, mp, MNT_UPDATE | MNT_RDONLY, 83 1.1 hannken &mount_args, mount_args_length); 84 1.1 hannken if (errno == EOPNOTSUPP) 85 1.1 hannken atf_tc_skip("%s", unsupported); 86 1.1 hannken if (expected_errno == 0) 87 1.1 hannken ATF_CHECK(error == 0); 88 1.1 hannken else 89 1.1 hannken ATF_CHECK_ERRNO(expected_errno, error == -1); 90 1.1 hannken } 91 1.1 hannken 92 1.1 hannken static void 93 1.1 hannken open_file_ro(const char *prefix) 94 1.1 hannken { 95 1.1 hannken 96 1.1 hannken snprintf(file_path, sizeof(file_path), "%s/file", prefix); 97 1.1 hannken RL(file_fd = rump_sys_open(file_path, O_CREAT | O_RDWR, 0777)); 98 1.1 hannken RL(rump_sys_close(file_fd)); 99 1.1 hannken RL(file_fd = rump_sys_open(file_path, O_RDONLY)); 100 1.1 hannken } 101 1.1 hannken 102 1.1 hannken static void 103 1.1 hannken open_file_ro_unlink(const char *prefix) 104 1.1 hannken { 105 1.1 hannken 106 1.1 hannken snprintf(file_path, sizeof(file_path), "%s/file", prefix); 107 1.1 hannken RL(file_fd = rump_sys_open(file_path, O_CREAT | O_RDWR, 0777)); 108 1.1 hannken RL(rump_sys_close(file_fd)); 109 1.1 hannken RL(file_fd = rump_sys_open(file_path, O_RDONLY)); 110 1.1 hannken RL(rump_sys_unlink(file_path)); 111 1.1 hannken } 112 1.1 hannken 113 1.1 hannken static void 114 1.1 hannken open_file_rw(const char *prefix) 115 1.1 hannken { 116 1.1 hannken 117 1.1 hannken snprintf(file_path, sizeof(file_path), "%s/file", prefix); 118 1.1 hannken RL(file_fd = rump_sys_open(file_path, O_CREAT | O_RDWR, 0777)); 119 1.1 hannken } 120 1.1 hannken 121 1.1 hannken static void 122 1.1 hannken close_file(const char *unused) 123 1.1 hannken { 124 1.1 hannken 125 1.1 hannken RL(rump_sys_close(file_fd)); 126 1.1 hannken } 127 1.1 hannken 128 1.1 hannken static void 129 1.1 hannken basic_test(const atf_tc_t *tc, const char *mp, int expected_errno, 130 1.1 hannken bool use_layer, void (*pre)(const char *), void (*post)(const char *)) 131 1.1 hannken { 132 1.1 hannken const char *null_mount = "/nullm"; 133 1.1 hannken struct null_args nargs; 134 1.1 hannken 135 1.1 hannken if (use_layer) { 136 1.1 hannken RL(rump_sys_mkdir(null_mount, 0777)); 137 1.1 hannken memset(&nargs, 0, sizeof(nargs)); 138 1.2 msaitoh nargs.nulla_target = __UNCONST(mp); 139 1.1 hannken RL(rump_sys_mount(MOUNT_NULL, null_mount, 0, 140 1.1 hannken &nargs, sizeof(nargs))); 141 1.1 hannken } 142 1.1 hannken if (pre) 143 1.1 hannken (*pre)(use_layer ? null_mount : mp); 144 1.1 hannken remount_ro(tc, mp, expected_errno); 145 1.1 hannken if (post) 146 1.1 hannken (*post)(use_layer ? null_mount : mp); 147 1.1 hannken if (use_layer) 148 1.1 hannken RL(rump_sys_unmount(null_mount, 0)); 149 1.1 hannken } 150 1.1 hannken 151 1.1 hannken static void 152 1.1 hannken noneopen(const atf_tc_t *tc, const char *mp) 153 1.1 hannken { 154 1.1 hannken 155 1.1 hannken basic_test(tc, mp, 0, false, NULL, NULL); 156 1.1 hannken } 157 1.1 hannken 158 1.1 hannken static void 159 1.1 hannken readopen(const atf_tc_t *tc, const char *mp) 160 1.1 hannken { 161 1.1 hannken 162 1.1 hannken basic_test(tc, mp, 0, false, open_file_ro, close_file); 163 1.1 hannken } 164 1.1 hannken 165 1.1 hannken static void 166 1.1 hannken writeopen(const atf_tc_t *tc, const char *mp) 167 1.1 hannken { 168 1.1 hannken 169 1.1 hannken basic_test(tc, mp, EBUSY, false, open_file_rw, close_file); 170 1.1 hannken } 171 1.1 hannken 172 1.1 hannken static void 173 1.1 hannken read_unlinked(const atf_tc_t *tc, const char *mp) 174 1.1 hannken { 175 1.1 hannken 176 1.1 hannken basic_test(tc, mp, EBUSY, false, open_file_ro_unlink, close_file); 177 1.1 hannken } 178 1.1 hannken 179 1.1 hannken static void 180 1.1 hannken layer_noneopen(const atf_tc_t *tc, const char *mp) 181 1.1 hannken { 182 1.1 hannken 183 1.1 hannken basic_test(tc, mp, 0, true, NULL, NULL); 184 1.1 hannken } 185 1.1 hannken 186 1.1 hannken static void 187 1.1 hannken layer_readopen(const atf_tc_t *tc, const char *mp) 188 1.1 hannken { 189 1.1 hannken 190 1.1 hannken basic_test(tc, mp, 0, true, open_file_ro, close_file); 191 1.1 hannken } 192 1.1 hannken 193 1.1 hannken static void 194 1.1 hannken layer_writeopen(const atf_tc_t *tc, const char *mp) 195 1.1 hannken { 196 1.1 hannken 197 1.1 hannken basic_test(tc, mp, EBUSY, true, open_file_rw, close_file); 198 1.1 hannken } 199 1.1 hannken 200 1.1 hannken static void 201 1.1 hannken layer_read_unlinked(const atf_tc_t *tc, const char *mp) 202 1.1 hannken { 203 1.1 hannken 204 1.1 hannken basic_test(tc, mp, EBUSY, true, open_file_ro_unlink, close_file); 205 1.1 hannken } 206 1.1 hannken 207 1.1 hannken ATF_TC_FSAPPLY(noneopen, "remount r/o with no file open"); 208 1.1 hannken ATF_TC_FSAPPLY(readopen, "remount r/o with file open for reading"); 209 1.1 hannken ATF_TC_FSAPPLY(writeopen, "remount r/o with file open for writing"); 210 1.1 hannken ATF_TC_FSAPPLY(read_unlinked, 211 1.1 hannken "remount r/o with unlinked file open for reading"); 212 1.1 hannken ATF_TC_FSAPPLY(layer_noneopen, "remount r/o with no file open on layer"); 213 1.1 hannken ATF_TC_FSAPPLY(layer_readopen, 214 1.1 hannken "remount r/o with file open for reading on layer"); 215 1.1 hannken ATF_TC_FSAPPLY(layer_writeopen, 216 1.1 hannken "remount r/o with file open for writing on layer"); 217 1.1 hannken ATF_TC_FSAPPLY(layer_read_unlinked, 218 1.1 hannken "remount r/o with unlinked file open for reading on layer"); 219 1.1 hannken 220 1.1 hannken ATF_TP_ADD_TCS(tp) 221 1.1 hannken { 222 1.1 hannken 223 1.1 hannken ATF_TP_FSAPPLY(noneopen); 224 1.1 hannken ATF_TP_FSAPPLY(readopen); 225 1.1 hannken ATF_TP_FSAPPLY(writeopen); 226 1.1 hannken ATF_TP_FSAPPLY(read_unlinked); 227 1.1 hannken ATF_TP_FSAPPLY(layer_noneopen); 228 1.1 hannken ATF_TP_FSAPPLY(layer_readopen); 229 1.1 hannken ATF_TP_FSAPPLY(layer_writeopen); 230 1.1 hannken ATF_TP_FSAPPLY(layer_read_unlinked); 231 1.1 hannken 232 1.1 hannken return atf_no_error(); 233 1.1 hannken } 234