Fix btt to handle large numbers of output files
[blktrace.git] / btt / misc.c
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
30 #define INLINE_DECLARE
31 #include "globals.h"
32
33 int in_devices(struct blk_io_trace *t)
34 {
35         int i;
36         unsigned int mjr, mnr;
37         char *p = devices;
38
39         if (p == NULL) return 1;        /* Allow anything */
40
41         for (;;) {
42                 i = sscanf(p, "%u,%u;", &mjr, &mnr);
43                 if ((mjr == MAJOR(t->device) && (mnr == MINOR(t->device))))
44                         return 1;
45
46                 p = strchr(p, ';');
47                 if (!p)
48                         break;
49                 p++;
50         }
51
52         return 0;
53 }
54
55 void add_file(struct file_info **fipp, FILE *fp, char *oname)
56 {
57         struct file_info *fip = malloc(sizeof(*fip));
58
59         fip->ofp = fp;
60         fip->oname = oname;
61         fip->next = *fipp;
62         *fipp = fip;
63 }
64
65 void clean_files(struct file_info **fipp)
66 {
67         struct stat buf;
68         struct file_info *fip;
69
70         while ((fip = *fipp) != NULL) {
71                 *fipp = fip->next;
72
73                 fclose(fip->ofp);
74                 if (!stat(fip->oname, &buf) && (buf.st_size == 0))
75                         unlink(fip->oname);
76
77                 free(fip->oname);
78                 free(fip);
79         }
80 }
81
82 struct buf_info {
83         struct buf_info *next;
84         void *buf;
85 } *all_bufs;
86 void add_buf(void *buf)
87 {
88         struct buf_info *bip = malloc(sizeof(*bip));
89
90         bip->buf = buf;
91         bip->next = all_bufs;
92         all_bufs = bip;
93 }
94
95 void clean_bufs(void)
96 {
97         struct buf_info *bip;
98
99         while ((bip = all_bufs) != NULL) {
100                 all_bufs = bip->next;
101                 free(bip->buf);
102                 free(bip);
103         }
104 }
105
106 char *make_dev_hdr(char *pad, size_t len, struct d_info *dip, int add_parens)
107 {
108         if (dip->map == NULL) {
109                 if (add_parens)
110                         snprintf(pad, len, "(%3d,%3d)",
111                                  MAJOR(dip->device), MINOR(dip->device));
112                 else
113                         snprintf(pad, len, "%d,%d",
114                                  MAJOR(dip->device), MINOR(dip->device));
115         }
116         else
117                 snprintf(pad, len, "%s", dip->map->device);
118
119         return pad;
120 }
121
122 /*
123  * Due to the N(devs) parts of a lot of the output features provided
124  * by btt, it will fail opens on large(ish) systems. Here we try to
125  * keep bumping our open file limits, and if those fail, we return NULL.
126  *
127  * Root users will probably be OK with this, others...
128  */
129 FILE *my_fopen(const char *path, const char *mode)
130 {
131         FILE *fp;
132
133         fp = fopen(path, mode);
134         while (fp == NULL) {
135                 if (errno == ENFILE || errno == EMFILE) {
136                         struct rlimit rlim;
137
138                         if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
139                                 perror("get: RLIMIT_NOFILE");
140                                 return NULL;
141                         }
142
143                         rlim.rlim_cur++;
144                         if (rlim.rlim_cur >= rlim.rlim_max)
145                                 rlim.rlim_max++;
146
147                         if (setrlimit(RLIMIT_NOFILE, &rlim) < 0) {
148                                 perror("set: RLIMIT_NOFILE");
149                                 return NULL;
150                         }
151                 }
152                 else {
153                         perror(path);
154                         return NULL;
155                 }
156
157                 fp = fopen(path, mode);
158         }
159
160         return fp;
161 }
162
163 void dbg_ping(void) {}