1 /*****************************************************************************
2 * RRDtool 1.2.27 Copyright by Tobi Oetiker, 1997-2008
3 *****************************************************************************
4 * rrd_open.c Open an RRD File
5 *****************************************************************************
6 * $Id: rrd_open.c 1286 2008-02-17 10:08:10Z oetiker $
7 * $Log$
8 * Revision 1.10 2004/05/26 22:11:12 oetiker
9 * reduce compiler warnings. Many small fixes. -- Mike Slifcak <slif@bellsouth.net>
10 *
11 * Revision 1.9 2003/04/29 21:56:49 oetiker
12 * readline in rrd_open.c reads the file in 8 KB blocks, and calls realloc for
13 * each block. realloc is very slow in Mac OS X for huge blocks, e.g. when
14 * restoring databases from huge xml files. This patch finds the size of the
15 * file, and starts out with malloc'ing the full size.
16 * -- Peter Speck <speck@ruc.dk>
17 *
18 * Revision 1.8 2003/04/11 19:43:44 oetiker
19 * New special value COUNT which allows calculations based on the position of a
20 * value within a data set. Bug fix in rrd_rpncalc.c. PREV returned erroneus
21 * value for the second value. Bug fix in rrd_restore.c. Bug causing seek error
22 * when accesing an RRD restored from an xml that holds an RRD version <3.
23 * -- Ruben Justo <ruben@ainek.com>
24 *
25 * Revision 1.7 2003/03/31 21:22:12 oetiker
26 * enables RRDtool updates with microsecond or in case of windows millisecond
27 * precision. This is needed to reduce time measurement error when archive step
28 * is small. (<30s) -- Sasha Mikheev <sasha@avalon-net.co.il>
29 *
30 * Revision 1.6 2003/02/13 07:05:27 oetiker
31 * Find attached the patch I promised to send to you. Please note that there
32 * are three new source files (src/rrd_is_thread_safe.h, src/rrd_thread_safe.c
33 * and src/rrd_not_thread_safe.c) and the introduction of librrd_th. This
34 * library is identical to librrd, but it contains support code for per-thread
35 * global variables currently used for error information only. This is similar
36 * to how errno per-thread variables are implemented. librrd_th must be linked
37 * alongside of libpthred
38 *
39 * There is also a new file "THREADS", holding some documentation.
40 *
41 * -- Peter Stamfest <peter@stamfest.at>
42 *
43 * Revision 1.5 2002/06/20 00:21:03 jake
44 * More Win32 build changes; thanks to Kerry Calvert.
45 *
46 * Revision 1.4 2002/02/01 20:34:49 oetiker
47 * fixed version number and date/time
48 *
49 * Revision 1.3 2001/03/04 13:01:55 oetiker
50 * Aberrant Behavior Detection support. A brief overview added to rrdtool.pod.
51 * Major updates to rrd_update.c, rrd_create.c. Minor update to other core files.
52 * This is backwards compatible! But new files using the Aberrant stuff are not readable
53 * by old rrdtool versions. See http://cricket.sourceforge.net/aberrant/rrd_hw.htm
54 * -- Jake Brutlag <jakeb@corp.webtv.net>
55 *
56 * Revision 1.2 2001/03/04 10:29:20 oetiker
57 * fixed filedescriptor leak
58 * -- Mike Franusich <mike@franusich.com>
59 *
60 * Revision 1.1.1.1 2001/02/25 22:25:05 oetiker
61 * checkin
62 *
63 *****************************************************************************/
65 #include "rrd_tool.h"
66 #define MEMBLK 8192
68 /* open a database file, return its header and a open filehandle */
69 /* positioned to the first cdp in the first rra */
71 int
72 rrd_open(const char *file_name, FILE **in_file, rrd_t *rrd, int rdwr)
73 {
76 char *mode = NULL;
77 int version;
79 rrd_init(rrd);
80 if (rdwr == RRD_READONLY) {
81 mode = "rb";
82 } else {
83 mode = "rb+";
84 }
86 if (((*in_file) = fopen(file_name,mode)) == NULL ){
87 rrd_set_error("opening '%s': %s",file_name, rrd_strerror(errno));
88 return (-1);
89 }
91 #ifdef HAVE_POSIX_FADVISE
92 /* In general we need no read-ahead when dealing with rrd_files.
93 When we stop reading, it is highly unlikely that we start up again.
94 In this manner we actually save time and diskaccess (and buffer cache).
95 Thanks to Dave Plonka for the Idea of using POSIX_FADV_RANDOM here. */
96 /* if (0 != posix_fadvise(fileno(*in_file), 0, 0, POSIX_FADV_RANDOM)) {
97 rrd_set_error("setting POSIX_FADV_RANDOM on '%s': %s",file_name, rrd_strerror(errno));
98 fclose(*in_file);
99 return(-1); */
101 /* if it does not work, then this is sad, but we should not quit */
102 posix_fadvise(fileno(*in_file), 0, 0, POSIX_FADV_RANDOM);
104 /* } */
105 #endif
107 /*
108 if (rdwr == RRD_READWRITE)
109 {
110 if (setvbuf((*in_file),NULL,_IONBF,2)) {
111 rrd_set_error("failed to disable the stream buffer\n");
112 return (-1);
113 }
114 }
115 */
117 #define MYFREAD(MYVAR,MYVART,MYCNT) \
118 if ((MYVAR = malloc(sizeof(MYVART) * MYCNT)) == NULL) {\
119 rrd_set_error("" #MYVAR " malloc"); \
120 fclose(*in_file); \
121 return (-1); } \
122 fread(MYVAR,sizeof(MYVART),MYCNT, *in_file);
125 MYFREAD(rrd->stat_head, stat_head_t, 1)
126 /* lets see if the first read worked */
127 if (ferror( *in_file ) || feof(*in_file)) {
128 rrd_set_error("reading the cookie off %s faild",file_name);
129 fclose(*in_file);
130 return(-1);
131 }
133 /* lets do some test if we are on track ... */
134 if (strncmp(rrd->stat_head->cookie,RRD_COOKIE,4) != 0){
135 rrd_set_error("'%s' is not an RRD file",file_name);
136 free(rrd->stat_head);
137 rrd->stat_head = NULL;
138 fclose(*in_file);
139 return(-1);}
141 if (rrd->stat_head->float_cookie != FLOAT_COOKIE){
142 rrd_set_error("This RRD was created on other architecture");
143 free(rrd->stat_head);
144 rrd->stat_head = NULL;
145 fclose(*in_file);
146 return(-1);}
148 version = atoi(rrd->stat_head->version);
150 if (version > atoi(RRD_VERSION)){
151 rrd_set_error("can't handle RRD file version %s",
152 rrd->stat_head->version);
153 free(rrd->stat_head);
154 rrd->stat_head = NULL;
155 fclose(*in_file);
156 return(-1);}
159 MYFREAD(rrd->ds_def, ds_def_t, rrd->stat_head->ds_cnt)
160 MYFREAD(rrd->rra_def, rra_def_t, rrd->stat_head->rra_cnt)
161 /* handle different format for the live_head */
162 if(version < 3) {
163 rrd->live_head = (live_head_t *)malloc(sizeof(live_head_t));
164 if(rrd->live_head == NULL) {
165 rrd_set_error("live_head_t malloc");
166 fclose(*in_file);
167 return (-1);
168 }
169 fread(&rrd->live_head->last_up, sizeof(long), 1, *in_file);
170 rrd->live_head->last_up_usec = 0;
171 }
172 else {
173 MYFREAD(rrd->live_head, live_head_t, 1)
174 }
175 MYFREAD(rrd->pdp_prep, pdp_prep_t, rrd->stat_head->ds_cnt)
176 MYFREAD(rrd->cdp_prep, cdp_prep_t, (rrd->stat_head->rra_cnt
177 * rrd->stat_head->ds_cnt))
178 MYFREAD(rrd->rra_ptr, rra_ptr_t, rrd->stat_head->rra_cnt)
179 #undef MYFREAD
181 return(0);
182 }
184 void rrd_init(rrd_t *rrd)
185 {
186 rrd->stat_head = NULL;
187 rrd->ds_def = NULL;
188 rrd->rra_def = NULL;
189 rrd->live_head = NULL;
190 rrd->rra_ptr = NULL;
191 rrd->pdp_prep = NULL;
192 rrd->cdp_prep = NULL;
193 rrd->rrd_value = NULL;
194 }
196 void rrd_free(rrd_t *rrd)
197 {
198 if (rrd->stat_head) free(rrd->stat_head);
199 if (rrd->ds_def) free(rrd->ds_def);
200 if (rrd->rra_def) free(rrd->rra_def);
201 if (rrd->live_head) free(rrd->live_head);
202 if (rrd->rra_ptr) free(rrd->rra_ptr);
203 if (rrd->pdp_prep) free(rrd->pdp_prep);
204 if (rrd->cdp_prep) free(rrd->cdp_prep);
205 if (rrd->rrd_value) free(rrd->rrd_value);
206 }
208 /* routine used by external libraries to free memory allocated by
209 * rrd library */
210 void rrd_freemem(void *mem)
211 {
213 if (mem) free(mem);
214 }
216 int readfile(const char *file_name, char **buffer, int skipfirst){
217 long writecnt=0,totalcnt = MEMBLK;
218 long offset = 0;
219 FILE *input=NULL;
220 char c ;
221 if ((strcmp("-",file_name) == 0)) { input = stdin; }
222 else {
223 if ((input = fopen(file_name,"rb")) == NULL ){
224 rrd_set_error("opening '%s': %s",file_name,rrd_strerror(errno));
225 return (-1);
226 }
227 }
228 if (skipfirst){
229 do { c = getc(input); offset++; } while (c != '\n' && ! feof(input));
230 }
231 if (strcmp("-",file_name)) {
232 fseek(input, 0, SEEK_END);
233 /* have extra space for detecting EOF without realloc */
234 totalcnt = (ftell(input) + 1) / sizeof(char) - offset;
235 if (totalcnt < MEMBLK)
236 totalcnt = MEMBLK; /* sanitize */
237 fseek(input, offset * sizeof(char), SEEK_SET);
238 }
239 if (((*buffer) = (char *) malloc((totalcnt+4) * sizeof(char))) == NULL) {
240 perror("Allocate Buffer:");
241 exit(1);
242 };
243 do{
244 writecnt += fread((*buffer)+writecnt, 1, (totalcnt - writecnt) * sizeof(char),input);
245 if (writecnt >= totalcnt){
246 totalcnt += MEMBLK;
247 if (((*buffer)=rrd_realloc((*buffer), (totalcnt+4) * sizeof(char)))==NULL){
248 perror("Realloc Buffer:");
249 exit(1);
250 };
251 }
252 } while (! feof(input));
253 (*buffer)[writecnt] = '\0';
254 if (strcmp("-",file_name) != 0) {fclose(input);};
255 return writecnt;
256 }