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