xref: /plan9-contrib/sys/src/cmd/ptrace/tron.c (revision af198995f3f1f1d87a386835b2bcd15ca90a6fed)
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