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 32b956c13cSPhilippe Charnier #include <sys/cdefs.h> 33b956c13cSPhilippe Charnier __FBSDID("$FreeBSD$"); 343cf51049SPhilippe Charnier 3509d64da3SSean Eric Fagan /* 36bbeaf6c0SSean Eric Fagan * Various setup functions for truss. Not the cleanest-written code, 37bbeaf6c0SSean Eric Fagan * I'm afraid. 38bbeaf6c0SSean Eric Fagan */ 39bbeaf6c0SSean Eric Fagan 40580e0a2bSDag-Erling Smørgrav #include <sys/param.h> 41580e0a2bSDag-Erling Smørgrav #include <sys/ioctl.h> 42580e0a2bSDag-Erling Smørgrav #include <sys/pioctl.h> 43580e0a2bSDag-Erling Smørgrav #include <sys/wait.h> 44580e0a2bSDag-Erling Smørgrav 453cf51049SPhilippe Charnier #include <err.h> 463cf51049SPhilippe Charnier #include <fcntl.h> 473cf51049SPhilippe Charnier #include <signal.h> 48bbeaf6c0SSean Eric Fagan #include <stdio.h> 49bbeaf6c0SSean Eric Fagan #include <stdlib.h> 50bbeaf6c0SSean Eric Fagan #include <string.h> 5137169f94SMatthew N. Dodd #include <time.h> 52bbeaf6c0SSean Eric Fagan #include <unistd.h> 53bbeaf6c0SSean Eric Fagan 54ec0bed25SMatthew N. Dodd #include "truss.h" 551be5d704SMark Murray #include "extern.h" 561be5d704SMark Murray 57bbeaf6c0SSean Eric Fagan static int evflags = 0; 58bbeaf6c0SSean Eric Fagan 59bbeaf6c0SSean Eric Fagan /* 60bbeaf6c0SSean Eric Fagan * setup_and_wait() is called to start a process. All it really does 611fd98d7dSDag-Erling Smørgrav * is fork(), set itself up to stop on exec or exit, and then exec 62bbeaf6c0SSean Eric Fagan * the given command. At that point, the child process stops, and 63bbeaf6c0SSean Eric Fagan * the parent can wake up and deal with it. 64bbeaf6c0SSean Eric Fagan */ 65bbeaf6c0SSean Eric Fagan 66bbeaf6c0SSean Eric Fagan int 67bbeaf6c0SSean Eric Fagan setup_and_wait(char *command[]) { 68bbeaf6c0SSean Eric Fagan struct procfs_status pfs; 69bbeaf6c0SSean Eric Fagan char buf[32]; 70bbeaf6c0SSean Eric Fagan int fd; 71bbeaf6c0SSean Eric Fagan int pid; 72bbeaf6c0SSean Eric Fagan int flags; 73bbeaf6c0SSean Eric Fagan 741fd98d7dSDag-Erling Smørgrav pid = fork(); 75bbeaf6c0SSean Eric Fagan if (pid == -1) { 761fd98d7dSDag-Erling Smørgrav err(1, "fork failed"); 77bbeaf6c0SSean Eric Fagan } 78bbeaf6c0SSean Eric Fagan if (pid == 0) { /* Child */ 79bbeaf6c0SSean Eric Fagan int mask = S_EXEC | S_EXIT; 80bbeaf6c0SSean Eric Fagan fd = open("/proc/curproc/mem", O_WRONLY); 81bbeaf6c0SSean Eric Fagan if (fd == -1) 82e09a8fd1SPeter Wemm err(2, "cannot open /proc/curproc/mem"); 83fe41f305SSean Eric Fagan fcntl(fd, F_SETFD, 1); 84d7b7dcbaSSean Eric Fagan if (ioctl(fd, PIOCBIS, mask) == -1) 85e09a8fd1SPeter Wemm err(3, "PIOCBIS"); 8620fa828fSSean Eric Fagan flags = PF_LINGER; 8720fa828fSSean Eric Fagan /* 8820fa828fSSean Eric Fagan * The PF_LINGER flag tells procfs not to wake up the 8920fa828fSSean Eric Fagan * process on last close; normally, this is the behaviour 9020fa828fSSean Eric Fagan * we want. 9120fa828fSSean Eric Fagan */ 92d7b7dcbaSSean Eric Fagan if (ioctl(fd, PIOCSFL, flags) == -1) 933cf51049SPhilippe Charnier warn("cannot set PF_LINGER"); 94bbeaf6c0SSean Eric Fagan execvp(command[0], command); 95bbeaf6c0SSean Eric Fagan mask = ~0; 96d7b7dcbaSSean Eric Fagan ioctl(fd, PIOCBIC, ~0); 97bbeaf6c0SSean Eric Fagan err(4, "execvp %s", command[0]); 98bbeaf6c0SSean Eric Fagan } 99bbeaf6c0SSean Eric Fagan /* Only in the parent here */ 100bbeaf6c0SSean Eric Fagan 101bbeaf6c0SSean Eric Fagan if (waitpid(pid, NULL, WNOHANG) != 0) { 102bbeaf6c0SSean Eric Fagan /* 103bbeaf6c0SSean Eric Fagan * Process exited before it got to us -- meaning the exec failed 104bbeaf6c0SSean Eric Fagan * miserably -- so we just quietly exit. 105bbeaf6c0SSean Eric Fagan */ 106bbeaf6c0SSean Eric Fagan exit(1); 107bbeaf6c0SSean Eric Fagan } 108bbeaf6c0SSean Eric Fagan 109bbeaf6c0SSean Eric Fagan sprintf(buf, "/proc/%d/mem", pid); 110bbeaf6c0SSean Eric Fagan if ((fd = open(buf, O_RDWR)) == -1) 111e09a8fd1SPeter Wemm err(5, "cannot open %s", buf); 112bbeaf6c0SSean Eric Fagan if (ioctl(fd, PIOCWAIT, &pfs) == -1) 113e09a8fd1SPeter Wemm err(6, "PIOCWAIT"); 114bbeaf6c0SSean Eric Fagan if (pfs.why == S_EXIT) { 115b956c13cSPhilippe Charnier warnx("process exited before exec'ing"); 116d7b7dcbaSSean Eric Fagan ioctl(fd, PIOCCONT, 0); 117bbeaf6c0SSean Eric Fagan wait(0); 118bbeaf6c0SSean Eric Fagan exit(7); 119bbeaf6c0SSean Eric Fagan } 120bbeaf6c0SSean Eric Fagan close(fd); 121bbeaf6c0SSean Eric Fagan return pid; 122bbeaf6c0SSean Eric Fagan } 123bbeaf6c0SSean Eric Fagan 124bbeaf6c0SSean Eric Fagan /* 125bbeaf6c0SSean Eric Fagan * start_tracing picks up where setup_and_wait() dropped off -- namely, 126bbeaf6c0SSean Eric Fagan * it sets the event mask for the given process id. Called for both 127bbeaf6c0SSean Eric Fagan * monitoring an existing process and when we create our own. 128bbeaf6c0SSean Eric Fagan */ 129bbeaf6c0SSean Eric Fagan 130bbeaf6c0SSean Eric Fagan int 131c03bfcc8SMatthew N. Dodd start_tracing(int pid, int eventflags, int flags) { 132bbeaf6c0SSean Eric Fagan int fd; 133bbeaf6c0SSean Eric Fagan char buf[32]; 134bbeaf6c0SSean Eric Fagan struct procfs_status tmp; 135bbeaf6c0SSean Eric Fagan sprintf(buf, "/proc/%d/mem", pid); 13620fa828fSSean Eric Fagan 137bbeaf6c0SSean Eric Fagan fd = open(buf, O_RDWR); 13889361835SSean Eric Fagan if (fd == -1) { 13989361835SSean Eric Fagan /* 14089361835SSean Eric Fagan * The process may have run away before we could start -- this 14189361835SSean Eric Fagan * happens with SUGID programs. So we need to see if it still 14289361835SSean Eric Fagan * exists before we complain bitterly. 14389361835SSean Eric Fagan */ 14489361835SSean Eric Fagan if (kill(pid, 0) == -1) 14589361835SSean Eric Fagan return -1; 146bbeaf6c0SSean Eric Fagan err(8, "cannot open %s", buf); 14789361835SSean Eric Fagan } 148bbeaf6c0SSean Eric Fagan 149bbeaf6c0SSean Eric Fagan if (ioctl(fd, PIOCSTATUS, &tmp) == -1) { 150bbeaf6c0SSean Eric Fagan err(10, "cannot get procfs status struct"); 151bbeaf6c0SSean Eric Fagan } 152bbeaf6c0SSean Eric Fagan evflags = tmp.events; 153bbeaf6c0SSean Eric Fagan 154c03bfcc8SMatthew N. Dodd if (ioctl(fd, PIOCBIS, eventflags) == -1) 155bbeaf6c0SSean Eric Fagan err(9, "cannot set procfs event bit mask"); 156bbeaf6c0SSean Eric Fagan 15720fa828fSSean Eric Fagan /* 15820fa828fSSean Eric Fagan * This clears the PF_LINGER set above in setup_and_wait(); 15920fa828fSSean Eric Fagan * if truss happens to die before this, then the process 16020fa828fSSean Eric Fagan * needs to be woken up via procctl. 16120fa828fSSean Eric Fagan */ 16220fa828fSSean Eric Fagan 163c03bfcc8SMatthew N. Dodd if (ioctl(fd, PIOCSFL, flags) == -1) 1643cf51049SPhilippe Charnier warn("cannot clear PF_LINGER"); 16520fa828fSSean Eric Fagan 166bbeaf6c0SSean Eric Fagan return fd; 167bbeaf6c0SSean Eric Fagan } 168bbeaf6c0SSean Eric Fagan 169bbeaf6c0SSean Eric Fagan /* 170bbeaf6c0SSean Eric Fagan * Restore a process back to it's pre-truss state. 171bbeaf6c0SSean Eric Fagan * Called for SIGINT, SIGTERM, SIGQUIT. This only 172bbeaf6c0SSean Eric Fagan * applies if truss was told to monitor an already-existing 173bbeaf6c0SSean Eric Fagan * process. 174bbeaf6c0SSean Eric Fagan */ 175bbeaf6c0SSean Eric Fagan void 1761be5d704SMark Murray restore_proc(int signo __unused) { 177bbeaf6c0SSean Eric Fagan extern int Procfd; 178bbeaf6c0SSean Eric Fagan 179d7b7dcbaSSean Eric Fagan ioctl(Procfd, PIOCBIC, ~0); 180bbeaf6c0SSean Eric Fagan if (evflags) 181d7b7dcbaSSean Eric Fagan ioctl(Procfd, PIOCBIS, evflags); 182bbeaf6c0SSean Eric Fagan exit(0); 183bbeaf6c0SSean Eric Fagan } 184