1 /*****************************************************************************
2 * RRDtool 1.2.12 Copyright by Tobi Oetiker, 1997-2005
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 " PACKAGE_VERSION " Copyright 1997-2006 by Tobias Oetiker <tobi@oetiker.ch>\n"
26 " Compiled " __DATE__ " " __TIME__ "\n\n"
27 "Usage: rrdtool [options] command command_options\n\n";
30 "Valid commands: create, update, updatev, graph, dump, restore,\n"
31 "\t\tlast, first, info, fetch, tune, resize, xport\n\n";
33 char help_listremote[] =
34 "Valid remote commands: quit, ls, cd, mkdir\n\n";
38 "* create - create a new RRD\n\n"
39 "\trrdtool create filename [--start|-b start time]\n"
40 "\t\t[--step|-s step]\n"
41 "\t\t[DS:ds-name:DST:dst arguments]\n"
42 "\t\t[RRA:CF:cf arguments]\n\n";
45 "* dump - dump an RRD to XML\n\n"
46 "\trrdtool dump filename.rrd >filename.xml\n\n";
49 "* info - returns the configuration and status of the RRD\n\n"
50 "\trrdtool info filename.rrd\n\n";
53 "* restore - restore an RRD file from its XML form\n\n"
54 "\trrdtool restore [--range-check|-r] [--force-overwrite|-f] filename.xml filename.rrd\n\n";
57 "* last - show last update time for RRD\n\n"
58 "\trrdtool last filename.rrd\n\n";
61 "* first - show first update time for RRA within an RRD\n\n"
62 "\trrdtool first filename.rrd [--rraindex number]\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 version 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[-r|--resolution resolution]\n"
85 "\t\t[-s|--start start] [-e|--end end]\n\n";
87 /* break up very large strings (help_graph, help_tune) for ISO C89 compliance*/
90 "* graph - generate a graph from one or several RRD\n\n"
91 "\trrdtool graph filename [-s|--start seconds] [-e|--end seconds]\n"
92 "\t\t[-x|--x-grid x-axis grid and label]\n"
93 "\t\t[-Y|--alt-y-grid]\n"
94 "\t\t[-y|--y-grid y-axis grid and label]\n"
95 "\t\t[-v|--vertical-label string] [-w|--width pixels]\n"
96 "\t\t[-h|--height pixels] [-o|--logarithmic]\n"
97 "\t\t[-u|--upper-limit value] [-z|--lazy]\n"
98 "\t\t[-l|--lower-limit value] [-r|--rigid]\n"
99 "\t\t[-g|--no-legend]\n"
100 "\t\t[-F|--force-rules-legend]\n"
101 "\t\t[-j|--only-graph]\n";
103 "\t\t[-n|--font FONTTAG:size:font]\n"
104 "\t\t[-m|--zoom factor]\n"
105 "\t\t[-A|--alt-autoscale]\n"
106 "\t\t[-M|--alt-autoscale-max]\n"
107 "\t\t[-R|--font-render-mode {normal,light,mono}]\n"
108 "\t\t[-B|--font-smoothing-threshold size]\n"
109 "\t\t[-E|--slope-mode]\n"
110 "\t\t[-N|--no-gridfit]\n"
111 "\t\t[-X|--units-exponent value]\n"
112 "\t\t[-L|--units-length value]\n"
113 "\t\t[-S|--step seconds]\n"
114 "\t\t[-f|--imginfo printfstr]\n"
115 "\t\t[-a|--imgformat PNG]\n"
116 "\t\t[-c|--color COLORTAG#rrggbb[aa]] [-t|--title string]\n"
117 "\t\t[-W|--watermark string]\n"
118 "\t\t[DEF:vname=rrd:ds-name:CF]\n";
120 "\t\t[CDEF:vname=rpn-expression]\n"
121 "\t\t[VDEF:vdefname=rpn-expression]\n"
122 "\t\t[PRINT:vdefname:format]\n"
123 "\t\t[GPRINT:vdefname:format]\n"
124 "\t\t[COMMENT:text]\n"
125 "\t\t[SHIFT:vname:offset]\n"
126 "\t\t[TICK:vname#rrggbb[aa][:[fraction][:legend]]]\n"
127 "\t\t[HRULE:value#rrggbb[aa][:legend]]\n"
128 "\t\t[VRULE:value#rrggbb[aa][:legend]]\n"
129 "\t\t[LINE[width]:vname[#rrggbb[aa][:[legend][:STACK]]]]\n"
130 "\t\t[AREA:vname[#rrggbb[aa][:[legend][:STACK]]]]\n"
131 "\t\t[PRINT:vname:CF:format] (deprecated)\n"
132 "\t\t[GPRINT:vname:CF:format] (deprecated)\n"
133 "\t\t[STACK:vname[#rrggbb[aa][:legend]]] (deprecated)\n\n";
136 " * tune - Modify some basic properties of an RRD\n\n"
137 "\trrdtool tune filename\n"
138 "\t\t[--heartbeat|-h ds-name:heartbeat]\n"
139 "\t\t[--data-source-type|-d ds-name:DST]\n"
140 "\t\t[--data-source-rename|-r old-name:new-name]\n"
141 "\t\t[--minimum|-i ds-name:min] [--maximum|-a ds-name:max]\n"
142 "\t\t[--deltapos scale-value] [--deltaneg scale-value]\n"
143 "\t\t[--failure-threshold integer]\n"
144 "\t\t[--window-length integer]\n"
145 "\t\t[--alpha adaptation-parameter]\n";
147 " * tune - Modify some basic properties of an RRD\n\n"
148 "\t\t[--beta adaptation-parameter]\n"
149 "\t\t[--gamma adaptation-parameter]\n"
150 "\t\t[--gamma-deviation adaptation-parameter]\n"
151 "\t\t[--aberrant-reset ds-name]\n\n";
154 " * resize - alter the length of one of the RRAs in an RRD\n\n"
155 "\trrdtool resize filename rranum GROW|SHRINK rows\n\n";
158 "* xport - generate XML dump from one or several RRD\n\n"
159 "\trrdtool xport [-s|--start seconds] [-e|--end seconds]\n"
160 "\t\t[-m|--maxrows rows]\n"
161 "\t\t[--step seconds]\n"
162 "\t\t[DEF:vname=rrd:ds-name:CF]\n"
163 "\t\t[CDEF:vname=rpn-expression]\n"
164 "\t\t[XPORT:vname:legend]\n\n";
167 " * quit - closing a session in remote mode\n\n"
168 "\trrdtool quit\n\n";
171 " * ls - lists all *.rrd files in current directory\n\n"
175 " * cd - changes the current directory\n\n"
176 "\trrdtool cd new directory\n\n";
179 " * mkdir - creates a new directory\n\n"
180 "\trrdtool mkdir newdirectoryname\n\n";
183 "RRDtool is distributed under the Terms of the GNU General\n"
184 "Public License Version 2. (www.gnu.org/copyleft/gpl.html)\n\n"
186 "For more information read the RRD manpages\n\n";
188 enum { C_NONE, C_CREATE, C_DUMP, C_INFO, C_RESTORE, C_LAST, C_FIRST,
189 C_UPDATE, C_FETCH, C_GRAPH, C_TUNE, C_RESIZE, C_XPORT,
190 C_QUIT, C_LS, C_CD, C_MKDIR, C_UPDATEV };
192 int help_cmd = C_NONE;
196 if (!strcmp(cmd,"create"))
198 else if (!strcmp(cmd,"dump"))
200 else if (!strcmp(cmd,"info"))
202 else if (!strcmp(cmd,"restore"))
203 help_cmd = C_RESTORE;
204 else if (!strcmp(cmd,"last"))
206 else if (!strcmp(cmd,"first"))
208 else if (!strcmp(cmd,"update"))
210 else if (!strcmp(cmd,"updatev"))
211 help_cmd = C_UPDATEV;
212 else if (!strcmp(cmd,"fetch"))
214 else if (!strcmp(cmd,"graph"))
216 else if (!strcmp(cmd,"tune"))
218 else if (!strcmp(cmd,"resize"))
220 else if (!strcmp(cmd,"xport"))
222 else if (!strcmp(cmd,"quit"))
224 else if (!strcmp(cmd,"ls"))
226 else if (!strcmp(cmd,"cd"))
228 else if (!strcmp(cmd,"mkdir"))
231 fputs(help_main, stdout);
235 fputs(help_list, stdout);
237 fputs(help_listremote, stdout);
241 fputs(help_create, stdout);
244 fputs(help_dump, stdout);
247 fputs(help_info, stdout);
250 fputs(help_restore, stdout);
253 fputs(help_last, stdout);
256 fputs(help_first, stdout);
259 fputs(help_update, stdout);
262 fputs(help_updatev, stdout);
265 fputs(help_fetch, stdout);
268 fputs(help_graph1, stdout);
269 fputs(help_graph2, stdout);
270 fputs(help_graph3, stdout);
273 fputs(help_tune1, stdout);
274 fputs(help_tune2, stdout);
277 fputs(help_resize, stdout);
280 fputs(help_xport, stdout);
283 fputs(help_quit, stdout);
286 fputs(help_ls, stdout);
289 fputs(help_cd, stdout);
292 fputs(help_mkdir, stdout);
295 fputs(help_lic, stdout);
299 int main(int argc, char *argv[])
302 char aLine[MAX_LENGTH];
304 #ifdef MUST_DISABLE_SIGFPE
305 signal(SIGFPE,SIG_IGN);
307 #ifdef MUST_DISABLE_FPMASK
316 if (((argc == 2)||(argc == 3)) && !strcmp("-",argv[1]))
319 struct rusage myusage;
320 struct timeval starttime;
321 struct timeval currenttime;
324 tz.tz_minuteswest =0;
326 gettimeofday(&starttime,&tz);
329 if ((argc == 3) && strcmp("",argv[2])){
342 fprintf(stderr,"ERROR: can't change root to '%s' errno=%d\n",
349 fprintf(stderr,"ERROR: change root is not supported by your OS "
350 "or at least by this copy of rrdtool\n");
357 if (strcmp(firstdir,"")){
360 fprintf(stderr,"ERROR: %s\n",rrd_strerror(errno));
365 while (fgets(aLine, sizeof(aLine)-1, stdin)){
366 if ((argc = CountArgs(aLine)) == 0) {
367 printf("ERROR: not enough arguments\n");
369 if ((myargv = (char **) malloc((argc+1) *
370 sizeof(char *))) == NULL) {
374 if ((argc=CreateArgs(argv[0], aLine, argc, myargv)) < 0) {
375 printf("ERROR: creating arguments\n");
377 int ret = HandleInputLine(argc, myargv, stdout);
383 getrusage(RUSAGE_SELF,&myusage);
384 gettimeofday(¤ttime,&tz);
385 printf("OK u:%1.2f s:%1.2f r:%1.2f\n",
386 (double)myusage.ru_utime.tv_sec+
387 (double)myusage.ru_utime.tv_usec/1000000.0,
388 (double)myusage.ru_stime.tv_sec+
389 (double)myusage.ru_stime.tv_usec/1000000.0,
390 (double)(currenttime.tv_sec-starttime.tv_sec)
391 +(double)(currenttime.tv_usec-starttime.tv_usec)
399 fflush(stdout); /* this is important for pipes to work */
407 else if (argc == 3 && !strcmp(argv[1],"help"))
413 exit(HandleInputLine(argc, argv, stderr));
418 /* HandleInputLine is NOT thread safe - due to readdir issues,
419 resolving them portably is not really simple. */
420 int HandleInputLine(int argc, char **argv, FILE* out)
422 #if defined(HAVE_OPENDIR) && defined (HAVE_READDIR)
423 DIR *curdir; /* to read current dir with ls */
426 #if defined(HAVE_SYS_STAT_H)
431 if (argc>1 && strcmp("quit", argv[1]) == 0){
433 printf("ERROR: invalid parameter count for quit\n");
438 #if defined(HAVE_OPENDIR) && defined(HAVE_READDIR) && defined(HAVE_CHDIR)
439 if (argc>1 && strcmp("cd", argv[1]) == 0){
441 printf("ERROR: invalid parameter count for cd\n");
444 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
445 if (getuid()==0 && ! ChangeRoot){
446 printf("ERROR: chdir security problem - rrdtool is running as "
447 "root but not chroot!\n");
453 printf("ERROR: %s\n",rrd_strerror(errno));
458 if (argc>1 && strcmp("mkdir", argv[1]) == 0){
460 printf("ERROR: invalid parameter count for mkdir\n");
463 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
464 if (getuid()==0 && ! ChangeRoot){
465 printf("ERROR: mkdir security problem - rrdtool is running as "
466 "root but not chroot!\n");
472 printf("ERROR: %s\n",rrd_strerror(errno));
477 if (argc>1 && strcmp("ls", argv[1]) == 0){
479 printf("ERROR: invalid parameter count for ls\n");
482 if ((curdir=opendir("."))!=NULL){
483 while((dent=readdir(curdir))!=NULL){
484 if (!stat(dent->d_name,&st)){
485 if (S_ISDIR(st.st_mode)){
486 printf("d %s\n",dent->d_name);
488 if (strlen(dent->d_name)>4 && S_ISREG(st.st_mode)){
489 if (!strcmp(dent->d_name+NAMLEN(dent)-4,".rrd") ||
490 !strcmp(dent->d_name+NAMLEN(dent)-4,".RRD")){
491 printf("- %s\n",dent->d_name);
498 printf("ERROR: %s\n",rrd_strerror(errno));
503 #endif /* opendir and readdir */
507 || strcmp("help", argv[1]) == 0
508 || strcmp("--help", argv[1]) == 0
509 || strcmp("-help", argv[1]) == 0
510 || strcmp("-?", argv[1]) == 0
511 || strcmp("-h", argv[1]) == 0 ) {
516 if (strcmp("create", argv[1]) == 0)
517 rrd_create(argc-1, &argv[1]);
518 else if (strcmp("dump", argv[1]) == 0)
519 rrd_dump(argc-1, &argv[1]);
520 else if (strcmp("info", argv[1]) == 0
521 || strcmp("updatev", argv[1]) == 0){
523 if (strcmp("info",argv[1]) == 0)
524 data=rrd_info(argc-1, &argv[1]);
526 data=rrd_update_v(argc-1, &argv[1]);
529 printf ("%s = ", data->key);
532 switch (data->type) {
534 if (isnan (data->value.u_val))
537 printf ("%0.10e", data->value.u_val);
540 printf ("%lu", data->value.u_cnt);
543 printf ("%d", data->value.u_int);
546 printf ("\"%s\"", data->value.u_str);
547 free(data->value.u_str);
557 else if (strcmp("--version", argv[1]) == 0 ||
558 strcmp("version", argv[1]) == 0 ||
559 strcmp("v", argv[1]) == 0 ||
560 strcmp("-v", argv[1]) == 0 ||
561 strcmp("-version", argv[1]) == 0 )
562 printf("RRDtool " PACKAGE_VERSION " Copyright by Tobi Oetiker, 1997-2005 (%f)\n",
564 else if (strcmp("restore", argv[1]) == 0)
565 rrd_restore(argc-1, &argv[1]);
566 else if (strcmp("resize", argv[1]) == 0)
567 rrd_resize(argc-1, &argv[1]);
568 else if (strcmp("last", argv[1]) == 0)
569 printf("%ld\n",rrd_last(argc-1, &argv[1]));
570 else if (strcmp("first", argv[1]) == 0)
571 printf("%ld\n",rrd_first(argc-1, &argv[1]));
572 else if (strcmp("update", argv[1]) == 0)
573 rrd_update(argc-1, &argv[1]);
574 else if (strcmp("fetch", argv[1]) == 0) {
575 time_t start,end, ti;
576 unsigned long step, ds_cnt,i,ii;
577 rrd_value_t *data,*datai;
579 if (rrd_fetch(argc-1, &argv[1],&start,&end,&step,&ds_cnt,&ds_namv,&data) != -1) {
582 for (i = 0; i<ds_cnt;i++)
583 printf("%20s",ds_namv[i]);
585 for (ti = start+step; ti <= end; ti += step){
586 printf("%10lu:", ti);
587 for (ii = 0; ii < ds_cnt; ii++)
588 printf(" %0.10e", *(datai++));
591 for (i=0;i<ds_cnt;i++)
596 } else if (strcmp("xport", argv[1]) == 0) {
598 unsigned long int j = 0;
599 time_t start,end, ti;
600 unsigned long step, col_cnt,row_cnt;
601 rrd_value_t *data,*ptr;
603 if(rrd_xport(argc-1, &argv[1], &xxsize,&start,&end,&step,&col_cnt,&legend_v,&data) != -1) {
604 row_cnt = (end-start)/step;
606 printf("<?xml version=\"1.0\" encoding=\"%s\"?>\n\n", XML_ENCODING);
607 printf("<%s>\n", ROOT_TAG);
608 printf(" <%s>\n", META_TAG);
609 printf(" <%s>%lu</%s>\n", META_START_TAG, start+step, META_START_TAG);
610 printf(" <%s>%lu</%s>\n", META_STEP_TAG, step, META_STEP_TAG);
611 printf(" <%s>%lu</%s>\n", META_END_TAG, end, META_END_TAG);
612 printf(" <%s>%lu</%s>\n", META_ROWS_TAG, row_cnt, META_ROWS_TAG);
613 printf(" <%s>%lu</%s>\n", META_COLS_TAG, col_cnt, META_COLS_TAG);
614 printf(" <%s>\n", LEGEND_TAG);
615 for (j = 0; j < col_cnt; j++) {
618 printf(" <%s>%s</%s>\n", LEGEND_ENTRY_TAG, entry, LEGEND_ENTRY_TAG);
622 printf(" </%s>\n", LEGEND_TAG);
623 printf(" </%s>\n", META_TAG);
624 printf(" <%s>\n", DATA_TAG);
625 for (ti = start+step; ti <= end; ti += step) {
626 printf (" <%s>", DATA_ROW_TAG);
627 printf ("<%s>%lu</%s>", COL_TIME_TAG, ti, COL_TIME_TAG);
628 for (j = 0; j < col_cnt; j++) {
629 rrd_value_t newval = DNAN;
632 printf("<%s>NaN</%s>", COL_DATA_TAG, COL_DATA_TAG);
634 printf("<%s>%0.10e</%s>", COL_DATA_TAG, newval, COL_DATA_TAG);
638 printf("</%s>\n", DATA_ROW_TAG);
641 printf(" </%s>\n", DATA_TAG);
642 printf("</%s>\n", ROOT_TAG);
645 else if (strcmp("graph", argv[1]) == 0) {
647 #ifdef notused /*XXX*/
648 const char *imgfile = argv[2]; /* rrd_graph changes argv pointer */
653 int tostdout = (strcmp(argv[2],"-") == 0);
655 for (i=2;i<argc;i++){
656 if (strcmp(argv[i],"--imginfo") == 0 || strcmp(argv[i],"-f") == 0){
661 if( rrd_graph(argc-1, &argv[1], &calcpr, &xsize, &ysize, NULL, &ymin, &ymax) != -1 ) {
662 if (!tostdout && !imginfo)
663 printf ("%dx%d\n",xsize,ysize);
665 for(i=0;calcpr[i];i++){
667 printf("%s\n",calcpr[i]);
674 } else if (strcmp("tune", argv[1]) == 0)
675 rrd_tune(argc-1, &argv[1]);
677 rrd_set_error("unknown function '%s'",argv[1]);
679 if (rrd_test_error()) {
680 fprintf(out, "ERROR: %s\n",rrd_get_error());
687 int CountArgs(char *aLine)
692 while (aLine[i] == ' ') i++;
693 while (aLine[i] != 0){
694 if((aLine[i]== ' ') && inarg){
697 if((aLine[i]!= ' ') && ! inarg){
707 * CreateArgs - take a string (aLine) and tokenize
709 int CreateArgs(char *pName, char *aLine, int argc, char **argv)
718 /* remove trailing space and newlines */
719 while (len && aLine[len] <= ' ') {
720 aLine[len] = 0 ; len--;
722 /* sikp leading blanks */
723 while (*aLine && *aLine <= ' ') aLine++;
750 pargv[argc++] = putP;
758 pargv[argc++] = putP;