1 /* 2 * Copryight 1997 Sean Eric Fagan 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. All advertising materials mentioning features or use of this software 13 * must display the following acknowledgement: 14 * This product includes software developed by Sean Eric Fagan 15 * 4. Neither the name of the author may be used to endorse or promote 16 * products derived from this software without specific prior written 17 * permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * $FreeBSD: src/usr.bin/truss/setup.c,v 1.10.2.2 2002/02/15 11:43:51 des Exp $ 32 * $DragonFly: src/usr.bin/truss/setup.c,v 1.3 2003/11/04 15:34:41 eirikn Exp $ 33 */ 34 35 /* 36 * Various setup functions for truss. Not the cleanest-written code, 37 * I'm afraid. 38 */ 39 40 #include <sys/param.h> 41 #include <sys/ioctl.h> 42 #include <sys/pioctl.h> 43 #include <sys/wait.h> 44 45 #include <err.h> 46 #include <errno.h> 47 #include <fcntl.h> 48 #include <signal.h> 49 #include <stdio.h> 50 #include <stdlib.h> 51 #include <string.h> 52 #include <unistd.h> 53 54 #include "truss.h" 55 #include "extern.h" 56 57 static int evflags = 0; 58 59 /* 60 * setup_and_wait() is called to start a process. All it really does 61 * is fork(), set itself up to stop on exec or exit, and then exec 62 * the given command. At that point, the child process stops, and 63 * the parent can wake up and deal with it. 64 */ 65 66 int 67 setup_and_wait(char *command[]) { 68 struct procfs_status pfs; 69 char *buf; 70 int fd; 71 int pid; 72 int flags; 73 74 pid = fork(); 75 if (pid == -1) { 76 err(1, "fork failed"); 77 } 78 if (pid == 0) { /* Child */ 79 int mask = S_EXEC | S_EXIT; 80 asprintf(&buf, "%s/curproc/mem", procfs_path); 81 if (buf == NULL) 82 err(1, "Out of memory"); 83 fd = open(buf, O_WRONLY); 84 free(buf); 85 if (fd == -1) 86 err(2, "cannot open %s", buf); 87 fcntl(fd, F_SETFD, 1); 88 if (ioctl(fd, PIOCBIS, mask) == -1) 89 err(3, "PIOCBIS"); 90 flags = PF_LINGER; 91 /* 92 * The PF_LINGER flag tells procfs not to wake up the 93 * process on last close; normally, this is the behaviour 94 * we want. 95 */ 96 if (ioctl(fd, PIOCSFL, flags) == -1) 97 warn("cannot set PF_LINGER"); 98 execvp(command[0], command); 99 mask = ~0; 100 ioctl(fd, PIOCBIC, ~0); 101 err(4, "execvp %s", command[0]); 102 } 103 /* Only in the parent here */ 104 105 if (waitpid(pid, NULL, WNOHANG) != 0) { 106 /* 107 * Process exited before it got to us -- meaning the exec failed 108 * miserably -- so we just quietly exit. 109 */ 110 exit(1); 111 } 112 113 asprintf(&buf, "%s/%d/mem", procfs_path, pid); 114 if (buf == NULL) 115 err(1, "Out of memory"); 116 do { 117 fd = open(buf, O_RDWR); 118 } while(fd == -1 && errno == EAGAIN); 119 free(buf); 120 if (fd == -1) 121 err(5, "cannot open %s", buf); 122 if (ioctl(fd, PIOCWAIT, &pfs) == -1) 123 err(6, "PIOCWAIT"); 124 if (pfs.why == S_EXIT) { 125 fprintf(stderr, "process exited before exec'ing\n"); 126 ioctl(fd, PIOCCONT, 0); 127 wait(0); 128 exit(7); 129 } 130 close(fd); 131 return pid; 132 } 133 134 /* 135 * start_tracing picks up where setup_and_wait() dropped off -- namely, 136 * it sets the event mask for the given process id. Called for both 137 * monitoring an existing process and when we create our own. 138 */ 139 140 int 141 start_tracing(int pid, int flags) { 142 int fd; 143 char *buf; 144 struct procfs_status tmp; 145 146 asprintf(&buf, "%s/%d/mem", procfs_path, pid); 147 if (buf == NULL) 148 err(1, "Out of memory"); 149 do { 150 fd = open(buf, O_RDWR); 151 } while(fd == -1 && errno == EAGAIN); 152 free(buf); 153 if (fd == -1) { 154 /* 155 * The process may have run away before we could start -- this 156 * happens with SUGID programs. So we need to see if it still 157 * exists before we complain bitterly. 158 */ 159 if (kill(pid, 0) == -1) 160 return -1; 161 err(8, "cannot open %s", buf); 162 } 163 164 if (ioctl(fd, PIOCSTATUS, &tmp) == -1) { 165 err(10, "cannot get procfs status struct"); 166 } 167 evflags = tmp.events; 168 169 if (ioctl(fd, PIOCBIS, flags) == -1) 170 err(9, "cannot set procfs event bit mask"); 171 172 /* 173 * This clears the PF_LINGER set above in setup_and_wait(); 174 * if truss happens to die before this, then the process 175 * needs to be woken up via procctl. 176 */ 177 178 if (ioctl(fd, PIOCSFL, 0) == -1) 179 warn("cannot clear PF_LINGER"); 180 181 return fd; 182 } 183 184 /* 185 * Restore a process back to it's pre-truss state. 186 * Called for SIGINT, SIGTERM, SIGQUIT. This only 187 * applies if truss was told to monitor an already-existing 188 * process. 189 */ 190 void 191 restore_proc(int signo __unused) { 192 ioctl(Procfd, PIOCBIC, ~0); 193 if (evflags) 194 ioctl(Procfd, PIOCBIS, evflags); 195 exit(0); 196 } 197