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