OSDN Git Service

ext4.h: add EXT4_FEATURE_INCOMPAT_ENCRYPT am: 1468fbabdd am: de07b52713 am: 1965c510e4
[android-x86/system-extras.git] / ioshark / compile_ioshark.c
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdio.h>
18 #include <sys/time.h>
19 #include <sys/types.h>
20 #include <unistd.h>
21 #include <stdlib.h>
22 #include <signal.h>
23 #include <string.h>
24 #include <sys/stat.h>
25 #include <sys/errno.h>
26 #include <fcntl.h>
27 #include <ctype.h>
28 #include "ioshark.h"
29 #include "compile_ioshark.h"
30
31 char *progname;
32
33 char in_buf[2048];
34
35 struct flags_map_s {
36         char *flag_str;
37         int flag;
38 };
39
40 #define ARRAY_SIZE(a)   (sizeof(a) / sizeof(a[0]))
41
42 struct flags_map_s open_flags_map[] = {
43         { "O_RDONLY", O_RDONLY },
44         { "O_WRONLY", O_WRONLY },
45         { "O_RDWR", O_RDWR },
46         { "O_CREAT", O_CREAT },
47         { "O_SYNC", O_SYNC },
48         { "O_TRUNC", O_TRUNC },
49         { "O_EXCL", O_EXCL },
50         { "O_APPEND", O_APPEND },
51         { "O_NOATIME", O_NOATIME },
52         { "O_ASYNC", O_ASYNC },
53         { "O_CLOEXEC", O_CLOEXEC },
54         { "O_DIRECT", O_DIRECT },
55         { "O_DIRECTORY", O_DIRECTORY },
56         { "O_LARGEFILE", O_LARGEFILE },
57         { "O_NOCTTY", O_NOCTTY },
58         { "O_NOFOLLOW", O_NOFOLLOW },
59         { "O_NONBLOCK", O_NONBLOCK },
60         { "O_NDELAY", O_NDELAY },
61         { "O_PATH", O_PATH }
62 };
63
64 struct flags_map_s lseek_action_map[] = {
65         { "SEEK_SET", SEEK_SET },
66         { "SEEK_CUR", SEEK_CUR },
67         { "SEEK_END", SEEK_END }
68 };
69
70 struct flags_map_s fileop_map[] = {
71         { "lseek", IOSHARK_LSEEK },
72         { "_llseek", IOSHARK_LLSEEK },
73         { "pread64", IOSHARK_PREAD64 },
74         { "pwrite64", IOSHARK_PWRITE64 },
75         { "read", IOSHARK_READ },
76         { "write", IOSHARK_WRITE },
77         { "mmap", IOSHARK_MMAP },
78         { "mmap2", IOSHARK_MMAP2 },
79         { "openat", IOSHARK_OPEN },
80         { "fsync", IOSHARK_FSYNC },
81         { "fdatasync", IOSHARK_FDATASYNC },
82         { "close", IOSHARK_CLOSE },
83         { "ftrace", IOSHARK_MAPPED_PREAD }
84 };
85
86 struct in_mem_file_op {
87         struct ioshark_file_operation disk_file_op;
88         struct in_mem_file_op *next;
89 };
90
91 struct in_mem_file_op *in_mem_file_op_head = NULL, *in_mem_file_op_tail = NULL;
92
93 void usage(void)
94 {
95         fprintf(stderr, "%s in_file out_file\n", progname);
96 }
97
98 void
99 init_prev_time(struct timeval *tv)
100 {
101         tv->tv_sec = tv->tv_usec = 0;
102 }
103
104 /*
105  * delta ts is the time delta from the previous IO in this tracefile.
106  */
107 static u_int64_t
108 get_delta_ts(char *buf, struct timeval *prev)
109 {
110         struct timeval op_tv, tv_res;
111
112         sscanf(buf, "%lu.%lu", &op_tv.tv_sec, &op_tv.tv_usec);
113         /* First item */
114         if (prev->tv_sec == 0 && prev->tv_usec == 0)
115                 tv_res.tv_sec = tv_res.tv_usec = 0;
116         else
117                 timersub(&op_tv, prev, &tv_res);
118         *prev = op_tv;
119         return (tv_res.tv_usec + (tv_res.tv_sec * 1000000));
120 }
121
122 void
123 get_tracetype(char *buf, char *trace_type)
124 {
125         char *s, *s2;
126
127         *trace_type = '\0';
128         s = strchr(buf, ' ');
129         if (s == NULL) {
130                 fprintf(stderr,
131                         "%s Malformed Trace Type ? %s\n",
132                         progname, __func__);
133                 exit(EXIT_FAILURE);
134         }
135         while (*s == ' ')
136                 s++;
137         if (sscanf(s, "%s", trace_type) != 1) {
138                 fprintf(stderr,
139                         "%s Malformed Trace Type ? %s\n",
140                         progname, __func__);
141                 exit(EXIT_FAILURE);
142         }
143         if (strcmp(trace_type, "strace") != 0 &&
144             strcmp(trace_type, "ftrace") != 0) {
145                 fprintf(stderr,
146                         "%s Unknown/Missing Trace Type (has to be strace|ftrace) %s\n",
147                         progname, __func__);
148                 exit(EXIT_FAILURE);
149         }
150         /*
151          * Remove the keyword "strace"/"ftrace" from the buffer
152          */
153         s2 = strchr(s, ' ');
154         if (s2 == NULL) {
155                 fprintf(stderr,
156                         "%s Malformed Trace Type ? %s\n",
157                         progname, __func__);
158                 exit(EXIT_FAILURE);
159         }
160         while (*s2 == ' ')
161                 s2++;
162         if (*s2  == '\0') {
163                 /*
164                  * Premature end of input record
165                  */
166                 fprintf(stderr,
167                         "%s Mal-formed strace/ftrace record %s:%s\n",
168                         progname, __func__, buf);
169                 exit(EXIT_FAILURE);
170         }
171         /* strcpy() expects non-overlapping buffers, but bcopy doesn't */
172         bcopy(s2, s, strlen(s2) + 1);
173 }
174
175 void
176 get_pathname(char *buf, char *pathname, enum file_op file_op)
177 {
178         char *s, *s2, save;
179
180         if (file_op == IOSHARK_MAPPED_PREAD) {
181                 s = strchr(buf, '/');
182                 if (s == NULL) {
183                         fprintf(stderr, "%s: Malformed line: %s\n",
184                                 __func__, buf);
185                         exit(EXIT_FAILURE);
186                 }
187                 s2 = strchr(s, ' ');
188                 if (s2 == NULL) {
189                         fprintf(stderr, "%s: Malformed line: %s\n",
190                                 __func__, buf);
191                         exit(EXIT_FAILURE);
192                 }
193         } else {
194                 if (file_op == IOSHARK_OPEN)
195                         s = strchr(buf, '"');
196                 else
197                         s = strchr(buf, '<');
198                 if (s == NULL) {
199                         fprintf(stderr, "%s: Malformed line: %s\n",
200                                 __func__, buf);
201                         exit(EXIT_FAILURE);
202                 }
203                 s += 1;
204                 if (file_op == IOSHARK_OPEN)
205                         s2 = strchr(s, '"');
206                 else
207                         s2 = strchr(s, '>');
208                 if (s2 == NULL) {
209                         fprintf(stderr, "%s: Malformed line: %s\n",
210                                 __func__, buf);
211                         exit(EXIT_FAILURE);
212                 }
213         }
214         save = *s2;
215         *s2 = '\0';
216         strcpy(pathname, s);
217         *s2 = save;
218 }
219
220 void
221 get_syscall(char *buf, char *syscall)
222 {
223         char *s, *s2;
224
225         s = strchr(buf, ' ');
226         if (s == NULL) {
227                 fprintf(stderr, "%s: Malformed line: %s\n",
228                         __func__, buf);
229                 exit(EXIT_FAILURE);
230         }
231         s += 1;
232         s2 = strchr(s, '(');
233         if (s2 == NULL) {
234                 fprintf(stderr, "%s: Malformed line: %s\n",
235                         __func__, buf);
236                 exit(EXIT_FAILURE);
237         }
238         *s2 = '\0';
239         strcpy(syscall, s);
240         *s2 = '(';
241 }
242
243 void
244 get_mmap_offset_len_prot(char *buf, int *prot, off_t *offset, u_int64_t *len)
245 {
246         char *s, *s1;
247         int i;
248         char protstr[128];
249
250         s = strchr(buf, ',');
251         if (s == NULL) {
252                 fprintf(stderr, "%s: Malformed line: %s\n",
253                         __func__, buf);
254                 exit(EXIT_FAILURE);
255         }
256         s += 2;
257         sscanf(s, "%ju", len);
258         s1 = strchr(s, ',');
259         if (s1 == NULL) {
260                 fprintf(stderr, "%s: Malformed line: %s\n",
261                         __func__, buf);
262                 exit(EXIT_FAILURE);
263         }
264         s1 += 2;
265         s = strchr(s1, ',');
266         if (s == NULL) {
267                 fprintf(stderr, "%s: Malformed line: %s\n",
268                         __func__, buf);
269                 exit(EXIT_FAILURE);
270         }
271         *s = '\0';
272         strcpy(protstr, s1);
273         *prot = 0;
274         if (strstr(protstr, "PROT_READ"))
275                 *prot |= IOSHARK_PROT_READ;
276         if (strstr(protstr, "PROT_WRITE"))
277                 *prot |= IOSHARK_PROT_WRITE;
278         *s = ',';
279         s += 2;
280         for (i = 0 ; i < 2 ; i++) {
281                 s = strchr(s, ',');
282                 if (s == NULL) {
283                         fprintf(stderr, "%s: Malformed line: %s\n",
284                                 __func__, buf);
285                         exit(EXIT_FAILURE);
286                 }
287                 s += 2;
288         }
289         sscanf(s, "%jx", offset);
290 }
291
292 void
293 get_lseek_offset_action(char *buf, enum file_op op,
294                         off_t *offset, char *action)
295 {
296         char *s, *s2;
297
298         s = strchr(buf, ',');
299         if (s == NULL) {
300                 fprintf(stderr, "%s: Malformed line: %s\n",
301                         __func__, buf);
302                 exit(EXIT_FAILURE);
303         }
304         s += 2;
305         sscanf(s, "%ju", offset);
306         s = strchr(s, ',');
307         if (s == NULL) {
308                 fprintf(stderr, "%s: Malformed line: %s\n",
309                         __func__, buf);
310                 exit(EXIT_FAILURE);
311         }
312         s += 2;
313         if (op == IOSHARK_LLSEEK) {
314                 s = strchr(s, ',');
315                 if (s == NULL) {
316                         fprintf(stderr, "%s: Malformed line: %s\n",
317                                 __func__, buf);
318                         exit(EXIT_FAILURE);
319                 }
320                 s += 2;
321         }
322         s2 = strchr(s, ')');
323         if (s2 == NULL) {
324                 fprintf(stderr, "%s: Malformed line: %s\n",
325                         __func__, buf);
326                 exit(EXIT_FAILURE);
327         }
328         *s2 = '\0';
329         strcpy(action, s);
330         *s2 = ')';
331 }
332
333 void
334 get_rw_len(char *buf,
335            u_int64_t *len)
336 {
337         char *s_len;
338
339         s_len = strrchr(buf, ',');
340         if (s_len == NULL) {
341                 fprintf(stderr, "%s: Malformed line: %s\n",
342                         __func__, buf);
343                 exit(EXIT_FAILURE);
344         }
345         sscanf(s_len + 2, "%ju", len);
346 }
347
348 void
349 get_prw64_offset_len(char *buf,
350                      off_t *offset,
351                      u_int64_t *len)
352 {
353         char *s_offset, *s_len;
354
355         s_offset = strrchr(buf, ',');
356         if (s_offset == NULL) {
357                 fprintf(stderr, "%s: Malformed line 1: %s\n",
358                         __func__, buf);
359                 exit(EXIT_FAILURE);
360         }
361         *s_offset = '\0';
362         s_len = strrchr(buf, ',');
363         if (s_len == NULL) {
364                 fprintf(stderr, "%s: Malformed line 2: %s\n",
365                         __func__, buf);
366                 exit(EXIT_FAILURE);
367         }
368         *s_offset = ',';
369         sscanf(s_len + 2, "%ju", len);
370         sscanf(s_offset + 2, "%ju", offset);
371 }
372
373
374 void
375 get_ftrace_offset_len(char *buf,
376                       off_t *offset,
377                       u_int64_t *len)
378 {
379         char *s_offset;
380
381         s_offset = strchr(buf, '/');
382         if (s_offset == NULL) {
383                 fprintf(stderr, "%s: Malformed line 1: %s\n",
384                         __func__, buf);
385                 exit(EXIT_FAILURE);
386         }
387         s_offset = strchr(s_offset, ' ');
388         if (s_offset == NULL) {
389                 fprintf(stderr, "%s: Malformed line 2: %s\n",
390                         __func__, buf);
391                 exit(EXIT_FAILURE);
392         }
393         while (*s_offset == ' ')
394                 s_offset++;
395         if (sscanf(s_offset, "%ju %ju", offset, len) != 2) {
396                 fprintf(stderr, "%s: Malformed line 3: %s\n",
397                         __func__, buf);
398                 exit(EXIT_FAILURE);
399         }
400 }
401
402 void
403 get_openat_flags_mode(char *buf, char *flags, mode_t *mode)
404 {
405         char *s, *s2, lookfor;
406
407         s = strchr(buf, ',');
408         if (s == NULL) {
409                 fprintf(stderr, "%s: Malformed line: %s\n",
410                         __func__, buf);
411                 exit(EXIT_FAILURE);
412         }
413         s += 2;
414         s = strchr(s, ',');
415         if (s == NULL) {
416                 fprintf(stderr, "%s: Malformed line: %s\n",
417                         __func__, buf);
418                 exit(EXIT_FAILURE);
419         }
420         s += 2;
421         if (strstr(s, "O_CREAT") == NULL)
422                 lookfor = ')';
423         else
424                 lookfor = ',';
425         s2 = strchr(s, lookfor);
426         if (s2 == NULL) {
427                 fprintf(stderr, "%s: Malformed line: %s\n",
428                         __func__, buf);
429                 exit(EXIT_FAILURE);
430         }
431         *s2 = '\0';
432         strcpy(flags, s);
433         *s2 = lookfor;
434         if (strstr(s, "O_CREAT") != NULL) {
435                 s = s2 + 2;
436                 s2 = strchr(s, ')');
437                 if (s2 == NULL) {
438                         fprintf(stderr, "%s: Malformed line: %s\n",
439                                 __func__, buf);
440                         exit(EXIT_FAILURE);
441                 }
442                 *s2 = '\0';
443                 sscanf(s, "%o", mode);
444                 *s2 = ')';
445         }
446 }
447
448 int
449 lookup_map(char *s, struct flags_map_s *flags_map, int maplen)
450 {
451         int found = 0, flag = 0;
452         int i;
453
454         while (isspace(*s))
455                 s++;
456         for (i = 0 ; i < maplen ; i++) {
457                 if (strcmp(flags_map[i].flag_str, s) == 0) {
458                         flag = flags_map[i].flag;
459                         found = 1;
460                         break;
461                 }
462         }
463         if (found == 0) {
464                 fprintf(stderr, "%s: Unknown syscall %s\n",
465                         __func__, s);
466                 exit(1);
467         }
468         return flag;
469 }
470
471 int
472 map_open_flags(char *s)
473 {
474         int flags = 0;
475         char *s1;
476
477         while ((s1 = strchr(s, '|'))) {
478                 *s1 = '\0';
479                 flags |= lookup_map(s, open_flags_map,
480                                     ARRAY_SIZE(open_flags_map));
481                 *s1 = '|';
482                 s = s1 + 1;
483         }
484         /* Last option */
485         flags |= lookup_map(s, open_flags_map,
486                             ARRAY_SIZE(open_flags_map));
487         return flags;
488 }
489
490 int
491 map_lseek_action(char *s)
492 {
493         int flags = 0;
494         char *s1;
495
496         while ((s1 = strchr(s, '|'))) {
497                 *s1 = '\0';
498                 flags |= lookup_map(s, lseek_action_map,
499                                     ARRAY_SIZE(lseek_action_map));
500                 *s1 = '|';
501                 s = s1 + 1;
502         }
503         /* Last option */
504         flags |= lookup_map(s, lseek_action_map,
505                             ARRAY_SIZE(lseek_action_map));
506         return flags;
507 }
508
509 enum file_op
510 map_syscall(char *syscall)
511 {
512         return lookup_map(syscall, fileop_map,
513                           ARRAY_SIZE(fileop_map));
514 }
515
516 /*
517  * For each tracefile, we first create in-memory structures, then once
518  * we've processed each tracefile completely, we write out the in-memory
519  * structures and free them.
520  */
521 int main(int argc, char **argv)
522 {
523         FILE *fp;
524         char path[512];
525         char syscall[512];
526         char lseek_action_str[512];
527         char *s;
528         char open_flags_str[64];
529         void *db_node;
530         int num_io_operations = 0;
531         struct ioshark_header header;
532         struct ioshark_file_operation *disk_file_op;
533         struct in_mem_file_op *in_mem_fop;
534         struct stat st;
535         char *infile, *outfile;
536         struct timeval prev_time;
537         char trace_type[64];
538
539         progname = argv[0];
540         if (argc != 3) {
541                 usage();
542                 exit(EXIT_FAILURE);
543         }
544         infile = argv[1];
545         outfile = argv[2];
546         if (stat(infile, &st) < 0) {
547                 fprintf(stderr, "%s Can't stat %s\n",
548                         progname, infile);
549                 exit(EXIT_FAILURE);
550         }
551         if (st.st_size == 0) {
552                 fprintf(stderr, "%s Empty file %s\n",
553                         progname, infile);
554                 exit(EXIT_FAILURE);
555         }
556         init_prev_time(&prev_time);
557         init_filename_cache();
558         fp = fopen(infile, "r");
559         if (fp == NULL) {
560                 fprintf(stderr, "%s Can't open %s\n",
561                         progname, infile);
562                 exit(EXIT_FAILURE);
563         }
564         while (fgets(in_buf, 2048, fp)) {
565                 s = in_buf;
566                 while (isspace(*s))
567                         s++;
568                 in_mem_fop = malloc(sizeof(struct in_mem_file_op));
569                 disk_file_op = &in_mem_fop->disk_file_op;
570                 disk_file_op->delta_us = get_delta_ts(s, &prev_time);
571                 get_tracetype(s, trace_type);
572                 if (strcmp(trace_type, "strace") == 0) {
573                         get_syscall(s, syscall);
574                         disk_file_op->file_op = map_syscall(syscall);
575                 } else
576                         disk_file_op->file_op = map_syscall("ftrace");
577                 get_pathname(s, path, disk_file_op->file_op);
578                 db_node = files_db_add(path);
579                 disk_file_op->fileno = files_db_get_fileno(db_node);
580                 switch (disk_file_op->file_op) {
581                 case IOSHARK_LLSEEK:
582                 case IOSHARK_LSEEK:
583                         get_lseek_offset_action(s,
584                                         disk_file_op->file_op,
585                                         &disk_file_op->lseek_offset,
586                                         lseek_action_str);
587                         disk_file_op->lseek_action =
588                                 map_lseek_action(lseek_action_str);
589                         if (disk_file_op->lseek_action == SEEK_SET)
590                                 files_db_update_size(db_node,
591                                                      disk_file_op->lseek_offset);
592                         break;
593                 case IOSHARK_PREAD64:
594                 case IOSHARK_PWRITE64:
595                         get_prw64_offset_len(s,
596                                              &disk_file_op->prw_offset,
597                                              (u_int64_t *)&disk_file_op->prw_len);
598                         files_db_update_size(db_node,
599                                              disk_file_op->prw_offset +
600                                              disk_file_op->prw_len);
601                         break;
602                 case IOSHARK_READ:
603                 case IOSHARK_WRITE:
604                         get_rw_len(s, (u_int64_t *)&disk_file_op->rw_len);
605                         files_db_add_to_size(db_node,
606                                              disk_file_op->rw_len);
607                         break;
608                 case IOSHARK_MMAP:
609                 case IOSHARK_MMAP2:
610                         get_mmap_offset_len_prot(s,
611                                     &disk_file_op->mmap_prot,
612                                     &disk_file_op->mmap_offset,
613                                     (u_int64_t *)&disk_file_op->mmap_len);
614                         files_db_update_size(db_node,
615                                      disk_file_op->mmap_offset +
616                                      disk_file_op->mmap_len);
617                         break;
618                 case IOSHARK_OPEN:
619                         disk_file_op->open_mode = 0;
620                         get_openat_flags_mode(s, open_flags_str,
621                                       &disk_file_op->open_mode);
622                         disk_file_op->open_flags =
623                                 map_open_flags(open_flags_str);
624                         break;
625                 case IOSHARK_FSYNC:
626                 case IOSHARK_FDATASYNC:
627                         break;
628                 case IOSHARK_CLOSE:
629                         break;
630                 case IOSHARK_MAPPED_PREAD:
631                         /* Convert a mmap'ed read into a PREAD64 */
632                         disk_file_op->file_op = IOSHARK_PREAD64;
633                         get_ftrace_offset_len(s,
634                                               &disk_file_op->prw_offset,
635                                               (u_int64_t *)&disk_file_op->prw_len);
636                         files_db_update_size(db_node,
637                                              disk_file_op->prw_offset +
638                                              disk_file_op->prw_len);
639                         break;
640                 default:
641                         break;
642                 }
643                 /* Chain at the end */
644                 num_io_operations++;
645                 in_mem_fop->next = NULL;
646                 if (in_mem_file_op_head == NULL) {
647                         in_mem_file_op_tail = in_mem_fop;
648                         in_mem_file_op_head = in_mem_fop;
649                 } else {
650                         in_mem_file_op_tail->next = in_mem_fop;
651                         in_mem_file_op_tail = in_mem_fop;
652                 }
653         }
654         fclose(fp);
655         /*
656          * Now we can write everything out to the output tracefile.
657          */
658         fp = fopen(outfile, "w+");
659         if (fp == NULL) {
660                 fprintf(stderr, "%s Can't open trace.outfile\n",
661                         progname);
662                 exit(EXIT_FAILURE);
663         }
664         header.num_io_operations = num_io_operations;
665         header.num_files = files_db_get_total_obj();
666         if (fwrite(&header, sizeof(struct ioshark_header), 1, fp) != 1) {
667                 fprintf(stderr, "%s Write error trace.outfile\n",
668                         progname);
669                 exit(EXIT_FAILURE);
670         }
671         files_db_write_objects(fp);
672         while (in_mem_file_op_head != NULL) {
673                 struct in_mem_file_op *temp;
674
675                 disk_file_op = &in_mem_file_op_head->disk_file_op;
676                 if (fwrite(disk_file_op,
677                            sizeof(struct ioshark_file_operation), 1, fp) != 1) {
678                         fprintf(stderr, "%s Write error trace.outfile\n",
679                                 progname);
680                         exit(EXIT_FAILURE);
681                 }
682                 temp = in_mem_file_op_head;
683                 in_mem_file_op_head = in_mem_file_op_head->next;
684                 free(temp);
685         }
686         store_filename_cache();
687 }