f118da6fb11e9fdf0bfabd9c8cb7f6e2c589a484
[rrdtool.git] / src / rrd_create.c
1 /*****************************************************************************
2  * RRDtool 1.0.33  Copyright Tobias Oetiker, 1997 - 2000
3  *****************************************************************************
4  * rrd_create.c  creates new rrds
5  *****************************************************************************/
6
7 #include "rrd_tool.h"
8
9
10 int
11 rrd_create(int argc, char **argv) 
12 {
13     rrd_t          rrd;
14     long                i,long_tmp;
15     time_t             last_up;
16     struct time_value last_up_tv;
17     char *parsetime_error = NULL;
18
19     /* init last_up */
20     last_up = time(NULL)-10;
21     /* init rrd clean */
22     rrd_init(&rrd);
23     /* static header */
24     if((rrd.stat_head = calloc(1,sizeof(stat_head_t)))==NULL){
25         rrd_set_error("allocating rrd.stat_head");
26         return(-1);
27     }
28
29     /* live header */
30     if((rrd.live_head = calloc(1,sizeof(live_head_t)))==NULL){
31         rrd_set_error("allocating rrd.live_head");
32         return(-1);
33     }
34
35     /* set some defaults */
36     strcpy(rrd.stat_head->cookie,RRD_COOKIE);
37     strcpy(rrd.stat_head->version,RRD_VERSION);
38     rrd.stat_head->float_cookie = FLOAT_COOKIE;
39     rrd.stat_head->ds_cnt = 0; /* this will be adjusted later */
40     rrd.stat_head->rra_cnt = 0; /* ditto */
41     rrd.stat_head->pdp_step = 300; /* 5 minute default */
42
43     /* a default value */
44     rrd.ds_def = NULL;
45     rrd.rra_def = NULL;
46     
47     while (1){
48         static struct option long_options[] =
49         {
50             {"start",      required_argument, 0, 'b'},
51             {"step",        required_argument,0,'s'},
52             {0,0,0,0}
53         };
54         int option_index = 0;
55         int opt;
56         opt = getopt_long(argc, argv, "b:s:", 
57                           long_options, &option_index);
58         
59         if (opt == EOF)
60           break;
61         
62         switch(opt) {
63         case 'b':
64             if ((parsetime_error = parsetime(optarg, &last_up_tv))) {
65                 rrd_set_error("start time: %s", parsetime_error );
66                 rrd_free(&rrd);
67                 return(-1);
68             }
69             if (last_up_tv.type == RELATIVE_TO_END_TIME ||
70                 last_up_tv.type == RELATIVE_TO_START_TIME) {
71                 rrd_set_error("specifying time relative to the 'start' "
72                               "or 'end' makes no sense here");
73                 rrd_free(&rrd);
74                 return(-1);
75             }
76
77             last_up = mktime(&last_up_tv.tm) + last_up_tv.offset;
78             
79             if (last_up < 3600*24*365*10){
80                 rrd_set_error("the first entry to the RRD should be after 1980");
81                 rrd_free(&rrd);
82                 return(-1);
83             }   
84             break;
85
86         case 's':
87             long_tmp = atol(optarg);
88             if (long_tmp < 1){
89                 rrd_set_error("step size should be no less than one second");
90                 rrd_free(&rrd);
91                 return(-1);
92             }
93             rrd.stat_head->pdp_step = long_tmp;
94             break;
95
96         case '?':
97             if (optopt != 0)
98                 rrd_set_error("unknown option '%c'", optopt);
99             else
100                 rrd_set_error("unknown option '%s'",argv[optind-1]);
101             rrd_free(&rrd);
102             return(-1);
103         }
104     }
105     rrd.live_head->last_up = last_up;
106
107     for(i=optind+1;i<argc;i++){
108         char minstr[DS_NAM_SIZE], maxstr[DS_NAM_SIZE];  
109         int ii;
110         if (strncmp(argv[i],"DS:",3)==0){
111             size_t old_size = sizeof(ds_def_t)*(rrd.stat_head->ds_cnt);
112             if((rrd.ds_def = rrd_realloc(rrd.ds_def,
113                                      old_size+sizeof(ds_def_t)))==NULL){
114                 rrd_set_error("allocating rrd.ds_def");
115                 rrd_free(&rrd);
116                 return(-1);     
117             }
118             memset(&rrd.ds_def[rrd.stat_head->ds_cnt], 0, sizeof(ds_def_t));
119             if (sscanf(&argv[i][3],
120                        DS_NAM_FMT ":" DST_FMT ":%lu:%18[^:]:%18[^:]",
121                        rrd.ds_def[rrd.stat_head->ds_cnt].ds_nam,
122                        rrd.ds_def[rrd.stat_head->ds_cnt].dst,
123                        &rrd.ds_def[rrd.stat_head->ds_cnt].par[DS_mrhb_cnt].u_cnt,
124                        minstr,maxstr) == 5){
125                 /* check for duplicate datasource names */
126                 for(ii=0;ii<rrd.stat_head->ds_cnt;ii++){
127                         if(strcmp(rrd.ds_def[rrd.stat_head->ds_cnt].ds_nam,
128                                   rrd.ds_def[ii].ds_nam) == 0){
129                                 rrd_set_error("Duplicate DS name: %s",rrd.ds_def[ii].ds_nam);
130                                 rrd_free(&rrd);
131                                 return(-1);
132                         }                                                               
133                 }
134                 if(dst_conv(rrd.ds_def[rrd.stat_head->ds_cnt].dst) == -1){
135                     rrd_free(&rrd);
136                     return (-1);
137                 }
138                 if (minstr[0] == 'U' && minstr[1] == 0)
139                     rrd.ds_def[rrd.stat_head->ds_cnt].par[DS_min_val].u_val = DNAN;
140                 else
141                     rrd.ds_def[rrd.stat_head->ds_cnt].par[DS_min_val].u_val = atof(minstr);
142                 
143                 if (maxstr[0] == 'U' && maxstr[1] == 0)
144                     rrd.ds_def[rrd.stat_head->ds_cnt].par[DS_max_val].u_val = DNAN;
145                 else
146                     rrd.ds_def[rrd.stat_head->ds_cnt].par[DS_max_val].u_val  = atof(maxstr);
147                 
148                 if (! isnan(rrd.ds_def[rrd.stat_head->ds_cnt].par[DS_min_val].u_val) &&
149                     ! isnan(rrd.ds_def[rrd.stat_head->ds_cnt].par[DS_max_val].u_val) &&
150                     rrd.ds_def[rrd.stat_head->ds_cnt].par[DS_min_val].u_val
151                     >= rrd.ds_def[rrd.stat_head->ds_cnt].par[DS_max_val].u_val ) {
152                     rrd_set_error("min must be less than max in DS definition");
153                     rrd_free(&rrd);
154                     return (-1);                
155                 }
156                 rrd.stat_head->ds_cnt++;            
157             } else {
158                 rrd_set_error("can't parse argument '%s'",argv[i]);
159                 rrd_free(&rrd);
160                 return (-1);            
161             }
162         } else if (strncmp(argv[i],"RRA:",3)==0){
163             size_t old_size = sizeof(rra_def_t)*(rrd.stat_head->rra_cnt);
164             if((rrd.rra_def = rrd_realloc(rrd.rra_def,
165                                       old_size+sizeof(rra_def_t)))==NULL){
166                 rrd_set_error("allocating rrd.rra_def");
167                 rrd_free(&rrd);
168                 return(-1);     
169             }
170             memset(&rrd.rra_def[rrd.stat_head->rra_cnt], 0, sizeof(rra_def_t));
171             if (sscanf(&argv[i][4],
172                        CF_NAM_FMT ":%lf:%lu:%lu",
173                        rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam,
174                        &rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_cdp_xff_val].u_val,
175                        &rrd.rra_def[rrd.stat_head->rra_cnt].pdp_cnt,
176                        &rrd.rra_def[rrd.stat_head->rra_cnt].row_cnt) == 4){
177                 if(cf_conv(rrd.rra_def[rrd.stat_head->rra_cnt].cf_nam) == -1){
178                     rrd_free(&rrd);
179                     return (-1);
180                 }
181                 if (rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_cdp_xff_val].u_val<0.0 ||
182                     rrd.rra_def[rrd.stat_head->rra_cnt].par[RRA_cdp_xff_val].u_val>=1.0) {
183                     rrd_set_error("the xff must always be >= 0 and < 1");
184                     rrd_free(&rrd);
185                     return (-1);
186                 }
187                 rrd.stat_head->rra_cnt++;                       
188             }
189             else {  
190                 rrd_set_error("can't parse argument '%s'",argv[i]);
191                 rrd_free(&rrd);
192                 return (-1);            
193             }
194
195         } else {
196             rrd_set_error("can't parse argument '%s'",argv[i]);
197             rrd_free(&rrd);
198             return -1;
199         }
200     }
201
202
203     if (rrd.stat_head->rra_cnt < 1){
204         rrd_set_error("you must define at least one Round Robin Archive");
205         rrd_free(&rrd);
206         return(-1);
207     }
208
209     if (rrd.stat_head->ds_cnt < 1){
210         rrd_set_error("you must define at least one Data Source");
211         rrd_free(&rrd);
212         return(-1);
213     }
214     return rrd_create_fn(argv[optind],&rrd);
215 }
216
217 /* create and empty rrd file according to the specs given */
218
219 int
220 rrd_create_fn(char *file_name, rrd_t *rrd)
221 {
222     unsigned long    i,ii;
223     FILE             *rrd_file;
224     rrd_value_t       unknown = DNAN ;
225
226     if ((rrd_file = fopen(file_name,"wb")) == NULL ) {
227         rrd_set_error("creating '%s': %s",file_name,strerror(errno));
228         free(rrd->stat_head);
229         free(rrd->ds_def);
230         free(rrd->rra_def);
231         return(-1);
232     }
233     
234     fwrite(rrd->stat_head,
235            sizeof(stat_head_t), 1, rrd_file);
236
237     fwrite(rrd->ds_def,
238            sizeof(ds_def_t), rrd->stat_head->ds_cnt, rrd_file);
239
240     fwrite(rrd->rra_def,
241            sizeof(rra_def_t), rrd->stat_head->rra_cnt, rrd_file);
242     
243     fwrite(rrd->live_head,
244            sizeof(live_head_t),1, rrd_file);
245
246     if((rrd->pdp_prep = calloc(1,sizeof(pdp_prep_t))) == NULL){
247         rrd_set_error("allocating pdp_prep");
248         rrd_free(rrd);
249         fclose(rrd_file);
250         return(-1);
251     }
252
253     strcpy(rrd->pdp_prep->last_ds,"UNKN");
254
255     rrd->pdp_prep->scratch[PDP_val].u_val = 0.0;
256     rrd->pdp_prep->scratch[PDP_unkn_sec_cnt].u_cnt = 
257         rrd->live_head->last_up % rrd->stat_head->pdp_step;
258
259     for(i=0; i < rrd->stat_head->ds_cnt; i++)
260         fwrite( rrd->pdp_prep,sizeof(pdp_prep_t),1,rrd_file);
261     
262     if((rrd->cdp_prep = calloc(1,sizeof(cdp_prep_t))) == NULL){
263         rrd_set_error("allocating cdp_prep");
264         rrd_free(rrd);
265         fclose(rrd_file);
266         return(-1);
267     }
268
269     /* can not be zero because we don't know nothing ... */
270     rrd->cdp_prep->scratch[CDP_val].u_val = DNAN;
271     for(i=0; i < rrd->stat_head->rra_cnt; i++) {
272
273         /* startup missing pdp count */
274         rrd->cdp_prep->scratch[CDP_unkn_pdp_cnt].u_cnt = 
275             ((rrd->live_head->last_up -
276              rrd->pdp_prep->scratch[PDP_unkn_sec_cnt].u_cnt)
277             % (rrd->stat_head->pdp_step 
278                * rrd->rra_def[i].pdp_cnt)) / rrd->stat_head->pdp_step;  
279
280
281         for(ii=0; ii < rrd->stat_head->ds_cnt; ii++) {
282             fwrite( rrd->cdp_prep,sizeof(cdp_prep_t),1,rrd_file);
283         }
284     }
285
286     /* now, we must make sure that the rest of the rrd
287        struct is properly initialized */
288
289     if((rrd->rra_ptr = calloc(1,sizeof(rra_ptr_t))) == NULL) {
290         rrd_set_error("allocating rra_ptr");
291         rrd_free(rrd);
292         fclose(rrd_file);
293         return(-1);
294     }
295
296     rrd->rra_ptr->cur_row = 0;
297     for(i=0; i <rrd->stat_head->rra_cnt; i++)
298         fwrite( rrd->rra_ptr,
299                 sizeof(rra_ptr_t), 1,rrd_file);
300
301
302
303     /* write the empty data area */
304     for(i=0; 
305         i <  rrd->stat_head->rra_cnt;
306         i++)
307         {
308             for(ii=0; 
309                 ii <  rrd->rra_def[i].row_cnt 
310                     * rrd->stat_head->ds_cnt;
311                 ii++){
312                 fwrite(&unknown,sizeof(rrd_value_t),1,rrd_file);
313             }
314         }
315
316     /* lets see if we had an error */
317     if(ferror(rrd_file)){
318         rrd_set_error("a file error occurred while creating '%s'",file_name);
319         fclose(rrd_file);       
320         rrd_free(rrd);
321         return(-1);
322     }
323
324     fclose(rrd_file);    
325     rrd_free(rrd);
326     return (0);
327 }