1/*
2 * blktrace output analysis: generate a timeline & gather statistics
3 *
4 * Copyright (C) 2006 Alan D. Brunelle <Alan.Brunelle@hp.com>
5 *
6 *  This program is free software; you can redistribute it and/or modify
7 *  it under the terms of the GNU General Public License as published by
8 *  the Free Software Foundation; either version 2 of the License, or
9 *  (at your option) any later version.
10 *
11 *  This program is distributed in the hope that it will be useful,
12 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 *  GNU General Public License for more details.
15 *
16 *  You should have received a copy of the GNU General Public License
17 *  along with this program; if not, write to the Free Software
18 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 *
20 */
21#include <errno.h>
22#include <stdio.h>
23#include <string.h>
24#include <unistd.h>
25#include <sys/types.h>
26#include <sys/stat.h>
27#include <sys/time.h>
28#include <sys/resource.h>
29#include <fcntl.h>
30
31#define INLINE_DECLARE
32#include "globals.h"
33
34struct file_info {
35	struct list_head head;
36	FILE *ofp;
37	char *oname;
38};
39
40struct buf_info {
41	struct list_head head;
42	void *buf;
43};
44
45LIST_HEAD(files_to_clean);
46LIST_HEAD(all_bufs);
47
48static void clean_files(void)
49{
50	struct list_head *p, *q;
51
52	list_for_each_safe(p, q, &files_to_clean) {
53		struct stat buf;
54		struct file_info *fip = list_entry(p, struct file_info, head);
55
56		fclose(fip->ofp);
57		if (!stat(fip->oname, &buf) && (buf.st_size == 0))
58			unlink(fip->oname);
59
60		list_del(&fip->head);
61		free(fip->oname);
62		free(fip);
63	}
64}
65
66static void clean_bufs(void)
67{
68	struct list_head *p, *q;
69
70	list_for_each_safe(p, q, &all_bufs) {
71		struct buf_info *bip = list_entry(p, struct buf_info, head);
72
73		list_del(&bip->head);
74		free(bip->buf);
75		free(bip);
76	}
77}
78
79#ifndef _ANDROID_
80/*
81 * Due to the N(devs) parts of a lot of the output features provided
82 * by btt, it will fail opens on large(ish) systems. Here we try to
83 * keep bumping our open file limits, and if those fail, we return NULL.
84 *
85 * Root users will probably be OK with this, others...
86 */
87static int increase_limit(int resource, rlim_t increase)
88{
89	struct rlimit rlim;
90	int save_errno = errno;
91
92	if (!getrlimit(resource, &rlim)) {
93		rlim.rlim_cur += increase;
94		if (rlim.rlim_cur >= rlim.rlim_max)
95			rlim.rlim_max = rlim.rlim_cur + increase;
96
97		if (!setrlimit(resource, &rlim))
98			return 1;
99	}
100
101	errno = save_errno;
102	return 0;
103}
104#endif
105
106static int handle_open_failure(void)
107{
108	if (errno == ENFILE || errno == EMFILE)
109#ifndef _ANDROID_
110		return increase_limit(RLIMIT_NOFILE, 16);
111#else
112		return -ENOSYS;
113#endif
114
115	return 0;
116}
117
118void add_file(FILE *fp, char *oname)
119{
120	struct file_info *fip = malloc(sizeof(*fip));
121
122	fip->ofp = fp;
123	fip->oname = oname;
124	list_add_tail(&fip->head, &files_to_clean);
125}
126
127void add_buf(void *buf)
128{
129	struct buf_info *bip = malloc(sizeof(*bip));
130
131	bip->buf = buf;
132	list_add_tail(&bip->head, &all_bufs);
133}
134
135void clean_allocs(void)
136{
137	clean_files();
138	clean_bufs();
139}
140
141char *make_dev_hdr(char *pad, size_t len, struct d_info *dip, int add_parens)
142{
143	if (dip->devmap)
144		snprintf(pad, len, "%s", dip->devmap);
145	else if (add_parens)
146		snprintf(pad, len, "(%3d,%3d)",
147			 MAJOR(dip->device), MINOR(dip->device));
148	else
149		snprintf(pad, len, "%d,%d",
150			 MAJOR(dip->device), MINOR(dip->device));
151
152	return pad;
153}
154
155FILE *my_fopen(const char *path, const char *mode)
156{
157	FILE *fp;
158
159	do {
160		fp = fopen(path, mode);
161	} while (fp == NULL && handle_open_failure());
162
163	return fp;
164}
165
166int my_open(const char *path, int flags)
167{
168	int fd;
169
170	do {
171		fd = open(path, flags);
172	} while (fd < 0 && handle_open_failure());
173
174	return fd;
175}
176
177void dbg_ping(void) {}
178