1bbeaf6c0SSean Eric Fagan /* 209d64da3SSean Eric Fagan * Copryight 1997 Sean Eric Fagan 309d64da3SSean Eric Fagan * 409d64da3SSean Eric Fagan * Redistribution and use in source and binary forms, with or without 509d64da3SSean Eric Fagan * modification, are permitted provided that the following conditions 609d64da3SSean Eric Fagan * are met: 709d64da3SSean Eric Fagan * 1. Redistributions of source code must retain the above copyright 809d64da3SSean Eric Fagan * notice, this list of conditions and the following disclaimer. 909d64da3SSean Eric Fagan * 2. Redistributions in binary form must reproduce the above copyright 1009d64da3SSean Eric Fagan * notice, this list of conditions and the following disclaimer in the 1109d64da3SSean Eric Fagan * documentation and/or other materials provided with the distribution. 1209d64da3SSean Eric Fagan * 3. All advertising materials mentioning features or use of this software 1309d64da3SSean Eric Fagan * must display the following acknowledgement: 1409d64da3SSean Eric Fagan * This product includes software developed by Sean Eric Fagan 1509d64da3SSean Eric Fagan * 4. Neither the name of the author may be used to endorse or promote 1609d64da3SSean Eric Fagan * products derived from this software without specific prior written 1709d64da3SSean Eric Fagan * permission. 1809d64da3SSean Eric Fagan * 1909d64da3SSean Eric Fagan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2009d64da3SSean Eric Fagan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2109d64da3SSean Eric Fagan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2209d64da3SSean Eric Fagan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2309d64da3SSean Eric Fagan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2409d64da3SSean Eric Fagan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2509d64da3SSean Eric Fagan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2609d64da3SSean Eric Fagan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2709d64da3SSean Eric Fagan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2809d64da3SSean Eric Fagan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2909d64da3SSean Eric Fagan * SUCH DAMAGE. 3009d64da3SSean Eric Fagan */ 3109d64da3SSean Eric Fagan 323cf51049SPhilippe Charnier #ifndef lint 333cf51049SPhilippe Charnier static const char rcsid[] = 34c3aac50fSPeter Wemm "$FreeBSD$"; 353cf51049SPhilippe Charnier #endif /* not lint */ 363cf51049SPhilippe Charnier 3709d64da3SSean Eric Fagan /* 38bbeaf6c0SSean Eric Fagan * Various setup functions for truss. Not the cleanest-written code, 39bbeaf6c0SSean Eric Fagan * I'm afraid. 40bbeaf6c0SSean Eric Fagan */ 41bbeaf6c0SSean Eric Fagan 42580e0a2bSDag-Erling Smørgrav #include <sys/param.h> 43580e0a2bSDag-Erling Smørgrav #include <sys/ioctl.h> 44580e0a2bSDag-Erling Smørgrav #include <sys/pioctl.h> 45580e0a2bSDag-Erling Smørgrav #include <sys/wait.h> 46580e0a2bSDag-Erling Smørgrav 473cf51049SPhilippe Charnier #include <err.h> 483cf51049SPhilippe Charnier #include <errno.h> 493cf51049SPhilippe Charnier #include <fcntl.h> 503cf51049SPhilippe Charnier #include <signal.h> 51bbeaf6c0SSean Eric Fagan #include <stdio.h> 52bbeaf6c0SSean Eric Fagan #include <stdlib.h> 53bbeaf6c0SSean Eric Fagan #include <string.h> 54bbeaf6c0SSean Eric Fagan #include <unistd.h> 55bbeaf6c0SSean Eric Fagan 56ec0bed25SMatthew N. Dodd #include "truss.h" 571be5d704SMark Murray #include "extern.h" 581be5d704SMark Murray 59bbeaf6c0SSean Eric Fagan static int evflags = 0; 60bbeaf6c0SSean Eric Fagan 61bbeaf6c0SSean Eric Fagan /* 62bbeaf6c0SSean Eric Fagan * setup_and_wait() is called to start a process. All it really does 631fd98d7dSDag-Erling Smørgrav * is fork(), set itself up to stop on exec or exit, and then exec 64bbeaf6c0SSean Eric Fagan * the given command. At that point, the child process stops, and 65bbeaf6c0SSean Eric Fagan * the parent can wake up and deal with it. 66bbeaf6c0SSean Eric Fagan */ 67bbeaf6c0SSean Eric Fagan 68bbeaf6c0SSean Eric Fagan int 69bbeaf6c0SSean Eric Fagan setup_and_wait(char *command[]) { 70bbeaf6c0SSean Eric Fagan struct procfs_status pfs; 71bbeaf6c0SSean Eric Fagan char buf[32]; 72bbeaf6c0SSean Eric Fagan int fd; 73bbeaf6c0SSean Eric Fagan int pid; 74bbeaf6c0SSean Eric Fagan int flags; 75bbeaf6c0SSean Eric Fagan 761fd98d7dSDag-Erling Smørgrav pid = fork(); 77bbeaf6c0SSean Eric Fagan if (pid == -1) { 781fd98d7dSDag-Erling Smørgrav err(1, "fork failed"); 79bbeaf6c0SSean Eric Fagan } 80bbeaf6c0SSean Eric Fagan if (pid == 0) { /* Child */ 81bbeaf6c0SSean Eric Fagan int mask = S_EXEC | S_EXIT; 82bbeaf6c0SSean Eric Fagan fd = open("/proc/curproc/mem", O_WRONLY); 83bbeaf6c0SSean Eric Fagan if (fd == -1) 84e09a8fd1SPeter Wemm err(2, "cannot open /proc/curproc/mem"); 85fe41f305SSean Eric Fagan fcntl(fd, F_SETFD, 1); 86d7b7dcbaSSean Eric Fagan if (ioctl(fd, PIOCBIS, mask) == -1) 87e09a8fd1SPeter Wemm err(3, "PIOCBIS"); 8820fa828fSSean Eric Fagan flags = PF_LINGER; 8920fa828fSSean Eric Fagan /* 9020fa828fSSean Eric Fagan * The PF_LINGER flag tells procfs not to wake up the 9120fa828fSSean Eric Fagan * process on last close; normally, this is the behaviour 9220fa828fSSean Eric Fagan * we want. 9320fa828fSSean Eric Fagan */ 94d7b7dcbaSSean Eric Fagan if (ioctl(fd, PIOCSFL, flags) == -1) 953cf51049SPhilippe Charnier warn("cannot set PF_LINGER"); 96bbeaf6c0SSean Eric Fagan execvp(command[0], command); 97bbeaf6c0SSean Eric Fagan mask = ~0; 98d7b7dcbaSSean Eric Fagan ioctl(fd, PIOCBIC, ~0); 99bbeaf6c0SSean Eric Fagan err(4, "execvp %s", command[0]); 100bbeaf6c0SSean Eric Fagan } 101bbeaf6c0SSean Eric Fagan /* Only in the parent here */ 102bbeaf6c0SSean Eric Fagan 103bbeaf6c0SSean Eric Fagan if (waitpid(pid, NULL, WNOHANG) != 0) { 104bbeaf6c0SSean Eric Fagan /* 105bbeaf6c0SSean Eric Fagan * Process exited before it got to us -- meaning the exec failed 106bbeaf6c0SSean Eric Fagan * miserably -- so we just quietly exit. 107bbeaf6c0SSean Eric Fagan */ 108bbeaf6c0SSean Eric Fagan exit(1); 109bbeaf6c0SSean Eric Fagan } 110bbeaf6c0SSean Eric Fagan 111bbeaf6c0SSean Eric Fagan sprintf(buf, "/proc/%d/mem", pid); 112bbeaf6c0SSean Eric Fagan if ((fd = open(buf, O_RDWR)) == -1) 113e09a8fd1SPeter Wemm err(5, "cannot open %s", buf); 114bbeaf6c0SSean Eric Fagan if (ioctl(fd, PIOCWAIT, &pfs) == -1) 115e09a8fd1SPeter Wemm err(6, "PIOCWAIT"); 116bbeaf6c0SSean Eric Fagan if (pfs.why == S_EXIT) { 117bbeaf6c0SSean Eric Fagan fprintf(stderr, "process exited before exec'ing\n"); 118d7b7dcbaSSean Eric Fagan ioctl(fd, PIOCCONT, 0); 119bbeaf6c0SSean Eric Fagan wait(0); 120bbeaf6c0SSean Eric Fagan exit(7); 121bbeaf6c0SSean Eric Fagan } 122bbeaf6c0SSean Eric Fagan close(fd); 123bbeaf6c0SSean Eric Fagan return pid; 124bbeaf6c0SSean Eric Fagan } 125bbeaf6c0SSean Eric Fagan 126bbeaf6c0SSean Eric Fagan /* 127bbeaf6c0SSean Eric Fagan * start_tracing picks up where setup_and_wait() dropped off -- namely, 128bbeaf6c0SSean Eric Fagan * it sets the event mask for the given process id. Called for both 129bbeaf6c0SSean Eric Fagan * monitoring an existing process and when we create our own. 130bbeaf6c0SSean Eric Fagan */ 131bbeaf6c0SSean Eric Fagan 132bbeaf6c0SSean Eric Fagan int 133bbeaf6c0SSean Eric Fagan start_tracing(int pid, int flags) { 134bbeaf6c0SSean Eric Fagan int fd; 135bbeaf6c0SSean Eric Fagan char buf[32]; 136bbeaf6c0SSean Eric Fagan struct procfs_status tmp; 137bbeaf6c0SSean Eric Fagan sprintf(buf, "/proc/%d/mem", pid); 13820fa828fSSean Eric Fagan 139bbeaf6c0SSean Eric Fagan fd = open(buf, O_RDWR); 14089361835SSean Eric Fagan if (fd == -1) { 14189361835SSean Eric Fagan /* 14289361835SSean Eric Fagan * The process may have run away before we could start -- this 14389361835SSean Eric Fagan * happens with SUGID programs. So we need to see if it still 14489361835SSean Eric Fagan * exists before we complain bitterly. 14589361835SSean Eric Fagan */ 14689361835SSean Eric Fagan if (kill(pid, 0) == -1) 14789361835SSean Eric Fagan return -1; 148bbeaf6c0SSean Eric Fagan err(8, "cannot open %s", buf); 14989361835SSean Eric Fagan } 150bbeaf6c0SSean Eric Fagan 151bbeaf6c0SSean Eric Fagan if (ioctl(fd, PIOCSTATUS, &tmp) == -1) { 152bbeaf6c0SSean Eric Fagan err(10, "cannot get procfs status struct"); 153bbeaf6c0SSean Eric Fagan } 154bbeaf6c0SSean Eric Fagan evflags = tmp.events; 155bbeaf6c0SSean Eric Fagan 156d7b7dcbaSSean Eric Fagan if (ioctl(fd, PIOCBIS, flags) == -1) 157bbeaf6c0SSean Eric Fagan err(9, "cannot set procfs event bit mask"); 158bbeaf6c0SSean Eric Fagan 15920fa828fSSean Eric Fagan /* 16020fa828fSSean Eric Fagan * This clears the PF_LINGER set above in setup_and_wait(); 16120fa828fSSean Eric Fagan * if truss happens to die before this, then the process 16220fa828fSSean Eric Fagan * needs to be woken up via procctl. 16320fa828fSSean Eric Fagan */ 16420fa828fSSean Eric Fagan 165d7b7dcbaSSean Eric Fagan if (ioctl(fd, PIOCSFL, 0) == -1) 1663cf51049SPhilippe Charnier warn("cannot clear PF_LINGER"); 16720fa828fSSean Eric Fagan 168bbeaf6c0SSean Eric Fagan return fd; 169bbeaf6c0SSean Eric Fagan } 170bbeaf6c0SSean Eric Fagan 171bbeaf6c0SSean Eric Fagan /* 172bbeaf6c0SSean Eric Fagan * Restore a process back to it's pre-truss state. 173bbeaf6c0SSean Eric Fagan * Called for SIGINT, SIGTERM, SIGQUIT. This only 174bbeaf6c0SSean Eric Fagan * applies if truss was told to monitor an already-existing 175bbeaf6c0SSean Eric Fagan * process. 176bbeaf6c0SSean Eric Fagan */ 177bbeaf6c0SSean Eric Fagan void 1781be5d704SMark Murray restore_proc(int signo __unused) { 179bbeaf6c0SSean Eric Fagan extern int Procfd; 180bbeaf6c0SSean Eric Fagan 181d7b7dcbaSSean Eric Fagan ioctl(Procfd, PIOCBIC, ~0); 182bbeaf6c0SSean Eric Fagan if (evflags) 183d7b7dcbaSSean Eric Fagan ioctl(Procfd, PIOCBIS, evflags); 184bbeaf6c0SSean Eric Fagan exit(0); 185bbeaf6c0SSean Eric Fagan } 186