]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/ratrace.c
nusb: use ep->addr instead of ep->id in unstall() library function
[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 Str Str;
16 struct Str {
17         char    *buf;
18         int     len;
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         Str *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(Str) + Bufsize, 1);
57         s->buf = (char *)&s[1];
58         while((s->len = pread(tfd, s->buf, Bufsize - 1, 0)) > 0){
59                 if (forking && s->buf[1] == '=' && s->buf[3] != '-') {
60                         forking = 0;
61                         newpid = strtol(&s->buf[3], 0, 0);
62                         sendp(forkc, (void*)newpid);
63                         procrfork(reader, (void*)newpid, Stacksize, 0);
64                 }
65
66                 /*
67                  * There are three tests here and they (I hope) guarantee
68                  * no false positives.
69                  */
70                 if (strstr(s->buf, " Rfork") != nil) {
71                         char *a[8];
72                         char *rf;
73
74                         rf = strdup(s->buf);
75                         if (tokenize(rf, a, 8) == 5) {
76                                 ulong flags;
77
78                                 flags = strtoul(a[4], 0, 16);
79                                 if (flags & RFPROC)
80                                         forking = 1;
81                         }
82                         free(rf);
83                 }
84                 sendp(out, s);
85                 cwrite(cfd, truss, "startsyscall", 12);
86                 s = mallocz(sizeof(Str) + Bufsize, 1);
87                 s->buf = (char *)&s[1];
88         }
89         sendp(quit, nil);
90         threadexitsall(nil);
91 }
92
93 void
94 writer(void *)
95 {
96         int newpid;
97         Alt a[4];
98         Str *s;
99
100         a[0].op = CHANRCV;
101         a[0].c = quit;
102         a[0].v = nil;
103         a[1].op = CHANRCV;
104         a[1].c = out;
105         a[1].v = &s;
106         a[2].op = CHANRCV;
107         a[2].c = forkc;
108         a[2].v = &newpid;
109         a[3].op = CHANEND;
110
111         for(;;)
112                 switch(alt(a)){
113                 case 0:
114                         nread--;
115                         if(nread <= 0)
116                                 goto done;
117                         break;
118                 case 1:
119                         /* it's a nice null terminated thing */
120                         fprint(2, "%s", s->buf);
121                         free(s);
122                         break;
123                 case 2:
124                         // procrfork(reader, (void*)newpid, Stacksize, 0);
125                         nread++;
126                         break;
127                 }
128 done:
129         exits(nil);
130 }
131
132 void
133 usage(void)
134 {
135         fprint(2, "Usage: ratrace [-c cmd [arg...]] | [pid]\n");
136         exits("usage");
137 }
138
139 void
140 threadmain(int argc, char **argv)
141 {
142         int pid;
143         char *cmd = nil;
144         char **args = nil;
145
146         /*
147          * don't bother with fancy arg processing, because it picks up options
148          * for the command you are starting.  Just check for -c as argv[1]
149          * and then take it from there.
150          */
151         if (argc < 2)
152                 usage();
153         if (argv[1][0] == '-')
154                 switch(argv[1][1]) {
155                 case 'c':
156                         if (argc < 3)
157                                 usage();
158                         cmd = strdup(argv[2]);
159                         args = &argv[2];
160                         break;
161                 default:
162                         usage();
163                 }
164
165         /* run a command? */
166         if(cmd) {
167                 pid = fork();
168                 if (pid < 0)
169                         sysfatal("fork failed: %r");
170                 if(pid == 0) {
171                         exec(cmd, args);
172                         if(cmd[0] != '/')
173                                 exec(smprint("/bin/%s", cmd), args);
174                         sysfatal("exec %s failed: %r", cmd);
175                 }
176         } else {
177                 if(argc != 2)
178                         usage();
179                 pid = atoi(argv[1]);
180         }
181
182         out   = chancreate(sizeof(char*), 0);
183         quit  = chancreate(sizeof(char*), 0);
184         forkc = chancreate(sizeof(ulong *), 0);
185         nread++;
186         procrfork(writer, nil, Stacksize, 0);
187         reader((void*)pid);
188 }