1*af198995SDavid du Colombier #include <u.h>
2*af198995SDavid du Colombier #include <libc.h>
3*af198995SDavid du Colombier
4*af198995SDavid du Colombier static void
usage(void)5*af198995SDavid du Colombier usage(void)
6*af198995SDavid du Colombier {
7*af198995SDavid du Colombier fprint(2, "usage: %s [-s nkevs] [-f dev] [-o file] [-p pid] cmd [args...]\n", argv0);
8*af198995SDavid du Colombier exits("usage");
9*af198995SDavid du Colombier }
10*af198995SDavid du Colombier
11*af198995SDavid du Colombier char buf[1*1024*1024];
12*af198995SDavid du Colombier int done;
13*af198995SDavid du Colombier int pids[128];
14*af198995SDavid du Colombier int npids;
15*af198995SDavid du Colombier
16*af198995SDavid du Colombier void
main(int argc,char * argv[])17*af198995SDavid du Colombier main(int argc, char *argv[])
18*af198995SDavid du Colombier {
19*af198995SDavid du Colombier int fd, cfd, pid, ofd, i;
20*af198995SDavid du Colombier char file[128], *f;
21*af198995SDavid du Colombier char *dev, *devctl, *out;
22*af198995SDavid du Colombier long tot, nr;
23*af198995SDavid du Colombier int sz;
24*af198995SDavid du Colombier
25*af198995SDavid du Colombier sz = 8;
26*af198995SDavid du Colombier dev = "/dev/ptrace";
27*af198995SDavid du Colombier out = nil;
28*af198995SDavid du Colombier ARGBEGIN{
29*af198995SDavid du Colombier case 'f':
30*af198995SDavid du Colombier dev = EARGF(usage());
31*af198995SDavid du Colombier break;
32*af198995SDavid du Colombier case 'o':
33*af198995SDavid du Colombier out = EARGF(usage());
34*af198995SDavid du Colombier break;
35*af198995SDavid du Colombier case 's':
36*af198995SDavid du Colombier sz = strtoul(EARGF(usage()), 0, 0);
37*af198995SDavid du Colombier break;
38*af198995SDavid du Colombier case 'p':
39*af198995SDavid du Colombier if(npids > nelem(pids))
40*af198995SDavid du Colombier sysfatal("too many pids");
41*af198995SDavid du Colombier pids[npids++] = strtoul(EARGF(usage()), 0, 0);
42*af198995SDavid du Colombier break;
43*af198995SDavid du Colombier default:
44*af198995SDavid du Colombier usage();
45*af198995SDavid du Colombier }ARGEND
46*af198995SDavid du Colombier if(argc == 0)
47*af198995SDavid du Colombier usage();
48*af198995SDavid du Colombier
49*af198995SDavid du Colombier sz *= 1024;
50*af198995SDavid du Colombier if(sz < 1024)
51*af198995SDavid du Colombier sz = 1024;
52*af198995SDavid du Colombier if(sz > 64*1024) /* perhaps we shouldn't limit it */
53*af198995SDavid du Colombier sz = 64*1024;
54*af198995SDavid du Colombier
55*af198995SDavid du Colombier devctl = smprint("%sctl", dev);
56*af198995SDavid du Colombier if(devctl == nil)
57*af198995SDavid du Colombier sysfatal("no memory");
58*af198995SDavid du Colombier
59*af198995SDavid du Colombier if(access(argv[0], AEXIST) < 0){
60*af198995SDavid du Colombier seprint(file, file+sizeof file, "/bin/%s", argv[0]);
61*af198995SDavid du Colombier f = file;
62*af198995SDavid du Colombier }else
63*af198995SDavid du Colombier f = argv[0];
64*af198995SDavid du Colombier if(access(f, AEXIST) < 0)
65*af198995SDavid du Colombier sysfatal("%s: %r", argv[0]);
66*af198995SDavid du Colombier
67*af198995SDavid du Colombier
68*af198995SDavid du Colombier /* prepage; don't want interference while tracing */
69*af198995SDavid du Colombier for(i = 0; i < sizeof buf; i += 4096)
70*af198995SDavid du Colombier buf[i] = 0;
71*af198995SDavid du Colombier
72*af198995SDavid du Colombier rfork(RFREND);
73*af198995SDavid du Colombier pid = 0;
74*af198995SDavid du Colombier
75*af198995SDavid du Colombier /* play a dance with the traced command so it starts when we want,
76*af198995SDavid du Colombier * or issue the trace command for the traced pids.
77*af198995SDavid du Colombier */
78*af198995SDavid du Colombier cfd = open(devctl, OWRITE);
79*af198995SDavid du Colombier if(cfd < 0)
80*af198995SDavid du Colombier sysfatal("can't trace: %r");
81*af198995SDavid du Colombier if(npids == 0){
82*af198995SDavid du Colombier pid = rfork(RFPROC|RFFDG);
83*af198995SDavid du Colombier switch(pid){
84*af198995SDavid du Colombier case -1:
85*af198995SDavid du Colombier sysfatal("fork: %r");
86*af198995SDavid du Colombier case 0:
87*af198995SDavid du Colombier /* wait until traced */
88*af198995SDavid du Colombier if(rendezvous(usage, 0) == 0)
89*af198995SDavid du Colombier exits("no trace");
90*af198995SDavid du Colombier rfork(RFREND);
91*af198995SDavid du Colombier exec(f, argv);
92*af198995SDavid du Colombier sysfatal("exec: %r");
93*af198995SDavid du Colombier }
94*af198995SDavid du Colombier if(fprint(cfd, "size %d\n", sz) < 0 || fprint(cfd, "trace %d 1\n", pid) < 0){
95*af198995SDavid du Colombier rendezvous(usage, 0);
96*af198995SDavid du Colombier sysfatal("can't trace");
97*af198995SDavid du Colombier }
98*af198995SDavid du Colombier
99*af198995SDavid du Colombier if(out == nil){
100*af198995SDavid du Colombier rendezvous(usage, usage);
101*af198995SDavid du Colombier waitpid();
102*af198995SDavid du Colombier exits(nil);
103*af198995SDavid du Colombier }
104*af198995SDavid du Colombier }else{
105*af198995SDavid du Colombier for(i = 0; i < npids; i++)
106*af198995SDavid du Colombier if(fprint(cfd, "trace %d 1\n", pids[i]) < 0)
107*af198995SDavid du Colombier fprint(2, "%s: trace %d: %r\n", argv0, pids[i]);
108*af198995SDavid du Colombier }
109*af198995SDavid du Colombier close(cfd);
110*af198995SDavid du Colombier
111*af198995SDavid du Colombier /* ready: open the trace and collect what we can. */
112*af198995SDavid du Colombier fd = open(dev, OREAD);
113*af198995SDavid du Colombier ofd = create(out, OWRITE, 0664);
114*af198995SDavid du Colombier if(fd < 0 || ofd < 0){
115*af198995SDavid du Colombier if(npids == 0)
116*af198995SDavid du Colombier rendezvous(usage, 0);
117*af198995SDavid du Colombier sysfatal("can't trace: %r");
118*af198995SDavid du Colombier }
119*af198995SDavid du Colombier
120*af198995SDavid du Colombier done = 0;
121*af198995SDavid du Colombier switch(rfork(RFPROC|RFMEM)){
122*af198995SDavid du Colombier case -1:
123*af198995SDavid du Colombier sysfatal("fork");
124*af198995SDavid du Colombier default:
125*af198995SDavid du Colombier if(npids == 0){
126*af198995SDavid du Colombier /* let the traced go! */
127*af198995SDavid du Colombier rendezvous(usage, usage);
128*af198995SDavid du Colombier }
129*af198995SDavid du Colombier
130*af198995SDavid du Colombier while(waitpid() != pid)
131*af198995SDavid du Colombier ;
132*af198995SDavid du Colombier done = 1;
133*af198995SDavid du Colombier exits(nil);
134*af198995SDavid du Colombier case 0:
135*af198995SDavid du Colombier /* The damn device won't block us. We must insist upon eof.
136*af198995SDavid du Colombier * Besides, when done, we must give time for the events to
137*af198995SDavid du Colombier * arrive.
138*af198995SDavid du Colombier */
139*af198995SDavid du Colombier for(;;){
140*af198995SDavid du Colombier for(tot = 0; tot < sizeof buf - 128; tot += nr){
141*af198995SDavid du Colombier nr = read(fd, buf+tot, sizeof buf - tot);
142*af198995SDavid du Colombier if(nr < 0)
143*af198995SDavid du Colombier sysfatal("read: %r");
144*af198995SDavid du Colombier if(nr == 0){
145*af198995SDavid du Colombier sleep(100);
146*af198995SDavid du Colombier if(done)
147*af198995SDavid du Colombier break;
148*af198995SDavid du Colombier }
149*af198995SDavid du Colombier }
150*af198995SDavid du Colombier if(tot > 0 && write(ofd, buf, tot) != tot)
151*af198995SDavid du Colombier sysfatal("write: %r");
152*af198995SDavid du Colombier /* try to read more if we were done; but just once. */
153*af198995SDavid du Colombier if(done && tot == 0 && done++ == 2)
154*af198995SDavid du Colombier break;
155*af198995SDavid du Colombier }
156*af198995SDavid du Colombier close(fd);
157*af198995SDavid du Colombier close(ofd);
158*af198995SDavid du Colombier rendezvous(main, nil);
159*af198995SDavid du Colombier exits(nil);
160*af198995SDavid du Colombier }
161*af198995SDavid du Colombier }
162