setup.c revision 31573
1/* 2 * Various setup functions for truss. Not the cleanest-written code, 3 * I'm afraid. 4 */ 5/* 6 * $Id: setup.c,v 1.1 1997/12/06 05:23:05 sef Exp $ 7 */ 8 9#include <stdio.h> 10#include <stdlib.h> 11#include <string.h> 12#include <unistd.h> 13#include <errno.h> 14#include <err.h> 15#include <fcntl.h> 16#include <signal.h> 17#include <sys/ioctl.h> 18#include <sys/pioctl.h> 19#include <sys/types.h> 20#include <sys/wait.h> 21 22static int evflags = 0; 23 24/* 25 * setup_and_wait() is called to start a process. All it really does 26 * is vfork(), set itself up to stop on exec or exit, and then exec 27 * the given command. At that point, the child process stops, and 28 * the parent can wake up and deal with it. 29 */ 30 31int 32setup_and_wait(char *command[]) { 33 struct procfs_status pfs; 34 char buf[32]; 35 int fd; 36 int pid; 37 extern char *prog; 38 int flags; 39 40 pid = vfork(); 41 if (pid == -1) { 42 err(1, "vfork failed\n"); 43 } 44 if (pid == 0) { /* Child */ 45 int mask = S_EXEC | S_EXIT; 46 fd = open("/proc/curproc/mem", O_WRONLY); 47 if (fd == -1) 48 err(2, "cannot open /proc/curproc/mem: %s\n", strerror(errno)); 49 fcntl(fd, F_SETFD, 1); 50 if (ioctl(fd, PIOCBIS, &mask) == -1) 51 err(3, "PIOCBIS: %s\n", strerror(errno)); 52 execvp(command[0], command); 53 mask = ~0; 54 ioctl(fd, PIOCBIC, &mask); 55 err(4, "execvp %s", command[0]); 56 } 57 /* Only in the parent here */ 58 59 if (waitpid(pid, NULL, WNOHANG) != 0) { 60 /* 61 * Process exited before it got to us -- meaning the exec failed 62 * miserably -- so we just quietly exit. 63 */ 64 exit(1); 65 } 66 67 sprintf(buf, "/proc/%d/mem", pid); 68 if ((fd = open(buf, O_RDWR)) == -1) 69 err(5, "cannot open %s: %s\n", buf, strerror(errno)); 70 if (ioctl(fd, PIOCWAIT, &pfs) == -1) 71 err(6, "PIOCWAIT: %s\n", strerror(errno)); 72 if (pfs.why == S_EXIT) { 73 int zero = 0; 74 fprintf(stderr, "process exited before exec'ing\n"); 75 ioctl(fd, PIOCCONT, &zero); 76 wait(0); 77 exit(7); 78 } 79 close(fd); 80 return pid; 81} 82 83/* 84 * start_tracing picks up where setup_and_wait() dropped off -- namely, 85 * it sets the event mask for the given process id. Called for both 86 * monitoring an existing process and when we create our own. 87 */ 88 89int 90start_tracing(int pid, int flags) { 91 int fd; 92 char buf[32]; 93 struct procfs_status tmp; 94 sprintf(buf, "/proc/%d/mem", pid); 95 fd = open(buf, O_RDWR); 96 if (fd == -1) 97 err(8, "cannot open %s", buf); 98 99 if (ioctl(fd, PIOCSTATUS, &tmp) == -1) { 100 err(10, "cannot get procfs status struct"); 101 } 102 evflags = tmp.events; 103 104 if (ioctl(fd, PIOCBIS, &flags) == -1) 105 err(9, "cannot set procfs event bit mask"); 106 107 return fd; 108} 109 110/* 111 * Restore a process back to it's pre-truss state. 112 * Called for SIGINT, SIGTERM, SIGQUIT. This only 113 * applies if truss was told to monitor an already-existing 114 * process. 115 */ 116void 117restore_proc(int signo) { 118 extern int Procfd; 119 int i; 120 121 i = ~0; 122 ioctl(Procfd, PIOCBIC, &i); 123 if (evflags) 124 ioctl(Procfd, PIOCBIS, &evflags); 125 exit(0); 126} 127