]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/ratrace.c
merge
[plan9front.git] / sys / src / cmd / ratrace.c
1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4
5 enum {
6         Stacksize       = 8*1024,
7 };
8
9 Channel *out;
10 Channel *quit;
11 Channel *forkc;
12 int readers = 1;
13
14 typedef struct Msg Msg;
15 struct Msg {
16         int     pid;
17         char    buf[8*1024];
18 };
19
20 typedef struct Reader Reader;
21 struct Reader {
22         int     pid;
23
24         int     tfd;
25         int     cfd;
26
27         Msg*    msg;
28 };
29
30 void
31 die(Reader *r)
32 {
33         Msg *s;
34
35         s = r->msg;
36         snprint(s->buf, sizeof(s->buf), " = %r\n");
37         s->pid = r->pid;
38         sendp(quit, s);
39         if(r->tfd >= 0)
40                 close(r->tfd);
41         if(r->cfd >= 0)
42                 close(r->cfd);
43         threadexits(nil);
44 }
45
46 void
47 cwrite(Reader *r, char *cmd)
48 {
49         if (write(r->cfd, cmd, strlen(cmd)) < 0)
50                 die(r);
51 }
52
53 void
54 reader(void *v)
55 {
56         int forking = 0, newpid;
57         Reader r;
58         Msg *s;
59
60         r.pid = (int)(uintptr)v;
61         r.tfd = r.cfd = -1;
62
63         r.msg = s = mallocz(sizeof(Msg), 1);
64         snprint(s->buf, sizeof(s->buf), "/proc/%d/ctl", r.pid);
65         if ((r.cfd = open(s->buf, OWRITE)) < 0)
66                 die(&r);
67         snprint(s->buf, sizeof(s->buf), "/proc/%d/syscall", r.pid);
68         if ((r.tfd = open(s->buf, OREAD)) < 0)
69                 die(&r);
70
71         cwrite(&r, "stop");
72         cwrite(&r, "startsyscall");
73
74         while(pread(r.tfd, s->buf, sizeof(s->buf)-1, 0) > 0){
75                 if (forking && s->buf[1] == '=' && s->buf[3] != '-') {
76                         forking = 0;
77                         newpid = strtol(&s->buf[3], 0, 0);
78                         sendp(forkc, (void*)newpid);
79                         procrfork(reader, (void*)newpid, Stacksize, 0);
80                 }
81
82                 /*
83                  * There are three tests here and they (I hope) guarantee
84                  * no false positives.
85                  */
86                 if (strstr(s->buf, " Rfork") != nil) {
87                         char *a[8];
88                         char *rf;
89
90                         rf = strdup(s->buf);
91                         if (tokenize(rf, a, 8) == 5) {
92                                 ulong flags;
93
94                                 flags = strtoul(a[4], 0, 16);
95                                 if (flags & RFPROC)
96                                         forking = 1;
97                         }
98                         free(rf);
99                 }
100                 s->pid = r.pid;
101                 sendp(out, s);
102
103                 r.msg = s = mallocz(sizeof(Msg), 1);
104                 cwrite(&r, "startsyscall");
105         }
106         die(&r);
107 }
108
109 void
110 writer(int lastpid)
111 {
112         char lastc = -1;
113         Alt a[4];
114         Msg *s;
115         int n;
116
117         a[0].op = CHANRCV;
118         a[0].c = quit;
119         a[0].v = &s;
120         a[1].op = CHANRCV;
121         a[1].c = out;
122         a[1].v = &s;
123         a[2].op = CHANRCV;
124         a[2].c = forkc;
125         a[2].v = nil;
126         a[3].op = CHANEND;
127
128         while(readers > 0){
129                 switch(alt(a)){
130                 case 0:
131                         readers--;
132                 case 1:
133                         if(s->pid != lastpid){
134                                 lastpid = s->pid;
135                                 if(lastc != '\n'){
136                                         lastc = '\n';
137                                         write(2, &lastc, 1);
138                                 }
139                                 if(s->buf[1] == '=')
140                                         fprint(2, "%d ...", lastpid);
141                         }
142                         n = strlen(s->buf);
143                         if(n > 0){
144                                 write(2, s->buf, n);
145                                 lastc = s->buf[n-1];
146                         }
147                         free(s);
148                         break;
149                 case 2:
150                         readers++;
151                         break;
152                 }
153         }
154 }
155
156 void
157 usage(void)
158 {
159         fprint(2, "Usage: ratrace [-c cmd [arg...]] | [pid]\n");
160         threadexits("usage");
161 }
162
163 void
164 threadmain(int argc, char **argv)
165 {
166         int pid;
167         char *cmd = nil;
168         char **args = nil;
169
170         /*
171          * don't bother with fancy arg processing, because it picks up options
172          * for the command you are starting.  Just check for -c as argv[1]
173          * and then take it from there.
174          */
175         if (argc < 2)
176                 usage();
177         if (argv[1][0] == '-')
178                 switch(argv[1][1]) {
179                 case 'c':
180                         if (argc < 3)
181                                 usage();
182                         cmd = strdup(argv[2]);
183                         args = &argv[2];
184                         break;
185                 default:
186                         usage();
187                 }
188
189         /* run a command? */
190         if(cmd) {
191                 pid = fork();
192                 if (pid < 0)
193                         sysfatal("fork failed: %r");
194                 if(pid == 0) {
195                         write(open(smprint("/proc/%d/ctl", getpid()), OWRITE|OCEXEC), "hang", 4);
196                         exec(cmd, args);
197                         if(cmd[0] != '/')
198                                 exec(smprint("/bin/%s", cmd), args);
199                         sysfatal("exec %s failed: %r", cmd);
200                 }
201         } else {
202                 if(argc != 2)
203                         usage();
204                 pid = atoi(argv[1]);
205         }
206
207         out   = chancreate(sizeof(Msg*), 0);
208         quit  = chancreate(sizeof(Msg*), 0);
209         forkc = chancreate(sizeof(void*), 0);
210         procrfork(reader, (void*)pid, Stacksize, 0);
211
212         writer(pid);
213         threadexits(nil);
214 }