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 
usage(void)93 void usage(void)
94 {
95 	fprintf(stderr, "%s in_file out_file\n", progname);
96 }
97 
98 void
init_prev_time(struct timeval * tv)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
get_delta_ts(char * buf,struct timeval * prev)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
get_tracetype(char * buf,char * trace_type)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
get_pathname(char * buf,char * pathname,enum file_op file_op)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
get_syscall(char * buf,char * syscall)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
get_mmap_offset_len_prot(char * buf,int * prot,off_t * offset,u_int64_t * len)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
get_lseek_offset_action(char * buf,enum file_op op,off_t * offset,char * action)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
get_rw_len(char * buf,u_int64_t * len)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
get_prw64_offset_len(char * buf,off_t * offset,u_int64_t * len)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
get_ftrace_offset_len(char * buf,off_t * offset,u_int64_t * len)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
get_openat_flags_mode(char * buf,char * flags,mode_t * mode)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
lookup_map(char * s,struct flags_map_s * flags_map,int maplen)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
map_open_flags(char * s)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
map_lseek_action(char * s)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
map_syscall(char * syscall)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  */
main(int argc,char ** argv)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 }
688