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 "lapi/syscalls.h" 33 34 char *TCID = "process_vm_readv02"; 35 int TST_TOTAL = 1; 36 37 static char *tst_string = "THIS IS A TEST"; 38 static int len; 39 static int pipe_fd[2]; 40 static pid_t pids[2]; 41 42 static void child_alloc(void); 43 static void child_invoke(void); 44 static void setup(void); 45 static void cleanup(void); 46 47 int main(int argc, char **argv) 48 { 49 int lc, status; 50 51 tst_parse_opts(argc, argv, NULL, NULL); 52 53 setup(); 54 for (lc = 0; TEST_LOOPING(lc); lc++) { 55 tst_count = 0; 56 len = strlen(tst_string); 57 58 SAFE_PIPE(cleanup, pipe_fd); 59 60 /* the start of child_alloc and child_invoke is already 61 * synchronized via pipe */ 62 pids[0] = fork(); 63 switch (pids[0]) { 64 case -1: 65 tst_brkm(TBROK | TERRNO, cleanup, "fork #0"); 66 case 0: 67 child_alloc(); 68 exit(0); 69 } 70 71 pids[1] = fork(); 72 switch (pids[1]) { 73 case -1: 74 tst_brkm(TBROK | TERRNO, cleanup, "fork #1"); 75 case 0: 76 child_invoke(); 77 exit(0); 78 } 79 80 /* wait until child_invoke reads from child_alloc's VM */ 81 SAFE_WAITPID(cleanup, pids[1], &status, 0); 82 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) 83 tst_resm(TFAIL, "child 1 returns %d", status); 84 85 /* child_alloc is free to exit now */ 86 TST_SAFE_CHECKPOINT_WAKE(cleanup, 0); 87 88 SAFE_WAITPID(cleanup, pids[0], &status, 0); 89 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) 90 tst_resm(TFAIL, "child 0 returns %d", status); 91 } 92 93 cleanup(); 94 tst_exit(); 95 } 96 97 static void child_alloc(void) 98 { 99 char *foo; 100 char buf[BUFSIZ]; 101 102 foo = SAFE_MALLOC(tst_exit, len + 1); 103 strncpy(foo, tst_string, len); 104 foo[len] = '\0'; 105 tst_resm(TINFO, "child 0: memory allocated and initialized."); 106 107 /* passing addr of string "foo" via pipe */ 108 SAFE_CLOSE(tst_exit, pipe_fd[0]); 109 snprintf(buf, BUFSIZ, "%p", foo); 110 SAFE_WRITE(tst_exit, 1, pipe_fd[1], buf, strlen(buf) + 1); 111 SAFE_CLOSE(tst_exit, pipe_fd[1]); 112 113 /* wait until child_invoke is done reading from our VM */ 114 TST_SAFE_CHECKPOINT_WAIT(cleanup, 0); 115 } 116 117 static void child_invoke(void) 118 { 119 char *lp, *rp; 120 char buf[BUFSIZ]; 121 struct iovec local, remote; 122 123 /* get addr from pipe */ 124 SAFE_CLOSE(tst_exit, pipe_fd[1]); 125 SAFE_READ(tst_exit, 0, pipe_fd[0], buf, BUFSIZ); 126 SAFE_CLOSE(tst_exit, pipe_fd[0]); 127 if (sscanf(buf, "%p", &rp) != 1) 128 tst_brkm(TBROK | TERRNO, tst_exit, "sscanf"); 129 130 lp = SAFE_MALLOC(tst_exit, len + 1); 131 local.iov_base = lp; 132 local.iov_len = len; 133 remote.iov_base = rp; 134 remote.iov_len = len; 135 136 tst_resm(TINFO, "child 1: reading string from same memory location."); 137 TEST(ltp_syscall(__NR_process_vm_readv, pids[0], 138 &local, 1, &remote, 1, 0)); 139 if (TEST_RETURN != len) 140 tst_brkm(TFAIL | TERRNO, tst_exit, "process_vm_readv"); 141 if (strncmp(lp, tst_string, len) != 0) 142 tst_brkm(TFAIL, tst_exit, "child 1: expected string: %s, " 143 "received string: %256s", tst_string, lp); 144 else 145 tst_resm(TPASS, "expected string received."); 146 } 147 148 static void setup(void) 149 { 150 tst_require_root(); 151 152 /* Just a sanity check of the existence of syscall */ 153 ltp_syscall(__NR_process_vm_readv, getpid(), NULL, 0, NULL, 0, 0); 154 155 tst_tmpdir(); 156 TST_CHECKPOINT_INIT(cleanup); 157 158 TEST_PAUSE; 159 } 160 161 static void cleanup(void) 162 { 163 tst_rmdir(); 164 } 165