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