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