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 32 #ifndef lint 33 static const char rcsid[] = 34 "$Id: setup.c,v 1.7 1998/01/05 07:30:25 charnier Exp $"; 35 #endif /* not lint */ 36 37 /* 38 * Various setup functions for truss. Not the cleanest-written code, 39 * I'm afraid. 40 */ 41 42 #include <err.h> 43 #include <errno.h> 44 #include <fcntl.h> 45 #include <signal.h> 46 #include <stdio.h> 47 #include <stdlib.h> 48 #include <string.h> 49 #include <unistd.h> 50 #include <sys/ioctl.h> 51 #include <sys/pioctl.h> 52 #include <sys/types.h> 53 #include <sys/wait.h> 54 55 static int evflags = 0; 56 57 /* 58 * setup_and_wait() is called to start a process. All it really does 59 * is fork(), set itself up to stop on exec or exit, and then exec 60 * the given command. At that point, the child process stops, and 61 * the parent can wake up and deal with it. 62 */ 63 64 int 65 setup_and_wait(char *command[]) { 66 struct procfs_status pfs; 67 char buf[32]; 68 int fd; 69 int pid; 70 int flags; 71 72 pid = fork(); 73 if (pid == -1) { 74 err(1, "fork failed"); 75 } 76 if (pid == 0) { /* Child */ 77 int mask = S_EXEC | S_EXIT; 78 fd = open("/proc/curproc/mem", O_WRONLY); 79 if (fd == -1) 80 err(2, "cannot open /proc/curproc/mem"); 81 fcntl(fd, F_SETFD, 1); 82 if (ioctl(fd, PIOCBIS, mask) == -1) 83 err(3, "PIOCBIS"); 84 flags = PF_LINGER; 85 /* 86 * The PF_LINGER flag tells procfs not to wake up the 87 * process on last close; normally, this is the behaviour 88 * we want. 89 */ 90 if (ioctl(fd, PIOCSFL, flags) == -1) 91 warn("cannot set PF_LINGER"); 92 execvp(command[0], command); 93 mask = ~0; 94 ioctl(fd, PIOCBIC, ~0); 95 err(4, "execvp %s", command[0]); 96 } 97 /* Only in the parent here */ 98 99 if (waitpid(pid, NULL, WNOHANG) != 0) { 100 /* 101 * Process exited before it got to us -- meaning the exec failed 102 * miserably -- so we just quietly exit. 103 */ 104 exit(1); 105 } 106 107 sprintf(buf, "/proc/%d/mem", pid); 108 if ((fd = open(buf, O_RDWR)) == -1) 109 err(5, "cannot open %s", buf); 110 if (ioctl(fd, PIOCWAIT, &pfs) == -1) 111 err(6, "PIOCWAIT"); 112 if (pfs.why == S_EXIT) { 113 fprintf(stderr, "process exited before exec'ing\n"); 114 ioctl(fd, PIOCCONT, 0); 115 wait(0); 116 exit(7); 117 } 118 close(fd); 119 return pid; 120 } 121 122 /* 123 * start_tracing picks up where setup_and_wait() dropped off -- namely, 124 * it sets the event mask for the given process id. Called for both 125 * monitoring an existing process and when we create our own. 126 */ 127 128 int 129 start_tracing(int pid, int flags) { 130 int fd; 131 char buf[32]; 132 struct procfs_status tmp; 133 sprintf(buf, "/proc/%d/mem", pid); 134 135 fd = open(buf, O_RDWR); 136 if (fd == -1) 137 err(8, "cannot open %s", buf); 138 139 if (ioctl(fd, PIOCSTATUS, &tmp) == -1) { 140 err(10, "cannot get procfs status struct"); 141 } 142 evflags = tmp.events; 143 144 if (ioctl(fd, PIOCBIS, flags) == -1) 145 err(9, "cannot set procfs event bit mask"); 146 147 /* 148 * This clears the PF_LINGER set above in setup_and_wait(); 149 * if truss happens to die before this, then the process 150 * needs to be woken up via procctl. 151 */ 152 153 if (ioctl(fd, PIOCSFL, 0) == -1) 154 warn("cannot clear PF_LINGER"); 155 156 return fd; 157 } 158 159 /* 160 * Restore a process back to it's pre-truss state. 161 * Called for SIGINT, SIGTERM, SIGQUIT. This only 162 * applies if truss was told to monitor an already-existing 163 * process. 164 */ 165 void 166 restore_proc(int signo) { 167 extern int Procfd; 168 169 ioctl(Procfd, PIOCBIC, ~0); 170 if (evflags) 171 ioctl(Procfd, PIOCBIS, evflags); 172 exit(0); 173 } 174