1 /*****************************************************************************
2 * RRDtool 1.1.x Copyright Tobias Oetiker, 1997 - 2002
3 *****************************************************************************
4 * rrd_tool.c Startup wrapper
5 *****************************************************************************/
10 void PrintUsage(char *cmd);
11 int CountArgs(char *aLine);
12 int CreateArgs(char *, char *, int, char **);
13 int HandleInputLine(int, char **, FILE*);
18 #define MAX_LENGTH 10000
21 void PrintUsage(char *cmd)
25 "RRDtool 1.1.x Copyright 1997-2003 by Tobias Oetiker <tobi@oetiker.ch>\n"
27 " Compiled " MAKE_TIMESTAMP "\n\n"
29 " Compiled " __DATE__ " " __TIME__ "\n\n"
31 "Usage: rrdtool [options] command command_options\n\n";
34 "Valid commands: create, update, updatev, graph, dump, restore,\n"
35 "\t\tlast, info, fetch, tune, resize, xport\n\n";
37 char help_listremote[] =
38 "Valid remote commands: quit, ls, cd, mkdir\n\n";
42 "* create - create a new RRD\n\n"
43 "\trrdtool create filename [--start|-b start time]\n"
44 "\t\t[--step|-s step]\n"
45 "\t\t[DS:ds-name:DST:dst arguments]\n"
46 "\t\t[RRA:CF:cf arguments]\n\n";
49 "* dump - dump an RRD to XML\n\n"
50 "\trrdtool dump filename.rrd >filename.xml\n\n";
53 "* info - returns the configuration and status of the RRD\n\n"
54 "\trrdtool info filename.rrd\n\n";
57 "* restore - restore an RRD file from its XML form\n\n"
58 "\trrdtool restore [--range-check|-r] [--force-overwrite|-f] filename.xml filename.rrd\n\n";
61 "* last - show last update time for RRD\n\n"
62 "\trrdtool last filename.rrd\n\n";
65 "* update - update an RRD\n\n"
66 "\trrdtool update filename\n"
67 "\t\t--template|-t ds-name:ds-name:...\n"
68 "\t\ttime|N:value[:value...]\n\n"
69 "\t\tat-time@value[:value...]\n\n"
70 "\t\t[ time:value[:value...] ..]\n\n";
73 "* updatev - a verbose verion of update\n"
74 "\treturns information about values, RRAs, and datasources updated\n\n"
75 "\trrdtool updatev filename\n"
76 "\t\t--template|-t ds-name:ds-name:...\n"
77 "\t\ttime|N:value[:value...]\n\n"
78 "\t\tat-time@value[:value...]\n\n"
79 "\t\t[ time:value[:value...] ..]\n\n";
82 "* fetch - fetch data out of an RRD\n\n"
83 "\trrdtool fetch filename.rrd CF\n"
84 "\t\t[--resolution|-r resolution]\n"
85 "\t\t[--start|-s start] [--end|-e end]\n\n";
88 "* graph - generate a graph from one or several RRD\n\n"
89 "\trrdtool graph filename [-s|--start seconds] [-e|--end seconds]\n"
90 "\t\t[-x|--x-grid x-axis grid and label]\n"
91 "\t\t[--alt-y-grid]\n"
92 "\t\t[-y|--y-grid y-axis grid and label]\n"
93 "\t\t[-v|--vertical-label string] [-w|--width pixels]\n"
94 "\t\t[-h|--height pixels] [-o|--logarithmic]\n"
95 "\t\t[-u|--upper-limit value] [-z|--lazy]\n"
96 "\t\t[-l|--lower-limit value] [-r|--rigid]\n"
97 "\t\t[-g|--no-legend]\n"
98 "\t\t[--font FONTTAG:size:font]\n"
99 "\t\t[--zoom factor]\n"
100 "\t\t[--alt-autoscale]\n"
101 "\t\t[--alt-autoscale-max]\n"
102 "\t\t[--units-exponent value]\n"
103 "\t\t[--step seconds]\n"
104 "\t\t[-f|--imginfo printfstr]\n"
105 "\t\t[-a|--imgformat PNG]\n"
106 "\t\t[-c|--color COLORTAG#rrggbb[aa]] [-t|--title string]\n"
107 "\t\t[DEF:vname=rrd:ds-name:CF]\n"
108 "\t\t[CDEF:vname=rpn-expression]\n"
109 "\t\t[PRINT:vname:CF:format]\n"
110 "\t\t[GPRINT:vname:CF:format]\n"
111 "\t\t[HRULE:value#rrggbb[aa][:legend]]\n"
112 "\t\t[VRULE:value#rrggbb[aa][:legend]]\n"
113 "\t\t[LINE{1|2|3}:vname[#rrggbb[aa][:legend]]]\n"
114 "\t\t[AREA:vname[#rrggbb[aa][:legend]]]\n"
115 "\t\t[STACK:vname[#rrggbb[aa][:legend]]]\n\n";
118 " * tune - Modify some basic properties of an RRD\n\n"
119 "\trrdtool tune filename\n"
120 "\t\t[--heartbeat|-h ds-name:heartbeat]\n"
121 "\t\t[--data-source-type|-d ds-name:DST]\n"
122 "\t\t[--data-source-rename|-r old-name:new-name]\n"
123 "\t\t[--minimum|-i ds-name:min] [--maximum|-a ds-name:max]\n"
124 "\t\t[--deltapos scale-value] [--deltaneg scale-value]\n"
125 "\t\t[--failure-threshold integer]\n"
126 "\t\t[--window-length integer]\n"
127 "\t\t[--alpha adaptation-parameter]\n"
128 "\t\t[--beta adaptation-parameter]\n"
129 "\t\t[--gamma adaptation-parameter]\n"
130 "\t\t[--gamma-deviation adaptation-parameter]\n"
131 "\t\t[--aberrant-reset ds-name]\n\n";
134 " * resize - alter the lenght of one of the RRAs in an RRD\n\n"
135 "\trrdtool resize filename rranum GROW|SHRINK rows\n\n";
138 "* xport - generate XML dump from one or several RRD\n\n"
139 "\trrdtool xport [-s|--start seconds] [-e|--end seconds]\n"
140 "\t\t[-m|--maxrows rows]\n"
141 "\t\t[--step seconds]\n"
142 "\t\t[DEF:vname=rrd:ds-name:CF]\n"
143 "\t\t[CDEF:vname=rpn-expression]\n"
144 "\t\t[XPORT:vname:legend]\n\n";
147 " * quit - closeing a session in remote mode\n\n"
148 "\trrdtool quit\n\n";
151 " * ls - lists all *.rrd files in current directory\n\n"
155 " * cd - changes the current directory\n\n"
156 "\trrdtool cd new direcotry\n\n";
159 " * mkdir - creates a new direcotry\n\n"
160 "\trrdtool mkdir newdirecotryname\n\n";
163 "RRDtool is distributed under the Terms of the GNU General\n"
164 "Public License Version 2. (www.gnu.org/copyleft/gpl.html)\n\n"
166 "For more information read the RRD manpages\n\n";
168 enum { C_NONE, C_CREATE, C_DUMP, C_INFO, C_RESTORE, C_LAST,
169 C_UPDATE, C_FETCH, C_GRAPH, C_TUNE, C_RESIZE, C_XPORT,
170 C_QUIT, C_LS, C_CD, C_MKDIR, C_UPDATEV };
172 int help_cmd = C_NONE;
176 if (!strcmp(cmd,"create"))
178 else if (!strcmp(cmd,"dump"))
180 else if (!strcmp(cmd,"info"))
182 else if (!strcmp(cmd,"restore"))
183 help_cmd = C_RESTORE;
184 else if (!strcmp(cmd,"last"))
186 else if (!strcmp(cmd,"update"))
188 else if (!strcmp(cmd,"updatev"))
189 help_cmd = C_UPDATEV;
190 else if (!strcmp(cmd,"fetch"))
192 else if (!strcmp(cmd,"graph"))
194 else if (!strcmp(cmd,"tune"))
196 else if (!strcmp(cmd,"resize"))
198 else if (!strcmp(cmd,"xport"))
200 else if (!strcmp(cmd,"quit"))
202 else if (!strcmp(cmd,"ls"))
204 else if (!strcmp(cmd,"cd"))
206 else if (!strcmp(cmd,"mkdir"))
209 fputs(help_main, stdout);
213 fputs(help_list, stdout);
215 fputs(help_listremote, stdout);
219 fputs(help_create, stdout);
222 fputs(help_dump, stdout);
225 fputs(help_info, stdout);
228 fputs(help_restore, stdout);
231 fputs(help_last, stdout);
234 fputs(help_update, stdout);
237 fputs(help_updatev, stdout);
240 fputs(help_fetch, stdout);
243 fputs(help_graph, stdout);
246 fputs(help_tune, stdout);
249 fputs(help_resize, stdout);
252 fputs(help_xport, stdout);
255 fputs(help_quit, stdout);
258 fputs(help_ls, stdout);
261 fputs(help_cd, stdout);
264 fputs(help_mkdir, stdout);
267 fputs(help_lic, stdout);
271 int main(int argc, char *argv[])
274 char aLine[MAX_LENGTH];
278 #ifdef MUST_DISABLE_SIGFPE
279 signal(SIGFPE,SIG_IGN);
281 #ifdef MUST_DISABLE_FPMASK
290 if (((argc == 2)||(argc == 3)) && !strcmp("-",argv[1]))
293 struct rusage myusage;
294 struct timeval starttime;
295 struct timeval currenttime;
298 tz.tz_minuteswest =0;
300 gettimeofday(&starttime,&tz);
304 if ((argc == 3) && strcmp("",argv[2])){
308 fprintf(stderr,"ERROR: can't change root to '%s' errno=%d\n",
319 if (strcmp(firstdir,"")){
322 fprintf(stderr,"ERROR: %s\n",strerror(errno));
327 fprintf(stderr,"ERROR: change root is not supported by your OS "
328 "or at least by this copy of rrdtool\n");
332 while (fgets(aLine, sizeof(aLine)-1, stdin)){
333 if ((argc = CountArgs(aLine)) == 0) {
334 fprintf(stderr,"ERROR: not enough arguments\n");
336 if ((myargv = (char **) malloc((argc+1) *
337 sizeof(char *))) == NULL) {
341 if ((argc=CreateArgs(argv[0], aLine, argc, myargv)) < 0) {
342 fprintf(stderr, "ERROR: creating arguments\n");
346 if (HandleInputLine(argc, myargv, stdout))
351 getrusage(RUSAGE_SELF,&myusage);
352 gettimeofday(¤ttime,&tz);
353 printf("OK u:%1.2f s:%1.2f r:%1.2f\n",
354 (double)myusage.ru_utime.tv_sec+
355 (double)myusage.ru_utime.tv_usec/1000000.0,
356 (double)myusage.ru_stime.tv_sec+
357 (double)myusage.ru_stime.tv_usec/1000000.0,
358 (double)(currenttime.tv_sec-starttime.tv_sec)
359 +(double)(currenttime.tv_usec-starttime.tv_usec)
364 fflush(stdout); /* this is important for pipes to work */
372 else if (argc == 3 && !strcmp(argv[1],"help"))
378 HandleInputLine(argc, argv, stderr);
382 /* HandleInputLine is NOT thread safe - due to readdir issues,
383 resolving them portably is not really simple. */
384 int HandleInputLine(int argc, char **argv, FILE* out)
386 #if defined(HAVE_OPENDIR) && defined (HAVE_READDIR)
387 DIR *curdir; /* to read current dir with ls */
390 #if defined(HAVE_SYS_STAT_H)
393 optind=0; /* reset gnu getopt */
394 opterr=0; /* no error messages */
397 if (argc>1 && strcmp("quit", argv[1]) == 0){
399 printf("ERROR: invalid parameter count for quit\n");
404 #if defined(HAVE_OPENDIR) && defined(HAVE_READDIR) && defined(HAVE_CHDIR)
405 if (argc>1 && strcmp("cd", argv[1]) == 0){
407 printf("ERROR: invalid parameter count for cd\n");
410 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
411 if (getuid()==0 && ! ChangeRoot){
412 printf("ERROR: chdir security problem - rrdtool is runnig as "
413 "root an no chroot!\n");
419 printf("ERROR: %s\n",strerror(errno));
423 if (argc>1 && strcmp("mkdir", argv[1]) == 0){
425 printf("ERROR: invalid parameter count for mkdir\n");
428 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
429 if (getuid()==0 && ! ChangeRoot){
430 printf("ERROR: mkdir security problem - rrdtool is runnig as "
431 "root an no chroot!\n");
437 printf("ERROR: %s\n",strerror(errno));
441 if (argc>1 && strcmp("ls", argv[1]) == 0){
443 printf("ERROR: invalid parameter count for ls\n");
446 if ((curdir=opendir("."))!=NULL){
447 while((dent=readdir(curdir))!=NULL){
448 if (!stat(dent->d_name,&st)){
449 if (S_ISDIR(st.st_mode)){
450 printf("d %s\n",dent->d_name);
452 if (strlen(dent->d_name)>4 && S_ISREG(st.st_mode)){
453 if (!strcmp(dent->d_name+NAMLEN(dent)-4,".rrd") ||
454 !strcmp(dent->d_name+NAMLEN(dent)-4,".RRD")){
455 printf("- %s\n",dent->d_name);
462 printf("ERROR: %s\n",strerror(errno));
467 #endif /* opendir and readdir */
471 || strcmp("help", argv[1]) == 0
472 || strcmp("--help", argv[1]) == 0
473 || strcmp("-help", argv[1]) == 0
474 || strcmp("-?", argv[1]) == 0
475 || strcmp("-h", argv[1]) == 0 ) {
480 if (strcmp("create", argv[1]) == 0)
481 rrd_create(argc-1, &argv[1]);
482 else if (strcmp("dump", argv[1]) == 0)
483 rrd_dump(argc-1, &argv[1]);
484 else if (strcmp("info", argv[1]) == 0
485 || strcmp("updatev", argv[1]) == 0){
487 if (strcmp("info",argv[1]) == 0)
488 data=rrd_info(argc-1, &argv[1]);
490 data=rrd_update_v(argc-1, &argv[1]);
493 printf ("%s = ", data->key);
496 switch (data->type) {
498 if (isnan (data->value.u_val))
501 printf ("%0.10e", data->value.u_val);
504 printf ("%lu", data->value.u_cnt);
507 printf ("%d", data->value.u_int);
510 printf ("\"%s\"", data->value.u_str);
511 free(data->value.u_str);
521 else if (strcmp("--version", argv[1]) == 0 ||
522 strcmp("version", argv[1]) == 0 ||
523 strcmp("v", argv[1]) == 0 ||
524 strcmp("-v", argv[1]) == 0 ||
525 strcmp("-version", argv[1]) == 0 )
526 printf("RRDtool 1.1.x Copyright (C) 1997-2003 by Tobias Oetiker <tobi@oetiker.ch>\n");
527 else if (strcmp("restore", argv[1]) == 0)
528 rrd_restore(argc-1, &argv[1]);
529 else if (strcmp("resize", argv[1]) == 0)
530 rrd_resize(argc-1, &argv[1]);
531 else if (strcmp("last", argv[1]) == 0)
532 printf("%ld\n",rrd_last(argc-1, &argv[1]));
533 else if (strcmp("update", argv[1]) == 0)
534 rrd_update(argc-1, &argv[1]);
535 else if (strcmp("fetch", argv[1]) == 0) {
536 time_t start,end, ti;
537 unsigned long step, ds_cnt,i,ii;
538 rrd_value_t *data,*datai;
540 if (rrd_fetch(argc-1, &argv[1],&start,&end,&step,&ds_cnt,&ds_namv,&data) != -1) {
543 for (i = 0; i<ds_cnt;i++)
544 printf("%20s",ds_namv[i]);
546 for (ti = start+step; ti <= end; ti += step){
547 printf("%10lu:", ti);
548 for (ii = 0; ii < ds_cnt; ii++)
549 printf(" %0.10e", *(datai++));
552 for (i=0;i<ds_cnt;i++)
557 } else if (strcmp("xport", argv[1]) == 0) {
559 unsigned long int j = 0;
560 time_t start,end, ti;
561 unsigned long step, col_cnt,row_cnt;
562 rrd_value_t *data,*ptr;
564 if(rrd_xport(argc-1, &argv[1], &xxsize,&start,&end,&step,&col_cnt,&legend_v,&data) != -1) {
565 row_cnt = (end-start)/step;
567 printf("<?xml version=\"1.0\" encoding=\"%s\"?>\n\n", XML_ENCODING);
568 printf("<%s>\n", ROOT_TAG);
569 printf(" <%s>\n", META_TAG);
570 printf(" <%s>%lu</%s>\n", META_START_TAG, start+step, META_START_TAG);
571 printf(" <%s>%lu</%s>\n", META_STEP_TAG, step, META_STEP_TAG);
572 printf(" <%s>%lu</%s>\n", META_END_TAG, end, META_END_TAG);
573 printf(" <%s>%lu</%s>\n", META_ROWS_TAG, row_cnt, META_ROWS_TAG);
574 printf(" <%s>%lu</%s>\n", META_COLS_TAG, col_cnt, META_COLS_TAG);
575 printf(" <%s>\n", LEGEND_TAG);
576 for (j = 0; j < col_cnt; j++) {
579 printf(" <%s>%s</%s>\n", LEGEND_ENTRY_TAG, entry, LEGEND_ENTRY_TAG);
583 printf(" </%s>\n", LEGEND_TAG);
584 printf(" </%s>\n", META_TAG);
585 printf(" <%s>\n", DATA_TAG);
586 for (ti = start+step; ti <= end; ti += step) {
587 printf (" <%s>", DATA_ROW_TAG);
588 printf ("<%s>%lu</%s>", COL_TIME_TAG, ti, COL_TIME_TAG);
589 for (j = 0; j < col_cnt; j++) {
590 rrd_value_t newval = DNAN;
593 printf("<%s>NaN</%s>", COL_DATA_TAG, COL_DATA_TAG);
595 printf("<%s>%0.10e</%s>", COL_DATA_TAG, newval, COL_DATA_TAG);
599 printf("</%s>\n", DATA_ROW_TAG);
602 printf(" </%s>\n", DATA_TAG);
603 printf("</%s>\n", ROOT_TAG);
606 else if (strcmp("graph", argv[1]) == 0) {
608 const char *imgfile = argv[2]; /* rrd_graph changes argv pointer */
611 int tostdout = (strcmp(argv[2],"-") == 0);
612 if( rrd_graph(argc-1, &argv[1], &calcpr, &xsize, &ysize, NULL) != -1 ) {
614 printf ("%dx%d\n",xsize,ysize);
616 for(i=0;calcpr[i];i++){
618 printf("%s\n",calcpr[i]);
625 } else if (strcmp("tune", argv[1]) == 0)
626 rrd_tune(argc-1, &argv[1]);
628 rrd_set_error("unknown function '%s'",argv[1]);
630 if (rrd_test_error()) {
631 fprintf(out, "ERROR: %s\n",rrd_get_error());
637 int CountArgs(char *aLine)
642 while (aLine[i] == ' ') i++;
643 while (aLine[i] != 0){
644 if((aLine[i]== ' ') && inarg){
647 if((aLine[i]!= ' ') && ! inarg){
657 * CreateArgs - take a string (aLine) and tokenize
659 int CreateArgs(char *pName, char *aLine, int argc, char **argv)
668 /* remove trailing space and newlines */
669 while (len && aLine[len] <= ' ') {
670 aLine[len] = 0 ; len--;
672 /* sikp leading blanks */
673 while (*aLine && *aLine <= ' ') aLine++;
700 pargv[argc++] = putP;
708 pargv[argc++] = putP;