1/* 2 * Copyright (c) International Business Machines Corp., 2001 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 12 * the GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 19/* 20 * Test Description: 21 * Verify that, mmap() succeeds when used to map a file where size of the 22 * file is not a multiple of the page size, the memory area beyond the end 23 * of the file to the end of the page is accessible. Also, verify that 24 * this area is all zeroed and the modifications done to this area are 25 * not written to the file. 26 * 27 * Expected Result: 28 * mmap() should succeed returning the address of the mapped region. 29 * The memory area beyond the end of file to the end of page should be 30 * filled with zero. 31 * The changes beyond the end of file should not get written to the file. 32 * 33 * HISTORY 34 * 07/2001 Ported by Wayne Boyer 35 */ 36#include <stdio.h> 37#include <stdlib.h> 38#include <sys/types.h> 39#include <errno.h> 40#include <unistd.h> 41#include <fcntl.h> 42#include <string.h> 43#include <signal.h> 44#include <stdint.h> 45#include <sys/stat.h> 46#include <sys/mman.h> 47#include <sys/shm.h> 48 49#include "test.h" 50 51#define TEMPFILE "mmapfile" 52 53char *TCID = "mmap01"; 54int TST_TOTAL = 1; 55 56static char *addr; 57static char *dummy; 58static size_t page_sz; 59static size_t file_sz; 60static int fildes; 61static char cmd_buffer[BUFSIZ]; 62 63static void setup(void); 64static void cleanup(void); 65 66int main(int ac, char **av) 67{ 68 int lc; 69 70 tst_parse_opts(ac, av, NULL, NULL); 71 72 setup(); 73 74 for (lc = 0; TEST_LOOPING(lc); lc++) { 75 76 tst_count = 0; 77 78 /* 79 * Call mmap to map the temporary file beyond EOF 80 * with write access. 81 */ 82 errno = 0; 83 addr = mmap(addr, page_sz, PROT_READ | PROT_WRITE, 84 MAP_FILE | MAP_SHARED | MAP_FIXED, fildes, 0); 85 86 /* Check for the return value of mmap() */ 87 if (addr == MAP_FAILED) { 88 tst_resm(TFAIL | TERRNO, "mmap of %s failed", TEMPFILE); 89 continue; 90 } 91 92 /* 93 * Check if mapped memory area beyond EOF are 94 * zeros and changes beyond EOF are not written 95 * to file. 96 */ 97 if (memcmp(&addr[file_sz], dummy, page_sz - file_sz)) { 98 tst_brkm(TFAIL, cleanup, 99 "mapped memory area contains invalid " 100 "data"); 101 } 102 103 /* 104 * Initialize memory beyond file size 105 */ 106 addr[file_sz] = 'X'; 107 addr[file_sz + 1] = 'Y'; 108 addr[file_sz + 2] = 'Z'; 109 110 /* 111 * Synchronize the mapped memory region 112 * with the file. 113 */ 114 if (msync(addr, page_sz, MS_SYNC) != 0) { 115 tst_brkm(TFAIL | TERRNO, cleanup, 116 "failed to synchronize mapped file"); 117 } 118 119 /* 120 * Now, Search for the pattern 'XYZ' in the 121 * temporary file. The pattern should not be 122 * found and the return value should be 1. 123 */ 124 if (system(cmd_buffer) != 0) { 125 tst_resm(TPASS, 126 "Functionality of mmap() successful"); 127 } else { 128 tst_resm(TFAIL, 129 "Specified pattern found in file"); 130 } 131 132 /* Clean up things in case we are looping */ 133 /* Unmap the mapped memory */ 134 if (munmap(addr, page_sz) != 0) { 135 tst_brkm(TFAIL | TERRNO, NULL, "munmap failed"); 136 } 137 } 138 139 cleanup(); 140 tst_exit(); 141} 142 143static void setup(void) 144{ 145 struct stat stat_buf; 146 char Path_name[PATH_MAX]; 147 char write_buf[] = "hello world\n"; 148 149 tst_sig(FORK, DEF_HANDLER, cleanup); 150 151 TEST_PAUSE; 152 153 tst_tmpdir(); 154 155 /* Get the path of temporary file to be created */ 156 if (getcwd(Path_name, sizeof(Path_name)) == NULL) { 157 tst_brkm(TFAIL | TERRNO, cleanup, 158 "getcwd failed to get current working directory"); 159 } 160 161 /* Creat a temporary file used for mapping */ 162 if ((fildes = open(TEMPFILE, O_RDWR | O_CREAT, 0666)) < 0) { 163 tst_brkm(TFAIL, cleanup, "opening %s failed", TEMPFILE); 164 } 165 166 /* Write some data into temporary file */ 167 if (write(fildes, write_buf, strlen(write_buf)) != strlen(write_buf)) { 168 tst_brkm(TFAIL, cleanup, "writing to %s", TEMPFILE); 169 } 170 171 /* Get the size of temporary file */ 172 if (stat(TEMPFILE, &stat_buf) < 0) { 173 tst_brkm(TFAIL | TERRNO, cleanup, "stat of %s failed", 174 TEMPFILE); 175 } 176 file_sz = stat_buf.st_size; 177 178 page_sz = getpagesize(); 179 180 /* Allocate and initialize dummy string of system page size bytes */ 181 if ((dummy = calloc(page_sz, sizeof(char))) == NULL) { 182 tst_brkm(TFAIL, cleanup, "calloc failed (dummy)"); 183 } 184 185 /* 186 * Initialize addr to align with the first segment boundary address 187 * above the break address of the process. 188 */ 189 addr = (void *)(((intptr_t) sbrk(0) + (SHMLBA - 1)) & ~(SHMLBA - 1)); 190 191 /* Set the break address of the process to the addr plus one 192 * page size. 193 */ 194 if ((intptr_t) sbrk(SHMLBA + page_sz) == -1) { 195 tst_brkm(TFAIL | TERRNO, cleanup, 196 "sbrk(SHMLBA + page_sz) failed"); 197 } 198 199 /* Initialize one page region from addr with 'A' */ 200 memset(addr, 'A', page_sz); 201 202 /* Create the command which will be executed in the test */ 203 sprintf(cmd_buffer, "grep XYZ %s/%s > /dev/null", Path_name, TEMPFILE); 204} 205 206static void cleanup(void) 207{ 208 close(fildes); 209 free(dummy); 210 tst_rmdir(); 211} 212