1 /*****************************************************************************
2 * RRDtool 1.2.15 Copyright by Tobi Oetiker, 1997-2006
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, pwd\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"
163 "\t\t[--unknownaszero]\n"
164 "\t\t[DEF:vname=rrd:ds-name:CF]\n"
165 "\t\t[CDEF:vname=rpn-expression]\n"
166 "\t\t[XPORT:vname:legend]\n\n";
169 " * quit - closing a session in remote mode\n\n"
170 "\trrdtool quit\n\n";
173 " * ls - lists all *.rrd files in current directory\n\n"
177 " * cd - changes the current directory\n\n"
178 "\trrdtool cd new directory\n\n";
181 " * mkdir - creates a new directory\n\n"
182 "\trrdtool mkdir newdirectoryname\n\n";
185 " * pwd - returns the current working directory\n\n"
189 "RRDtool is distributed under the Terms of the GNU General\n"
190 "Public License Version 2. (www.gnu.org/copyleft/gpl.html)\n\n"
192 "For more information read the RRD manpages\n\n";
194 enum { C_NONE, C_CREATE, C_DUMP, C_INFO, C_RESTORE, C_LAST, C_FIRST,
195 C_UPDATE, C_FETCH, C_GRAPH, C_TUNE, C_RESIZE, C_XPORT,
196 C_QUIT, C_LS, C_CD, C_MKDIR, C_PWD, C_UPDATEV };
198 int help_cmd = C_NONE;
202 if (!strcmp(cmd,"create"))
204 else if (!strcmp(cmd,"dump"))
206 else if (!strcmp(cmd,"info"))
208 else if (!strcmp(cmd,"restore"))
209 help_cmd = C_RESTORE;
210 else if (!strcmp(cmd,"last"))
212 else if (!strcmp(cmd,"first"))
214 else if (!strcmp(cmd,"update"))
216 else if (!strcmp(cmd,"updatev"))
217 help_cmd = C_UPDATEV;
218 else if (!strcmp(cmd,"fetch"))
220 else if (!strcmp(cmd,"graph"))
222 else if (!strcmp(cmd,"tune"))
224 else if (!strcmp(cmd,"resize"))
226 else if (!strcmp(cmd,"xport"))
228 else if (!strcmp(cmd,"quit"))
230 else if (!strcmp(cmd,"ls"))
232 else if (!strcmp(cmd,"cd"))
234 else if (!strcmp(cmd,"mkdir"))
236 else if (!strcmp(cmd,"pwd"))
239 fputs(help_main, stdout);
243 fputs(help_list, stdout);
245 fputs(help_listremote, stdout);
249 fputs(help_create, stdout);
252 fputs(help_dump, stdout);
255 fputs(help_info, stdout);
258 fputs(help_restore, stdout);
261 fputs(help_last, stdout);
264 fputs(help_first, stdout);
267 fputs(help_update, stdout);
270 fputs(help_updatev, stdout);
273 fputs(help_fetch, stdout);
276 fputs(help_graph1, stdout);
277 fputs(help_graph2, stdout);
278 fputs(help_graph3, stdout);
281 fputs(help_tune1, stdout);
282 fputs(help_tune2, stdout);
285 fputs(help_resize, stdout);
288 fputs(help_xport, stdout);
291 fputs(help_quit, stdout);
294 fputs(help_ls, stdout);
297 fputs(help_cd, stdout);
300 fputs(help_mkdir, stdout);
303 fputs(help_pwd, stdout);
306 fputs(help_lic, stdout);
309 static char *fgetslong(char **aLinePtr, FILE *stream)
312 size_t bufsize = MAX_LENGTH;
315 if (feof(stream)) return *aLinePtr = 0;
316 if (!(linebuf = malloc(bufsize))) {
317 perror("fgetslong: malloc");
321 while (fgets(linebuf + eolpos, MAX_LENGTH, stream)) {
322 eolpos += strlen(linebuf + eolpos);
323 if (linebuf[eolpos - 1] == '\n') return *aLinePtr = linebuf;
324 bufsize += MAX_LENGTH;
325 if (!(linebuf = realloc(linebuf, bufsize))) {
326 perror("fgetslong: realloc");
330 return *aLinePtr = linebuf[0] ? linebuf : 0;
333 int main(int argc, char *argv[])
338 #ifdef MUST_DISABLE_SIGFPE
339 signal(SIGFPE,SIG_IGN);
341 #ifdef MUST_DISABLE_FPMASK
350 if (((argc == 2)||(argc == 3)) && !strcmp("-",argv[1]))
353 struct rusage myusage;
354 struct timeval starttime;
355 struct timeval currenttime;
358 tz.tz_minuteswest =0;
360 gettimeofday(&starttime,&tz);
363 if ((argc == 3) && strcmp("",argv[2])){
376 fprintf(stderr,"ERROR: can't change root to '%s' errno=%d\n",
383 fprintf(stderr,"ERROR: change root is not supported by your OS "
384 "or at least by this copy of rrdtool\n");
391 if (strcmp(firstdir,"")){
394 fprintf(stderr,"ERROR: %s\n",rrd_strerror(errno));
399 while (fgetslong(&aLine, stdin)){
400 if ((argc = CountArgs(aLine)) == 0) {
401 printf("ERROR: not enough arguments\n");
403 if ((myargv = (char **) malloc((argc+1) *
404 sizeof(char *))) == NULL) {
408 if ((argc=CreateArgs(argv[0], aLine, argc, myargv)) < 0) {
409 printf("ERROR: creating arguments\n");
411 int ret = HandleInputLine(argc, myargv, stdout);
417 getrusage(RUSAGE_SELF,&myusage);
418 gettimeofday(¤ttime,&tz);
419 printf("OK u:%1.2f s:%1.2f r:%1.2f\n",
420 (double)myusage.ru_utime.tv_sec+
421 (double)myusage.ru_utime.tv_usec/1000000.0,
422 (double)myusage.ru_stime.tv_sec+
423 (double)myusage.ru_stime.tv_usec/1000000.0,
424 (double)(currenttime.tv_sec-starttime.tv_sec)
425 +(double)(currenttime.tv_usec-starttime.tv_usec)
433 fflush(stdout); /* this is important for pipes to work */
442 else if (argc == 3 && !strcmp(argv[1],"help"))
448 exit(HandleInputLine(argc, argv, stderr));
453 /* HandleInputLine is NOT thread safe - due to readdir issues,
454 resolving them portably is not really simple. */
455 int HandleInputLine(int argc, char **argv, FILE* out)
457 #if defined(HAVE_OPENDIR) && defined (HAVE_READDIR)
458 DIR *curdir; /* to read current dir with ls */
461 #if defined(HAVE_SYS_STAT_H)
464 char* cwd; /* To hold current working dir on call to pwd */
466 /* Reset errno to 0 before we start.
471 if (argc>1 && strcmp("quit", argv[1]) == 0){
473 printf("ERROR: invalid parameter count for quit\n");
478 #if defined(HAVE_OPENDIR) && defined(HAVE_READDIR) && defined(HAVE_CHDIR)
479 if (argc>1 && strcmp("cd", argv[1]) == 0){
481 printf("ERROR: invalid parameter count for cd\n");
484 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
485 if (getuid()==0 && ! ChangeRoot){
486 printf("ERROR: chdir security problem - rrdtool is running as "
487 "root but not chroot!\n");
493 printf("ERROR: %s\n",rrd_strerror(errno));
498 if (argc>1 && strcmp("pwd", argv[1]) == 0){
500 printf("ERROR: invalid parameter count for pwd\n");
503 cwd = getcwd(NULL, MAXPATH);
505 printf("ERROR: %s\n",rrd_strerror(errno));
512 if (argc>1 && strcmp("mkdir", argv[1]) == 0){
514 printf("ERROR: invalid parameter count for mkdir\n");
517 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
518 if (getuid()==0 && ! ChangeRoot){
519 printf("ERROR: mkdir security problem - rrdtool is running as "
520 "root but not chroot!\n");
526 printf("ERROR: %s\n",rrd_strerror(errno));
531 if (argc>1 && strcmp("ls", argv[1]) == 0){
533 printf("ERROR: invalid parameter count for ls\n");
536 if ((curdir=opendir("."))!=NULL){
537 while((dent=readdir(curdir))!=NULL){
538 if (!stat(dent->d_name,&st)){
539 if (S_ISDIR(st.st_mode)){
540 printf("d %s\n",dent->d_name);
542 if (strlen(dent->d_name)>4 && S_ISREG(st.st_mode)){
543 if (!strcmp(dent->d_name+NAMLEN(dent)-4,".rrd") ||
544 !strcmp(dent->d_name+NAMLEN(dent)-4,".RRD")){
545 printf("- %s\n",dent->d_name);
553 printf("ERROR: %s\n",rrd_strerror(errno));
558 #endif /* opendir and readdir */
562 || strcmp("help", argv[1]) == 0
563 || strcmp("--help", argv[1]) == 0
564 || strcmp("-help", argv[1]) == 0
565 || strcmp("-?", argv[1]) == 0
566 || strcmp("-h", argv[1]) == 0 ) {
571 if (strcmp("create", argv[1]) == 0)
572 rrd_create(argc-1, &argv[1]);
573 else if (strcmp("dump", argv[1]) == 0)
574 rrd_dump(argc-1, &argv[1]);
575 else if (strcmp("info", argv[1]) == 0
576 || strcmp("updatev", argv[1]) == 0){
578 if (strcmp("info",argv[1]) == 0)
579 data=rrd_info(argc-1, &argv[1]);
581 data=rrd_update_v(argc-1, &argv[1]);
584 printf ("%s = ", data->key);
587 switch (data->type) {
589 if (isnan (data->value.u_val))
592 printf ("%0.10e", data->value.u_val);
595 printf ("%lu", data->value.u_cnt);
598 printf ("%d", data->value.u_int);
601 printf ("\"%s\"", data->value.u_str);
602 free(data->value.u_str);
612 else if (strcmp("--version", argv[1]) == 0 ||
613 strcmp("version", argv[1]) == 0 ||
614 strcmp("v", argv[1]) == 0 ||
615 strcmp("-v", argv[1]) == 0 ||
616 strcmp("-version", argv[1]) == 0 )
617 printf("RRDtool " PACKAGE_VERSION " Copyright by Tobi Oetiker, 1997-2005 (%f)\n",
619 else if (strcmp("restore", argv[1]) == 0)
620 rrd_restore(argc-1, &argv[1]);
621 else if (strcmp("resize", argv[1]) == 0)
622 rrd_resize(argc-1, &argv[1]);
623 else if (strcmp("last", argv[1]) == 0)
624 printf("%ld\n",rrd_last(argc-1, &argv[1]));
625 else if (strcmp("first", argv[1]) == 0)
626 printf("%ld\n",rrd_first(argc-1, &argv[1]));
627 else if (strcmp("update", argv[1]) == 0)
628 rrd_update(argc-1, &argv[1]);
629 else if (strcmp("fetch", argv[1]) == 0) {
630 time_t start,end, ti;
631 unsigned long step, ds_cnt,i,ii;
632 rrd_value_t *data,*datai;
634 if (rrd_fetch(argc-1, &argv[1],&start,&end,&step,&ds_cnt,&ds_namv,&data) != -1) {
637 for (i = 0; i<ds_cnt;i++)
638 printf("%20s",ds_namv[i]);
640 for (ti = start+step; ti <= end; ti += step){
641 printf("%10lu:", ti);
642 for (ii = 0; ii < ds_cnt; ii++)
643 printf(" %0.10e", *(datai++));
646 for (i=0;i<ds_cnt;i++)
651 } else if (strcmp("xport", argv[1]) == 0) {
653 unsigned long int j = 0;
654 time_t start,end, ti;
655 unsigned long step, col_cnt,row_cnt;
656 rrd_value_t *data,*ptr;
659 int unknownaszero = 0;
662 vtag = malloc( strlen(COL_DATA_TAG)+10);
663 for ( i = 2; i < argc; i++){
664 if (strcmp("--enumds", argv[i]) == 0)
666 if (strcmp("--unknownaszero", argv[i]) == 0)
670 if(rrd_xport(argc-1, &argv[1], &xxsize,&start,&end,&step,&col_cnt,&legend_v,&data) != -1) {
671 row_cnt = (end-start)/step;
673 printf("<?xml version=\"1.0\" encoding=\"%s\"?>\n\n", XML_ENCODING);
674 printf("<%s>\n", ROOT_TAG);
675 printf(" <%s>\n", META_TAG);
676 printf(" <%s>%lu</%s>\n", META_START_TAG, start+step, META_START_TAG);
677 printf(" <%s>%lu</%s>\n", META_STEP_TAG, step, META_STEP_TAG);
678 printf(" <%s>%lu</%s>\n", META_END_TAG, end, META_END_TAG);
679 printf(" <%s>%lu</%s>\n", META_ROWS_TAG, row_cnt, META_ROWS_TAG);
680 printf(" <%s>%lu</%s>\n", META_COLS_TAG, col_cnt, META_COLS_TAG);
681 printf(" <%s>\n", LEGEND_TAG);
682 for (j = 0; j < col_cnt; j++) {
685 printf(" <%s>%s</%s>\n", LEGEND_ENTRY_TAG, entry, LEGEND_ENTRY_TAG);
689 printf(" </%s>\n", LEGEND_TAG);
690 printf(" </%s>\n", META_TAG);
691 printf(" <%s>\n", DATA_TAG);
692 for (ti = start+step; ti <= end; ti += step) {
693 printf (" <%s>", DATA_ROW_TAG);
694 printf ("<%s>%lu</%s>", COL_TIME_TAG, ti, COL_TIME_TAG);
695 for (j = 0; j < col_cnt; j++) {
697 snprintf(vtag,15,"%s%lu", COL_DATA_TAG, j);
699 snprintf(vtag,15,"%s",COL_DATA_TAG);
701 rrd_value_t newval = DNAN;
704 if (unknownaszero == 1)
705 printf("<%s>0</%s>", vtag,vtag);
707 printf("<%s>NaN</%s>", vtag,vtag);
709 printf("<%s>%0.10e</%s>", vtag, newval, vtag);
713 printf("</%s>\n", DATA_ROW_TAG);
716 printf(" </%s>\n", DATA_TAG);
717 printf("</%s>\n", ROOT_TAG);
721 else if (strcmp("graph", argv[1]) == 0) {
723 #ifdef notused /*XXX*/
724 const char *imgfile = argv[2]; /* rrd_graph changes argv pointer */
729 int tostdout = (strcmp(argv[2],"-") == 0);
731 for (i=2;i<argc;i++){
732 if (strcmp(argv[i],"--imginfo") == 0 || strcmp(argv[i],"-f") == 0){
737 if( rrd_graph(argc-1, &argv[1], &calcpr, &xsize, &ysize, NULL, &ymin, &ymax) != -1 ) {
738 if (!tostdout && !imginfo)
739 printf ("%dx%d\n",xsize,ysize);
741 for(i=0;calcpr[i];i++){
743 printf("%s\n",calcpr[i]);
750 } else if (strcmp("tune", argv[1]) == 0)
751 rrd_tune(argc-1, &argv[1]);
753 rrd_set_error("unknown function '%s'",argv[1]);
755 if (rrd_test_error()) {
756 fprintf(out, "ERROR: %s\n",rrd_get_error());
763 int CountArgs(char *aLine)
768 while (aLine[i] == ' ') i++;
769 while (aLine[i] != 0){
770 if((aLine[i]== ' ') && inarg){
773 if((aLine[i]!= ' ') && ! inarg){
783 * CreateArgs - take a string (aLine) and tokenize
785 int CreateArgs(char *pName, char *aLine, int argc, char **argv)
794 /* remove trailing space and newlines */
795 while (len && aLine[len] <= ' ') {
796 aLine[len] = 0 ; len--;
798 /* sikp leading blanks */
799 while (*aLine && *aLine <= ' ') aLine++;
826 pargv[argc++] = putP;
834 pargv[argc++] = putP;