1 /* $OpenBSD: t_msync.c,v 1.1.1.1 2019/11/19 19:57:04 bluhm Exp $ */ 2 /* $NetBSD: t_msync.c,v 1.3 2017/01/14 20:52:42 christos Exp $ */ 3 4 /*- 5 * Copyright (c) 2011 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Jukka Ruohonen. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include "macros.h" 34 35 #include <sys/cdefs.h> 36 __RCSID("$NetBSD: t_msync.c,v 1.3 2017/01/14 20:52:42 christos Exp $"); 37 38 #include <sys/mman.h> 39 40 #include "atf-c.h" 41 #include <errno.h> 42 #include <fcntl.h> 43 #include <limits.h> 44 #include <stdlib.h> 45 #include <string.h> 46 #include <unistd.h> 47 48 static long page = 0; 49 static const off_t off = 512; 50 static const char path[] = "msync"; 51 52 static const char *msync_sync(const char *, int); 53 54 static const char * 55 msync_sync(const char *garbage, int flags) 56 { 57 char *buf, *map = MAP_FAILED; 58 const char *str = NULL; 59 size_t len; 60 int fd, rv; 61 62 /* 63 * Create a temporary file, write 64 * one page to it, and map the file. 65 */ 66 buf = malloc(page); 67 68 if (buf == NULL) 69 return NULL; 70 71 memset(buf, 'x', page); 72 73 fd = open(path, O_RDWR | O_CREAT, 0700); 74 75 if (fd < 0) { 76 free(buf); 77 return "failed to open"; 78 } 79 80 ATF_REQUIRE_MSG(write(fd, buf, page) != -1, "write(2) failed: %s", 81 strerror(errno)); 82 83 map = mmap(NULL, page, PROT_READ | PROT_WRITE, MAP_FILE|MAP_PRIVATE, 84 fd, 0); 85 86 if (map == MAP_FAILED) { 87 str = "failed to map"; 88 goto out; 89 } 90 91 /* 92 * Seek to an arbitrary offset and 93 * write garbage to this position. 94 */ 95 if (lseek(fd, off, SEEK_SET) != off) { 96 str = "failed to seek"; 97 goto out; 98 } 99 100 len = strlen(garbage); 101 rv = write(fd, garbage, len); 102 103 if (rv != (ssize_t)len) { 104 str = "failed to write garbage"; 105 goto out; 106 } 107 108 /* 109 * Synchronize the mapping and verify 110 * that garbage is at the given offset. 111 */ 112 if (msync(map, page, flags) != 0) { 113 str = "failed to msync"; 114 goto out; 115 } 116 117 if (memcmp(map + off, garbage, len) != 0) { 118 str = "msync did not synchronize"; 119 goto out; 120 } 121 122 out: 123 free(buf); 124 125 (void)close(fd); 126 (void)unlink(path); 127 128 if (map != MAP_FAILED) 129 (void)munmap(map, page); 130 131 return str; 132 } 133 134 ATF_TC(msync_async); 135 ATF_TC_HEAD(msync_async, tc) 136 { 137 atf_tc_set_md_var(tc, "descr", "Test of msync(2), MS_ASYNC"); 138 } 139 140 ATF_TC_BODY(msync_async, tc) 141 { 142 const char *str; 143 144 str = msync_sync("garbage", MS_ASYNC); 145 146 if (str != NULL) 147 atf_tc_fail("%s", str); 148 } 149 150 ATF_TC(msync_err); 151 ATF_TC_HEAD(msync_err, tc) 152 { 153 atf_tc_set_md_var(tc, "descr", "Test error conditions in msync(2)"); 154 } 155 156 ATF_TC_BODY(msync_err, tc) 157 { 158 159 char *map = MAP_FAILED; 160 161 /* 162 * Test that invalid flags error out. 163 */ 164 ATF_REQUIRE(msync_sync("error", -1) != NULL); 165 ATF_REQUIRE(msync_sync("error", INT_MAX) != NULL); 166 167 errno = 0; 168 169 /* 170 * Map a page and then unmap to get an unmapped address. 171 */ 172 map = mmap(NULL, page, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, 173 -1, 0); 174 ATF_REQUIRE(map != MAP_FAILED); 175 176 (void)munmap(map, page); 177 178 ATF_REQUIRE(msync(map, page, MS_SYNC) != 0); 179 ATF_REQUIRE(errno == EFAULT); 180 } 181 182 ATF_TC(msync_invalidate); 183 ATF_TC_HEAD(msync_invalidate, tc) 184 { 185 atf_tc_set_md_var(tc, "descr", "Test of msync(2), MS_INVALIDATE"); 186 } 187 188 ATF_TC_BODY(msync_invalidate, tc) 189 { 190 const char *str; 191 192 str = msync_sync("garbage", MS_INVALIDATE); 193 194 if (str != NULL) 195 atf_tc_fail("%s", str); 196 } 197 198 ATF_TC(msync_sync); 199 ATF_TC_HEAD(msync_sync, tc) 200 { 201 atf_tc_set_md_var(tc, "descr", "Test of msync(2), MS_SYNC"); 202 } 203 204 ATF_TC_BODY(msync_sync, tc) 205 { 206 const char *str; 207 208 str = msync_sync("garbage", MS_SYNC); 209 210 if (str != NULL) 211 atf_tc_fail("%s", str); 212 } 213 214 ATF_TP_ADD_TCS(tp) 215 { 216 217 page = sysconf(_SC_PAGESIZE); 218 219 ATF_REQUIRE(page >= 0); 220 ATF_REQUIRE(page > off); 221 222 ATF_TP_ADD_TC(tp, msync_async); 223 ATF_TP_ADD_TC(tp, msync_err); 224 ATF_TP_ADD_TC(tp, msync_invalidate); 225 ATF_TP_ADD_TC(tp, msync_sync); 226 227 return atf_no_error(); 228 } 229