setup.c revision 31597
1/* 2 * Various setup functions for truss. Not the cleanest-written code, 3 * I'm afraid. 4 */ 5/* 6 * $Id: setup.c,v 1.3 1997/12/06 14:42:58 peter 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"); 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"); 49 fcntl(fd, F_SETFD, 1); 50 if (ioctl(fd, PIOCBIS, &mask) == -1) 51 err(3, "PIOCBIS"); 52 flags = PF_LINGER; 53 /* 54 * The PF_LINGER flag tells procfs not to wake up the 55 * process on last close; normally, this is the behaviour 56 * we want. 57 */ 58 if (ioctl(fd, PIOCSFL, &flags) == -1) 59 perror("cannot set PF_LINGER"); 60 execvp(command[0], command); 61 mask = ~0; 62 ioctl(fd, PIOCBIC, &mask); 63 err(4, "execvp %s", command[0]); 64 } 65 /* Only in the parent here */ 66 67 if (waitpid(pid, NULL, WNOHANG) != 0) { 68 /* 69 * Process exited before it got to us -- meaning the exec failed 70 * miserably -- so we just quietly exit. 71 */ 72 exit(1); 73 } 74 75 sprintf(buf, "/proc/%d/mem", pid); 76 if ((fd = open(buf, O_RDWR)) == -1) 77 err(5, "cannot open %s", buf); 78 if (ioctl(fd, PIOCWAIT, &pfs) == -1) 79 err(6, "PIOCWAIT"); 80 if (pfs.why == S_EXIT) { 81 int zero = 0; 82 fprintf(stderr, "process exited before exec'ing\n"); 83 ioctl(fd, PIOCCONT, &zero); 84 wait(0); 85 exit(7); 86 } 87 close(fd); 88 return pid; 89} 90 91/* 92 * start_tracing picks up where setup_and_wait() dropped off -- namely, 93 * it sets the event mask for the given process id. Called for both 94 * monitoring an existing process and when we create our own. 95 */ 96 97int 98start_tracing(int pid, int flags) { 99 int fd; 100 char buf[32]; 101 struct procfs_status tmp; 102 sprintf(buf, "/proc/%d/mem", pid); 103 104 fd = open(buf, O_RDWR); 105 if (fd == -1) 106 err(8, "cannot open %s", buf); 107 108 if (ioctl(fd, PIOCSTATUS, &tmp) == -1) { 109 err(10, "cannot get procfs status struct"); 110 } 111 evflags = tmp.events; 112 113 if (ioctl(fd, PIOCBIS, &flags) == -1) 114 err(9, "cannot set procfs event bit mask"); 115 116 /* 117 * This clears the PF_LINGER set above in setup_and_wait(); 118 * if truss happens to die before this, then the process 119 * needs to be woken up via procctl. 120 */ 121 122 flags = 0; 123 if (ioctl(fd, PIOCSFL, &flags) == -1) 124 perror("cannot clear PF_LINGER"); 125 126 return fd; 127} 128 129/* 130 * Restore a process back to it's pre-truss state. 131 * Called for SIGINT, SIGTERM, SIGQUIT. This only 132 * applies if truss was told to monitor an already-existing 133 * process. 134 */ 135void 136restore_proc(int signo) { 137 extern int Procfd; 138 int i; 139 140 i = ~0; 141 ioctl(Procfd, PIOCBIC, &i); 142 if (evflags) 143 ioctl(Procfd, PIOCBIS, &evflags); 144 exit(0); 145} 146