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