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 #include <limits.h> 30 31 #include "test.h" 32 #include "safe_macros.h" 33 #include "lapi/syscalls.h" 34 35 char *TCID = "process_vm_writev02"; 36 int TST_TOTAL = 1; 37 38 #define PADDING_SIZE 10 39 #define DEFAULT_CHAR 53 40 41 static int sflag; 42 static char *sz_opt; 43 static option_t options[] = { 44 {"s:", &sflag, &sz_opt}, 45 {NULL, NULL, NULL} 46 }; 47 48 static long bufsz; 49 static int pipe_fd[2]; 50 static pid_t pids[2]; 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 SAFE_PIPE(cleanup, pipe_fd); 69 70 /* the start of child_init_and_verify and child_write is 71 * already synchronized via pipe */ 72 pids[0] = fork(); 73 switch (pids[0]) { 74 case -1: 75 tst_brkm(TBROK | TERRNO, cleanup, "fork #0"); 76 case 0: 77 child_init_and_verify(); 78 exit(0); 79 default: 80 break; 81 } 82 83 pids[1] = fork(); 84 switch (pids[1]) { 85 case -1: 86 tst_brkm(TBROK | TERRNO, cleanup, "fork #1"); 87 case 0: 88 child_write(); 89 exit(0); 90 } 91 92 /* wait until child_write writes into 93 * child_init_and_verify's VM */ 94 SAFE_WAITPID(cleanup, pids[1], &status, 0); 95 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) 96 tst_resm(TFAIL, "child 1 returns %d", status); 97 98 /* signal child_init_and_verify to verify its VM now */ 99 TST_SAFE_CHECKPOINT_WAKE(cleanup, 0); 100 101 SAFE_WAITPID(cleanup, pids[0], &status, 0); 102 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) 103 tst_resm(TFAIL, "child 0 returns %d", status); 104 } 105 106 cleanup(); 107 tst_exit(); 108 } 109 110 static void child_init_and_verify(void) 111 { 112 unsigned char *foo; 113 char buf[bufsz]; 114 long i, nr_err; 115 116 foo = SAFE_MALLOC(tst_exit, bufsz); 117 for (i = 0; i < bufsz; i++) 118 foo[i] = DEFAULT_CHAR; 119 tst_resm(TINFO, "child 0: memory allocated."); 120 121 /* passing addr of string "foo" via pipe */ 122 SAFE_CLOSE(tst_exit, pipe_fd[0]); 123 snprintf(buf, bufsz, "%p", foo); 124 SAFE_WRITE(tst_exit, 1, pipe_fd[1], buf, strlen(buf) + 1); 125 SAFE_CLOSE(tst_exit, pipe_fd[1]); 126 127 /* wait until child_write() is done writing to our VM */ 128 TST_SAFE_CHECKPOINT_WAIT(cleanup, 0); 129 130 nr_err = 0; 131 for (i = 0; i < bufsz; i++) { 132 if (foo[i] != i % 256) { 133 #if DEBUG 134 tst_resm(TFAIL, "child 0: expected %i, got %i for " 135 "byte seq %ld", i % 256, foo[i], i); 136 #endif 137 nr_err++; 138 } 139 } 140 if (nr_err) 141 tst_brkm(TFAIL, tst_exit, "child 0: got %ld incorrect bytes.", 142 nr_err); 143 else 144 tst_resm(TPASS, "child 0: all bytes are expected."); 145 } 146 147 static void child_write(void) 148 { 149 unsigned char *lp, *rp; 150 char buf[bufsz]; 151 struct iovec local, remote; 152 long i; 153 154 /* get addr from pipe */ 155 SAFE_CLOSE(tst_exit, pipe_fd[1]); 156 SAFE_READ(tst_exit, 0, pipe_fd[0], buf, bufsz); 157 SAFE_CLOSE(tst_exit, pipe_fd[0]); 158 if (sscanf(buf, "%p", &rp) != 1) 159 tst_brkm(TBROK | TERRNO, tst_exit, "sscanf"); 160 161 lp = SAFE_MALLOC(tst_exit, bufsz + PADDING_SIZE * 2); 162 163 for (i = 0; i < bufsz + PADDING_SIZE * 2; i++) 164 lp[i] = DEFAULT_CHAR; 165 for (i = 0; i < bufsz; i++) 166 lp[i + PADDING_SIZE] = i % 256; 167 168 local.iov_base = lp + PADDING_SIZE; 169 local.iov_len = bufsz; 170 remote.iov_base = rp; 171 remote.iov_len = bufsz; 172 173 tst_resm(TINFO, "child 2: write to the same memory location."); 174 TEST(ltp_syscall(__NR_process_vm_writev, pids[0], &local, 175 1, &remote, 1, 0)); 176 if (TEST_RETURN != bufsz) 177 tst_brkm(TFAIL | TERRNO, tst_exit, "process_vm_readv"); 178 } 179 180 static void setup(void) 181 { 182 tst_require_root(); 183 184 /* Just a sanity check of the existence of syscall */ 185 ltp_syscall(__NR_process_vm_writev, getpid(), NULL, 0, NULL, 0, 0); 186 187 bufsz = 188 sflag ? SAFE_STRTOL(NULL, sz_opt, 1, LONG_MAX - PADDING_SIZE * 2) 189 : 100000; 190 191 tst_tmpdir(); 192 TST_CHECKPOINT_INIT(cleanup); 193 194 TEST_PAUSE; 195 } 196 197 static void cleanup(void) 198 { 199 tst_rmdir(); 200 } 201 202 static void help(void) 203 { 204 printf(" -s NUM Set the size of total buffer size.\n"); 205 } 206