Code

Imported upstream version 1.2.26
[pkg-rrdtool.git] / src / rrd_open.c
1 /*****************************************************************************
2  * RRDtool 1.2.26  Copyright by Tobi Oetiker, 1997-2007
3  *****************************************************************************
4  * rrd_open.c  Open an RRD File
5  *****************************************************************************
6  * $Id: rrd_open.c 1235 2007-11-20 00:15:07Z 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 {
75     
76     char *mode = NULL;
77     int version;
78     
79     rrd_init(rrd);
80     if (rdwr == RRD_READONLY) {
81         mode = "rb";
82     } else {
83         mode = "rb+";
84     }
85     
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);
103         
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 */
116     
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);
184 void rrd_init(rrd_t *rrd)
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;
196 void rrd_free(rrd_t *rrd)
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);
208 /* routine used by external libraries to free memory allocated by
209  * rrd library */
210 void rrd_freemem(void *mem)
213     if (mem) free(mem);
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;