1 /* 2 * Copyright (c) International Business Machines Corp., 2012 3 * Copyright (c) Linux Test Project, 2012 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 13 * the GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 20 #define _GNU_SOURCE 21 #include <sys/types.h> 22 #include <sys/uio.h> 23 #include <sys/wait.h> 24 #include <errno.h> 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <string.h> 28 #include <unistd.h> 29 30 #include "test.h" 31 #include "safe_macros.h" 32 #include "process_vm.h" 33 34 char *TCID = "process_vm_writev02"; 35 int TST_TOTAL = 1; 36 37 #define PADDING_SIZE 10 38 #define DEFAULT_CHAR 53 39 40 static int sflag; 41 static char *sz_opt; 42 static option_t options[] = { 43 {"s:", &sflag, &sz_opt}, 44 {NULL, NULL, NULL} 45 }; 46 47 static long bufsz; 48 static int pipe_fd[2]; 49 static pid_t pids[2]; 50 static int semid; 51 52 static void child_init_and_verify(void); 53 static void child_write(void); 54 static void setup(void); 55 static void cleanup(void); 56 static void help(void); 57 58 int main(int argc, char **argv) 59 { 60 int lc, status; 61 62 tst_parse_opts(argc, argv, options, &help); 63 64 setup(); 65 for (lc = 0; TEST_LOOPING(lc); lc++) { 66 tst_count = 0; 67 68 if (pipe(pipe_fd) < 0) 69 tst_brkm(TBROK | TERRNO, cleanup, "pipe"); 70 71 /* the start of child_init_and_verify and child_write is 72 * already synchronized via pipe */ 73 pids[0] = fork(); 74 switch (pids[0]) { 75 case -1: 76 tst_brkm(TBROK | TERRNO, cleanup, "fork #0"); 77 case 0: 78 child_init_and_verify(); 79 exit(0); 80 default: 81 break; 82 } 83 84 pids[1] = fork(); 85 switch (pids[1]) { 86 case -1: 87 tst_brkm(TBROK | TERRNO, cleanup, "fork #1"); 88 case 0: 89 child_write(); 90 exit(0); 91 } 92 93 /* wait until child_write writes into 94 * child_init_and_verify's VM */ 95 if (waitpid(pids[1], &status, 0) == -1) 96 tst_brkm(TBROK | TERRNO, cleanup, "waitpid"); 97 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) 98 tst_resm(TFAIL, "child 1 returns %d", status); 99 100 /* signal child_init_and_verify to verify its VM now */ 101 safe_semop(semid, 0, 1); 102 103 if (waitpid(pids[0], &status, 0) == -1) 104 tst_brkm(TBROK | TERRNO, cleanup, "waitpid"); 105 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) 106 tst_resm(TFAIL, "child 0 returns %d", status); 107 } 108 109 cleanup(); 110 tst_exit(); 111 } 112 113 static void child_init_and_verify(void) 114 { 115 unsigned char *foo; 116 char buf[bufsz]; 117 long i, nr_err; 118 119 foo = SAFE_MALLOC(tst_exit, bufsz); 120 for (i = 0; i < bufsz; i++) 121 foo[i] = DEFAULT_CHAR; 122 tst_resm(TINFO, "child 0: memory allocated."); 123 124 /* passing addr of string "foo" via pipe */ 125 SAFE_CLOSE(tst_exit, pipe_fd[0]); 126 snprintf(buf, bufsz, "%p", foo); 127 SAFE_WRITE(tst_exit, 1, pipe_fd[1], buf, strlen(buf)); 128 SAFE_CLOSE(tst_exit, pipe_fd[1]); 129 130 /* wait until child_write() is done writing to our VM */ 131 safe_semop(semid, 0, -1); 132 133 nr_err = 0; 134 for (i = 0; i < bufsz; i++) { 135 if (foo[i] != i % 256) { 136 #if DEBUG 137 tst_resm(TFAIL, "child 0: expected %i, got %i for " 138 "byte seq %ld", i % 256, foo[i], i); 139 #endif 140 nr_err++; 141 } 142 } 143 if (nr_err) 144 tst_brkm(TFAIL, tst_exit, "child 0: got %ld incorrect bytes.", 145 nr_err); 146 else 147 tst_resm(TPASS, "child 0: all bytes are expected."); 148 } 149 150 static void child_write(void) 151 { 152 unsigned char *lp, *rp; 153 char buf[bufsz]; 154 struct iovec local, remote; 155 long i; 156 157 /* get addr from pipe */ 158 SAFE_CLOSE(tst_exit, pipe_fd[1]); 159 SAFE_READ(tst_exit, 0, pipe_fd[0], buf, bufsz); 160 SAFE_CLOSE(tst_exit, pipe_fd[0]); 161 if (sscanf(buf, "%p", &rp) != 1) 162 tst_brkm(TBROK | TERRNO, tst_exit, "sscanf"); 163 164 lp = SAFE_MALLOC(tst_exit, bufsz + PADDING_SIZE * 2); 165 166 for (i = 0; i < bufsz + PADDING_SIZE * 2; i++) 167 lp[i] = DEFAULT_CHAR; 168 for (i = 0; i < bufsz; i++) 169 lp[i + PADDING_SIZE] = i % 256; 170 171 local.iov_base = lp + PADDING_SIZE; 172 local.iov_len = bufsz; 173 remote.iov_base = rp; 174 remote.iov_len = bufsz; 175 176 tst_resm(TINFO, "child 2: write to the same memory location."); 177 TEST(test_process_vm_writev(pids[0], &local, 1, &remote, 1, 0)); 178 if (TEST_RETURN != bufsz) 179 tst_brkm(TFAIL | TERRNO, tst_exit, "process_vm_readv"); 180 } 181 182 static void setup(void) 183 { 184 tst_require_root(); 185 186 bufsz = 187 sflag ? SAFE_STRTOL(NULL, sz_opt, 1, LONG_MAX - PADDING_SIZE * 2) 188 : 100000; 189 190 #if !defined(__NR_process_vm_readv) 191 tst_brkm(TCONF, NULL, "process_vm_writev does not exist " 192 "on your system"); 193 #endif 194 semid = init_sem(1); 195 196 TEST_PAUSE; 197 } 198 199 static void cleanup(void) 200 { 201 clean_sem(semid); 202 } 203 204 static void help(void) 205 { 206 printf(" -s NUM Set the size of total buffer size.\n"); 207 } 208