xref: /minix/minix/usr.sbin/btrace/btrace.c (revision 9f988b79)
1 /* Block trace command line tool - by D.C. van Moolenbroek */
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include <unistd.h>
6 #include <fcntl.h>
7 #include <sys/types.h>
8 #include <minix/btrace.h>
9 #include <minix/u64.h>
10 #include <sys/ioctl.h>
11 
12 static btrace_entry buf[BTBUF_SIZE];
13 
14 static void __dead
15 usage(void)
16 {
17 	fprintf(stderr, "usage:\n"
18 	    "%s start <device> <nr_entries>\n"
19 	    "%s stop <device> <file>\n"
20 	    "%s reset <device>\n"
21 	    "%s dump <file>\n",
22 	    getprogname(), getprogname(), getprogname(), getprogname());
23 
24 	exit(EXIT_FAILURE);
25 }
26 
27 static void
28 btrace_start(char * device, int nr_entries)
29 {
30 	int r, ctl, devfd;
31 	size_t size;
32 
33 	if ((devfd = open(device, O_RDONLY)) < 0) {
34 		perror("device open");
35 		exit(EXIT_FAILURE);
36 	}
37 
38 	size = nr_entries;
39 	if ((r = ioctl(devfd, BIOCTRACEBUF, &size)) < 0) {
40 		perror("ioctl(BIOCTRACEBUF)");
41 		exit(EXIT_FAILURE);
42 	}
43 
44 	ctl = BTCTL_START;
45 	if ((r = ioctl(devfd, BIOCTRACECTL, &ctl)) < 0) {
46 		perror("ioctl(BIOCTRACECTL)");
47 
48 		size = 0;
49 		(void)ioctl(devfd, BIOCTRACEBUF, &size);
50 
51 		exit(EXIT_FAILURE);
52 	}
53 
54 	close(devfd);
55 }
56 
57 static void
58 btrace_stop(char * device, char * file)
59 {
60 	int r, ctl, devfd, outfd;
61 	size_t size;
62 
63 	if ((devfd = open(device, O_RDONLY)) < 0) {
64 		perror("device open");
65 		exit(EXIT_FAILURE);
66 	}
67 
68 	if ((outfd = open(file, O_CREAT | O_TRUNC | O_WRONLY, 0600)) < 0) {
69 		perror("file open");
70 		exit(EXIT_FAILURE);
71 	  }
72 
73 	ctl = BTCTL_STOP;
74 	if ((r = ioctl(devfd, BIOCTRACECTL, &ctl)) < 0) {
75 		perror("ioctl(BIOCTRACECTL)");
76 		exit(EXIT_FAILURE);
77 	}
78 
79 	for (;;) {
80 		if ((r = ioctl(devfd, BIOCTRACEGET, buf)) < 0) {
81 			perror("ioctl(BIOCTRACEGET)");
82 			break;
83 		}
84 
85 		if (r == 0) break;
86 
87 		size = r * sizeof(buf[0]);
88 		if ((r = write(outfd, (char *)buf, size)) != size) {
89 			if (r < 0) perror("write");
90 			else fputs("short write\n", stderr);
91 		}
92 	}
93 
94 	close(outfd);
95 
96 	size = 0;
97 	if ((r = ioctl(devfd, BIOCTRACEBUF, &size)) < 0) {
98 		perror("ioctl(BIOCTRACEBUF)");
99 		exit(EXIT_FAILURE);
100 	}
101 
102 	close(devfd);
103 }
104 
105 static void
106 btrace_reset(char * device)
107 {
108 	size_t size;
109 	int r, ctl, devfd;
110 
111 	if ((devfd = open(device, O_RDONLY)) < 0) {
112 		perror("device open");
113 		exit(EXIT_FAILURE);
114 	}
115 
116 	ctl = BTCTL_STOP;
117 	(void)ioctl(devfd, BIOCTRACECTL, &ctl);
118 
119 	size = 0;
120 	if ((r = ioctl(devfd, BIOCTRACEBUF, &size)) < 0) {
121 		perror("ioctl(BIOCTRACEBUF)");
122 		exit(EXIT_FAILURE);
123 	}
124 
125 	close(devfd);
126 }
127 
128 static void
129 dump_entry(btrace_entry * entry)
130 {
131 	switch (entry->request) {
132 	case BTREQ_OPEN: printf("OPEN"); break;
133 	case BTREQ_CLOSE: printf("CLOSE"); break;
134 	case BTREQ_READ: printf("READ"); break;
135 	case BTREQ_WRITE: printf("WRITE"); break;
136 	case BTREQ_GATHER: printf("GATHER"); break;
137 	case BTREQ_SCATTER: printf("SCATTER"); break;
138 	case BTREQ_IOCTL: printf("IOCTL"); break;
139 	}
140 
141 	printf(" request\n");
142 
143 	switch (entry->request) {
144 	case BTREQ_OPEN:
145 		printf("- access:\t%x\n", entry->size);
146 		break;
147 	case BTREQ_READ:
148 	case BTREQ_WRITE:
149 	case BTREQ_GATHER:
150 	case BTREQ_SCATTER:
151 		printf("- position:\t%08lx%08lx\n",
152 		    ex64hi(entry->position), ex64lo(entry->position));
153 		printf("- size:\t\t%u\n", entry->size);
154 		printf("- flags:\t%x\n", entry->flags);
155 		break;
156 	case BTREQ_IOCTL:
157 		printf("- request:\t%08x\n", entry->size);
158 		break;
159 	}
160 
161 	printf("- start:\t%u us\n", entry->start_time);
162 	printf("- finish:\t%u us\n", entry->finish_time);
163 	if (entry->result == BTRES_INPROGRESS)
164 		printf("- result:\t(in progress)\n");
165 	else
166 		printf("- result:\t%d\n", entry->result);
167 	printf("\n");
168 }
169 
170 static void
171 btrace_dump(char * file)
172 {
173 	int i, r, infd;
174 
175 	if ((infd = open(file, O_RDONLY)) < 0) {
176 		perror("open");
177 		exit(EXIT_FAILURE);
178 	}
179 
180 	for (;;) {
181 		if ((r = read(infd, (char *)buf, sizeof(buf))) <= 0)
182 			break;
183 
184 		r /= sizeof(buf[0]);
185 
186 		for (i = 0; i < r; i++)
187 			dump_entry(&buf[i]);
188 	}
189 
190 	if (r < 0) perror("read");
191 
192 	close(infd);
193 }
194 
195 int main(int argc, char ** argv)
196 {
197 	int num;
198 
199 	setprogname(argv[0]);
200 
201 	if (argc < 3) usage();
202 
203 	if (!strcmp(argv[1], "start")) {
204 		if (argc < 4) usage();
205 
206 		num = atoi(argv[3]);
207 
208 		if (num <= 0) usage();
209 
210 		btrace_start(argv[2], num);
211 
212 	} else if (!strcmp(argv[1], "stop")) {
213 		if (argc < 4) usage();
214 
215 		btrace_stop(argv[2], argv[3]);
216 
217 	} else if (!strcmp(argv[1], "reset")) {
218 		btrace_reset(argv[2]);
219 
220 	} else if (!strcmp(argv[1], "dump")) {
221 		btrace_dump(argv[2]);
222 
223 	} else
224 		usage();
225 
226 	return EXIT_SUCCESS;
227 }
228