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-2005 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[DEF:vname=rrd:ds-name:CF]\n"
118 "\t\t[CDEF:vname=rpn-expression]\n";
120 "\t\t[VDEF:vdefname=rpn-expression]\n"
121 "\t\t[PRINT:vdefname:format]\n"
122 "\t\t[GPRINT:vdefname:format]\n"
123 "\t\t[COMMENT:text]\n"
124 "\t\t[SHIFT:vname:offset]\n"
125 "\t\t[TICK:vname#rrggbb[aa][:[fraction][:legend]]]\n"
126 "\t\t[HRULE:value#rrggbb[aa][:legend]]\n"
127 "\t\t[VRULE:value#rrggbb[aa][:legend]]\n"
128 "\t\t[LINE[width]:vname[#rrggbb[aa][:[legend][:STACK]]]]\n"
129 "\t\t[AREA:vname[#rrggbb[aa][:[legend][:STACK]]]]\n"
130 "\t\t[PRINT:vname:CF:format] (deprecated)\n"
131 "\t\t[GPRINT:vname:CF:format] (deprecated)\n"
132 "\t\t[STACK:vname[#rrggbb[aa][:legend]]] (deprecated)\n\n";
135 " * tune - Modify some basic properties of an RRD\n\n"
136 "\trrdtool tune filename\n"
137 "\t\t[--heartbeat|-h ds-name:heartbeat]\n"
138 "\t\t[--data-source-type|-d ds-name:DST]\n"
139 "\t\t[--data-source-rename|-r old-name:new-name]\n"
140 "\t\t[--minimum|-i ds-name:min] [--maximum|-a ds-name:max]\n"
141 "\t\t[--deltapos scale-value] [--deltaneg scale-value]\n"
142 "\t\t[--failure-threshold integer]\n"
143 "\t\t[--window-length integer]\n"
144 "\t\t[--alpha adaptation-parameter]\n";
146 " * tune - Modify some basic properties of an RRD\n\n"
147 "\t\t[--beta adaptation-parameter]\n"
148 "\t\t[--gamma adaptation-parameter]\n"
149 "\t\t[--gamma-deviation adaptation-parameter]\n"
150 "\t\t[--aberrant-reset ds-name]\n\n";
153 " * resize - alter the length of one of the RRAs in an RRD\n\n"
154 "\trrdtool resize filename rranum GROW|SHRINK rows\n\n";
157 "* xport - generate XML dump from one or several RRD\n\n"
158 "\trrdtool xport [-s|--start seconds] [-e|--end seconds]\n"
159 "\t\t[-m|--maxrows rows]\n"
160 "\t\t[--step seconds]\n"
161 "\t\t[DEF:vname=rrd:ds-name:CF]\n"
162 "\t\t[CDEF:vname=rpn-expression]\n"
163 "\t\t[XPORT:vname:legend]\n\n";
166 " * quit - closing a session in remote mode\n\n"
167 "\trrdtool quit\n\n";
170 " * ls - lists all *.rrd files in current directory\n\n"
174 " * cd - changes the current directory\n\n"
175 "\trrdtool cd new directory\n\n";
178 " * mkdir - creates a new directory\n\n"
179 "\trrdtool mkdir newdirectoryname\n\n";
182 "RRDtool is distributed under the Terms of the GNU General\n"
183 "Public License Version 2. (www.gnu.org/copyleft/gpl.html)\n\n"
185 "For more information read the RRD manpages\n\n";
187 enum { C_NONE, C_CREATE, C_DUMP, C_INFO, C_RESTORE, C_LAST, C_FIRST,
188 C_UPDATE, C_FETCH, C_GRAPH, C_TUNE, C_RESIZE, C_XPORT,
189 C_QUIT, C_LS, C_CD, C_MKDIR, C_UPDATEV };
191 int help_cmd = C_NONE;
195 if (!strcmp(cmd,"create"))
197 else if (!strcmp(cmd,"dump"))
199 else if (!strcmp(cmd,"info"))
201 else if (!strcmp(cmd,"restore"))
202 help_cmd = C_RESTORE;
203 else if (!strcmp(cmd,"last"))
205 else if (!strcmp(cmd,"first"))
207 else if (!strcmp(cmd,"update"))
209 else if (!strcmp(cmd,"updatev"))
210 help_cmd = C_UPDATEV;
211 else if (!strcmp(cmd,"fetch"))
213 else if (!strcmp(cmd,"graph"))
215 else if (!strcmp(cmd,"tune"))
217 else if (!strcmp(cmd,"resize"))
219 else if (!strcmp(cmd,"xport"))
221 else if (!strcmp(cmd,"quit"))
223 else if (!strcmp(cmd,"ls"))
225 else if (!strcmp(cmd,"cd"))
227 else if (!strcmp(cmd,"mkdir"))
230 fputs(help_main, stdout);
234 fputs(help_list, stdout);
236 fputs(help_listremote, stdout);
240 fputs(help_create, stdout);
243 fputs(help_dump, stdout);
246 fputs(help_info, stdout);
249 fputs(help_restore, stdout);
252 fputs(help_last, stdout);
255 fputs(help_first, stdout);
258 fputs(help_update, stdout);
261 fputs(help_updatev, stdout);
264 fputs(help_fetch, stdout);
267 fputs(help_graph1, stdout);
268 fputs(help_graph2, stdout);
269 fputs(help_graph3, stdout);
272 fputs(help_tune1, stdout);
273 fputs(help_tune2, stdout);
276 fputs(help_resize, stdout);
279 fputs(help_xport, stdout);
282 fputs(help_quit, stdout);
285 fputs(help_ls, stdout);
288 fputs(help_cd, stdout);
291 fputs(help_mkdir, stdout);
294 fputs(help_lic, stdout);
298 int main(int argc, char *argv[])
301 char aLine[MAX_LENGTH];
303 #ifdef MUST_DISABLE_SIGFPE
304 signal(SIGFPE,SIG_IGN);
306 #ifdef MUST_DISABLE_FPMASK
315 if (((argc == 2)||(argc == 3)) && !strcmp("-",argv[1]))
318 struct rusage myusage;
319 struct timeval starttime;
320 struct timeval currenttime;
323 tz.tz_minuteswest =0;
325 gettimeofday(&starttime,&tz);
328 if ((argc == 3) && strcmp("",argv[2])){
341 fprintf(stderr,"ERROR: can't change root to '%s' errno=%d\n",
348 fprintf(stderr,"ERROR: change root is not supported by your OS "
349 "or at least by this copy of rrdtool\n");
356 if (strcmp(firstdir,"")){
359 fprintf(stderr,"ERROR: %s\n",rrd_strerror(errno));
364 while (fgets(aLine, sizeof(aLine)-1, stdin)){
365 if ((argc = CountArgs(aLine)) == 0) {
366 fprintf(stderr,"ERROR: not enough arguments\n");
368 if ((myargv = (char **) malloc((argc+1) *
369 sizeof(char *))) == NULL) {
373 if ((argc=CreateArgs(argv[0], aLine, argc, myargv)) < 0) {
374 printf("ERROR: creating arguments\n");
376 int ret = HandleInputLine(argc, myargv, stdout);
382 getrusage(RUSAGE_SELF,&myusage);
383 gettimeofday(¤ttime,&tz);
384 printf("OK u:%1.2f s:%1.2f r:%1.2f\n",
385 (double)myusage.ru_utime.tv_sec+
386 (double)myusage.ru_utime.tv_usec/1000000.0,
387 (double)myusage.ru_stime.tv_sec+
388 (double)myusage.ru_stime.tv_usec/1000000.0,
389 (double)(currenttime.tv_sec-starttime.tv_sec)
390 +(double)(currenttime.tv_usec-starttime.tv_usec)
398 fflush(stdout); /* this is important for pipes to work */
406 else if (argc == 3 && !strcmp(argv[1],"help"))
412 exit(HandleInputLine(argc, argv, stderr));
417 /* HandleInputLine is NOT thread safe - due to readdir issues,
418 resolving them portably is not really simple. */
419 int HandleInputLine(int argc, char **argv, FILE* out)
421 #if defined(HAVE_OPENDIR) && defined (HAVE_READDIR)
422 DIR *curdir; /* to read current dir with ls */
425 #if defined(HAVE_SYS_STAT_H)
430 if (argc>1 && strcmp("quit", argv[1]) == 0){
432 printf("ERROR: invalid parameter count for quit\n");
437 #if defined(HAVE_OPENDIR) && defined(HAVE_READDIR) && defined(HAVE_CHDIR)
438 if (argc>1 && strcmp("cd", argv[1]) == 0){
440 printf("ERROR: invalid parameter count for cd\n");
443 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
444 if (getuid()==0 && ! ChangeRoot){
445 printf("ERROR: chdir security problem - rrdtool is running as "
446 "root but not chroot!\n");
452 printf("ERROR: %s\n",rrd_strerror(errno));
457 if (argc>1 && strcmp("mkdir", argv[1]) == 0){
459 printf("ERROR: invalid parameter count for mkdir\n");
462 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
463 if (getuid()==0 && ! ChangeRoot){
464 printf("ERROR: mkdir security problem - rrdtool is running as "
465 "root but not chroot!\n");
471 printf("ERROR: %s\n",rrd_strerror(errno));
476 if (argc>1 && strcmp("ls", argv[1]) == 0){
478 printf("ERROR: invalid parameter count for ls\n");
481 if ((curdir=opendir("."))!=NULL){
482 while((dent=readdir(curdir))!=NULL){
483 if (!stat(dent->d_name,&st)){
484 if (S_ISDIR(st.st_mode)){
485 printf("d %s\n",dent->d_name);
487 if (strlen(dent->d_name)>4 && S_ISREG(st.st_mode)){
488 if (!strcmp(dent->d_name+NAMLEN(dent)-4,".rrd") ||
489 !strcmp(dent->d_name+NAMLEN(dent)-4,".RRD")){
490 printf("- %s\n",dent->d_name);
497 printf("ERROR: %s\n",rrd_strerror(errno));
502 #endif /* opendir and readdir */
506 || strcmp("help", argv[1]) == 0
507 || strcmp("--help", argv[1]) == 0
508 || strcmp("-help", argv[1]) == 0
509 || strcmp("-?", argv[1]) == 0
510 || strcmp("-h", argv[1]) == 0 ) {
515 if (strcmp("create", argv[1]) == 0)
516 rrd_create(argc-1, &argv[1]);
517 else if (strcmp("dump", argv[1]) == 0)
518 rrd_dump(argc-1, &argv[1]);
519 else if (strcmp("info", argv[1]) == 0
520 || strcmp("updatev", argv[1]) == 0){
522 if (strcmp("info",argv[1]) == 0)
523 data=rrd_info(argc-1, &argv[1]);
525 data=rrd_update_v(argc-1, &argv[1]);
528 printf ("%s = ", data->key);
531 switch (data->type) {
533 if (isnan (data->value.u_val))
536 printf ("%0.10e", data->value.u_val);
539 printf ("%lu", data->value.u_cnt);
542 printf ("%d", data->value.u_int);
545 printf ("\"%s\"", data->value.u_str);
546 free(data->value.u_str);
556 else if (strcmp("--version", argv[1]) == 0 ||
557 strcmp("version", argv[1]) == 0 ||
558 strcmp("v", argv[1]) == 0 ||
559 strcmp("-v", argv[1]) == 0 ||
560 strcmp("-version", argv[1]) == 0 )
561 printf("RRDtool " PACKAGE_VERSION " Copyright by Tobi Oetiker, 1997-2005 (%f)\n",
563 else if (strcmp("restore", argv[1]) == 0)
564 rrd_restore(argc-1, &argv[1]);
565 else if (strcmp("resize", argv[1]) == 0)
566 rrd_resize(argc-1, &argv[1]);
567 else if (strcmp("last", argv[1]) == 0)
568 printf("%ld\n",rrd_last(argc-1, &argv[1]));
569 else if (strcmp("first", argv[1]) == 0)
570 printf("%ld\n",rrd_first(argc-1, &argv[1]));
571 else if (strcmp("update", argv[1]) == 0)
572 rrd_update(argc-1, &argv[1]);
573 else if (strcmp("fetch", argv[1]) == 0) {
574 time_t start,end, ti;
575 unsigned long step, ds_cnt,i,ii;
576 rrd_value_t *data,*datai;
578 if (rrd_fetch(argc-1, &argv[1],&start,&end,&step,&ds_cnt,&ds_namv,&data) != -1) {
581 for (i = 0; i<ds_cnt;i++)
582 printf("%20s",ds_namv[i]);
584 for (ti = start+step; ti <= end; ti += step){
585 printf("%10lu:", ti);
586 for (ii = 0; ii < ds_cnt; ii++)
587 printf(" %0.10e", *(datai++));
590 for (i=0;i<ds_cnt;i++)
595 } else if (strcmp("xport", argv[1]) == 0) {
597 unsigned long int j = 0;
598 time_t start,end, ti;
599 unsigned long step, col_cnt,row_cnt;
600 rrd_value_t *data,*ptr;
602 if(rrd_xport(argc-1, &argv[1], &xxsize,&start,&end,&step,&col_cnt,&legend_v,&data) != -1) {
603 row_cnt = (end-start)/step;
605 printf("<?xml version=\"1.0\" encoding=\"%s\"?>\n\n", XML_ENCODING);
606 printf("<%s>\n", ROOT_TAG);
607 printf(" <%s>\n", META_TAG);
608 printf(" <%s>%lu</%s>\n", META_START_TAG, start+step, META_START_TAG);
609 printf(" <%s>%lu</%s>\n", META_STEP_TAG, step, META_STEP_TAG);
610 printf(" <%s>%lu</%s>\n", META_END_TAG, end, META_END_TAG);
611 printf(" <%s>%lu</%s>\n", META_ROWS_TAG, row_cnt, META_ROWS_TAG);
612 printf(" <%s>%lu</%s>\n", META_COLS_TAG, col_cnt, META_COLS_TAG);
613 printf(" <%s>\n", LEGEND_TAG);
614 for (j = 0; j < col_cnt; j++) {
617 printf(" <%s>%s</%s>\n", LEGEND_ENTRY_TAG, entry, LEGEND_ENTRY_TAG);
621 printf(" </%s>\n", LEGEND_TAG);
622 printf(" </%s>\n", META_TAG);
623 printf(" <%s>\n", DATA_TAG);
624 for (ti = start+step; ti <= end; ti += step) {
625 printf (" <%s>", DATA_ROW_TAG);
626 printf ("<%s>%lu</%s>", COL_TIME_TAG, ti, COL_TIME_TAG);
627 for (j = 0; j < col_cnt; j++) {
628 rrd_value_t newval = DNAN;
631 printf("<%s>NaN</%s>", COL_DATA_TAG, COL_DATA_TAG);
633 printf("<%s>%0.10e</%s>", COL_DATA_TAG, newval, COL_DATA_TAG);
637 printf("</%s>\n", DATA_ROW_TAG);
640 printf(" </%s>\n", DATA_TAG);
641 printf("</%s>\n", ROOT_TAG);
644 else if (strcmp("graph", argv[1]) == 0) {
646 #ifdef notused /*XXX*/
647 const char *imgfile = argv[2]; /* rrd_graph changes argv pointer */
652 int tostdout = (strcmp(argv[2],"-") == 0);
653 if( rrd_graph(argc-1, &argv[1], &calcpr, &xsize, &ysize, NULL, &ymin, &ymax) != -1 ) {
655 printf ("%dx%d\n",xsize,ysize);
657 for(i=0;calcpr[i];i++){
659 printf("%s\n",calcpr[i]);
666 } else if (strcmp("tune", argv[1]) == 0)
667 rrd_tune(argc-1, &argv[1]);
669 rrd_set_error("unknown function '%s'",argv[1]);
671 if (rrd_test_error()) {
672 fprintf(out, "ERROR: %s\n",rrd_get_error());
679 int CountArgs(char *aLine)
684 while (aLine[i] == ' ') i++;
685 while (aLine[i] != 0){
686 if((aLine[i]== ' ') && inarg){
689 if((aLine[i]!= ' ') && ! inarg){
699 * CreateArgs - take a string (aLine) and tokenize
701 int CreateArgs(char *pName, char *aLine, int argc, char **argv)
710 /* remove trailing space and newlines */
711 while (len && aLine[len] <= ' ') {
712 aLine[len] = 0 ; len--;
714 /* sikp leading blanks */
715 while (*aLine && *aLine <= ' ') aLine++;
742 pargv[argc++] = putP;
750 pargv[argc++] = putP;