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[] = 343cf51049SPhilippe Charnier "$Id$"; 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 423cf51049SPhilippe Charnier #include <err.h> 433cf51049SPhilippe Charnier #include <errno.h> 443cf51049SPhilippe Charnier #include <fcntl.h> 453cf51049SPhilippe Charnier #include <signal.h> 46bbeaf6c0SSean Eric Fagan #include <stdio.h> 47bbeaf6c0SSean Eric Fagan #include <stdlib.h> 48bbeaf6c0SSean Eric Fagan #include <string.h> 49bbeaf6c0SSean Eric Fagan #include <unistd.h> 50bbeaf6c0SSean Eric Fagan #include <sys/ioctl.h> 51bbeaf6c0SSean Eric Fagan #include <sys/pioctl.h> 52bbeaf6c0SSean Eric Fagan #include <sys/types.h> 53bbeaf6c0SSean Eric Fagan #include <sys/wait.h> 54bbeaf6c0SSean Eric Fagan 55bbeaf6c0SSean Eric Fagan static int evflags = 0; 56bbeaf6c0SSean Eric Fagan 57bbeaf6c0SSean Eric Fagan /* 58bbeaf6c0SSean Eric Fagan * setup_and_wait() is called to start a process. All it really does 59bbeaf6c0SSean Eric Fagan * is vfork(), set itself up to stop on exec or exit, and then exec 60bbeaf6c0SSean Eric Fagan * the given command. At that point, the child process stops, and 61bbeaf6c0SSean Eric Fagan * the parent can wake up and deal with it. 62bbeaf6c0SSean Eric Fagan */ 63bbeaf6c0SSean Eric Fagan 64bbeaf6c0SSean Eric Fagan int 65bbeaf6c0SSean Eric Fagan setup_and_wait(char *command[]) { 66bbeaf6c0SSean Eric Fagan struct procfs_status pfs; 67bbeaf6c0SSean Eric Fagan char buf[32]; 68bbeaf6c0SSean Eric Fagan int fd; 69bbeaf6c0SSean Eric Fagan int pid; 70bbeaf6c0SSean Eric Fagan int flags; 71bbeaf6c0SSean Eric Fagan 72bbeaf6c0SSean Eric Fagan pid = vfork(); 73bbeaf6c0SSean Eric Fagan if (pid == -1) { 74e09a8fd1SPeter Wemm err(1, "vfork failed"); 75bbeaf6c0SSean Eric Fagan } 76bbeaf6c0SSean Eric Fagan if (pid == 0) { /* Child */ 77bbeaf6c0SSean Eric Fagan int mask = S_EXEC | S_EXIT; 78bbeaf6c0SSean Eric Fagan fd = open("/proc/curproc/mem", O_WRONLY); 79bbeaf6c0SSean Eric Fagan if (fd == -1) 80e09a8fd1SPeter Wemm err(2, "cannot open /proc/curproc/mem"); 81fe41f305SSean Eric Fagan fcntl(fd, F_SETFD, 1); 82d7b7dcbaSSean Eric Fagan if (ioctl(fd, PIOCBIS, mask) == -1) 83e09a8fd1SPeter Wemm err(3, "PIOCBIS"); 8420fa828fSSean Eric Fagan flags = PF_LINGER; 8520fa828fSSean Eric Fagan /* 8620fa828fSSean Eric Fagan * The PF_LINGER flag tells procfs not to wake up the 8720fa828fSSean Eric Fagan * process on last close; normally, this is the behaviour 8820fa828fSSean Eric Fagan * we want. 8920fa828fSSean Eric Fagan */ 90d7b7dcbaSSean Eric Fagan if (ioctl(fd, PIOCSFL, flags) == -1) 913cf51049SPhilippe Charnier warn("cannot set PF_LINGER"); 92bbeaf6c0SSean Eric Fagan execvp(command[0], command); 93bbeaf6c0SSean Eric Fagan mask = ~0; 94d7b7dcbaSSean Eric Fagan ioctl(fd, PIOCBIC, ~0); 95bbeaf6c0SSean Eric Fagan err(4, "execvp %s", command[0]); 96bbeaf6c0SSean Eric Fagan } 97bbeaf6c0SSean Eric Fagan /* Only in the parent here */ 98bbeaf6c0SSean Eric Fagan 99bbeaf6c0SSean Eric Fagan if (waitpid(pid, NULL, WNOHANG) != 0) { 100bbeaf6c0SSean Eric Fagan /* 101bbeaf6c0SSean Eric Fagan * Process exited before it got to us -- meaning the exec failed 102bbeaf6c0SSean Eric Fagan * miserably -- so we just quietly exit. 103bbeaf6c0SSean Eric Fagan */ 104bbeaf6c0SSean Eric Fagan exit(1); 105bbeaf6c0SSean Eric Fagan } 106bbeaf6c0SSean Eric Fagan 107bbeaf6c0SSean Eric Fagan sprintf(buf, "/proc/%d/mem", pid); 108bbeaf6c0SSean Eric Fagan if ((fd = open(buf, O_RDWR)) == -1) 109e09a8fd1SPeter Wemm err(5, "cannot open %s", buf); 110bbeaf6c0SSean Eric Fagan if (ioctl(fd, PIOCWAIT, &pfs) == -1) 111e09a8fd1SPeter Wemm err(6, "PIOCWAIT"); 112bbeaf6c0SSean Eric Fagan if (pfs.why == S_EXIT) { 113bbeaf6c0SSean Eric Fagan fprintf(stderr, "process exited before exec'ing\n"); 114d7b7dcbaSSean Eric Fagan ioctl(fd, PIOCCONT, 0); 115bbeaf6c0SSean Eric Fagan wait(0); 116bbeaf6c0SSean Eric Fagan exit(7); 117bbeaf6c0SSean Eric Fagan } 118bbeaf6c0SSean Eric Fagan close(fd); 119bbeaf6c0SSean Eric Fagan return pid; 120bbeaf6c0SSean Eric Fagan } 121bbeaf6c0SSean Eric Fagan 122bbeaf6c0SSean Eric Fagan /* 123bbeaf6c0SSean Eric Fagan * start_tracing picks up where setup_and_wait() dropped off -- namely, 124bbeaf6c0SSean Eric Fagan * it sets the event mask for the given process id. Called for both 125bbeaf6c0SSean Eric Fagan * monitoring an existing process and when we create our own. 126bbeaf6c0SSean Eric Fagan */ 127bbeaf6c0SSean Eric Fagan 128bbeaf6c0SSean Eric Fagan int 129bbeaf6c0SSean Eric Fagan start_tracing(int pid, int flags) { 130bbeaf6c0SSean Eric Fagan int fd; 131bbeaf6c0SSean Eric Fagan char buf[32]; 132bbeaf6c0SSean Eric Fagan struct procfs_status tmp; 133bbeaf6c0SSean Eric Fagan sprintf(buf, "/proc/%d/mem", pid); 13420fa828fSSean Eric Fagan 135bbeaf6c0SSean Eric Fagan fd = open(buf, O_RDWR); 136bbeaf6c0SSean Eric Fagan if (fd == -1) 137bbeaf6c0SSean Eric Fagan err(8, "cannot open %s", buf); 138bbeaf6c0SSean Eric Fagan 139bbeaf6c0SSean Eric Fagan if (ioctl(fd, PIOCSTATUS, &tmp) == -1) { 140bbeaf6c0SSean Eric Fagan err(10, "cannot get procfs status struct"); 141bbeaf6c0SSean Eric Fagan } 142bbeaf6c0SSean Eric Fagan evflags = tmp.events; 143bbeaf6c0SSean Eric Fagan 144d7b7dcbaSSean Eric Fagan if (ioctl(fd, PIOCBIS, flags) == -1) 145bbeaf6c0SSean Eric Fagan err(9, "cannot set procfs event bit mask"); 146bbeaf6c0SSean Eric Fagan 14720fa828fSSean Eric Fagan /* 14820fa828fSSean Eric Fagan * This clears the PF_LINGER set above in setup_and_wait(); 14920fa828fSSean Eric Fagan * if truss happens to die before this, then the process 15020fa828fSSean Eric Fagan * needs to be woken up via procctl. 15120fa828fSSean Eric Fagan */ 15220fa828fSSean Eric Fagan 153d7b7dcbaSSean Eric Fagan if (ioctl(fd, PIOCSFL, 0) == -1) 1543cf51049SPhilippe Charnier warn("cannot clear PF_LINGER"); 15520fa828fSSean Eric Fagan 156bbeaf6c0SSean Eric Fagan return fd; 157bbeaf6c0SSean Eric Fagan } 158bbeaf6c0SSean Eric Fagan 159bbeaf6c0SSean Eric Fagan /* 160bbeaf6c0SSean Eric Fagan * Restore a process back to it's pre-truss state. 161bbeaf6c0SSean Eric Fagan * Called for SIGINT, SIGTERM, SIGQUIT. This only 162bbeaf6c0SSean Eric Fagan * applies if truss was told to monitor an already-existing 163bbeaf6c0SSean Eric Fagan * process. 164bbeaf6c0SSean Eric Fagan */ 165bbeaf6c0SSean Eric Fagan void 166bbeaf6c0SSean Eric Fagan restore_proc(int signo) { 167bbeaf6c0SSean Eric Fagan extern int Procfd; 168bbeaf6c0SSean Eric Fagan 169d7b7dcbaSSean Eric Fagan ioctl(Procfd, PIOCBIC, ~0); 170bbeaf6c0SSean Eric Fagan if (evflags) 171d7b7dcbaSSean Eric Fagan ioctl(Procfd, PIOCBIS, evflags); 172bbeaf6c0SSean Eric Fagan exit(0); 173bbeaf6c0SSean Eric Fagan } 174