1 /*****************************************************************************
2 * RRDtool 1.2.23 Copyright by Tobi Oetiker, 1997-2007
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-2007 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, lastupdate, first, info, fetch, tune,\n"
32 "\t\tresize, xport\n\n";
34 char help_listremote[] =
35 "Valid remote commands: quit, ls, cd, mkdir, pwd\n\n";
39 "* create - create a new RRD\n\n"
40 "\trrdtool create filename [--start|-b start time]\n"
41 "\t\t[--step|-s step]\n"
42 "\t\t[DS:ds-name:DST:dst arguments]\n"
43 "\t\t[RRA:CF:cf arguments]\n\n";
46 "* dump - dump an RRD to XML\n\n"
47 "\trrdtool dump filename.rrd >filename.xml\n\n";
50 "* info - returns the configuration and status of the RRD\n\n"
51 "\trrdtool info filename.rrd\n\n";
54 "* restore - restore an RRD file from its XML form\n\n"
55 "\trrdtool restore [--range-check|-r] [--force-overwrite|-f] filename.xml filename.rrd\n\n";
58 "* last - show last update time for RRD\n\n"
59 "\trrdtool last filename.rrd\n\n";
61 char help_lastupdate[] =
62 "* lastupdate - returns the most recent datum stored for\n"
63 " each DS in an RRD\n\n"
64 "\trrdtool lastupdate filename.rrd\n\n";
67 "* first - show first update time for RRA within an RRD\n\n"
68 "\trrdtool first filename.rrd [--rraindex number]\n\n";
71 "* update - update an RRD\n\n"
72 "\trrdtool update filename\n"
73 "\t\t--template|-t ds-name:ds-name:...\n"
74 "\t\ttime|N:value[:value...]\n\n"
75 "\t\tat-time@value[:value...]\n\n"
76 "\t\t[ time:value[:value...] ..]\n\n";
79 "* updatev - a verbose version of update\n"
80 "\treturns information about values, RRAs, and datasources updated\n\n"
81 "\trrdtool updatev filename\n"
82 "\t\t--template|-t ds-name:ds-name:...\n"
83 "\t\ttime|N:value[:value...]\n\n"
84 "\t\tat-time@value[:value...]\n\n"
85 "\t\t[ time:value[:value...] ..]\n\n";
88 "* fetch - fetch data out of an RRD\n\n"
89 "\trrdtool fetch filename.rrd CF\n"
90 "\t\t[-r|--resolution resolution]\n"
91 "\t\t[-s|--start start] [-e|--end end]\n\n";
93 /* break up very large strings (help_graph, help_tune) for ISO C89 compliance*/
96 "* graph - generate a graph from one or several RRD\n\n"
97 "\trrdtool graph filename [-s|--start seconds] [-e|--end seconds]\n"
98 "\t\t[-x|--x-grid x-axis grid and label]\n"
99 "\t\t[-Y|--alt-y-grid]\n"
100 "\t\t[-y|--y-grid y-axis grid and label]\n"
101 "\t\t[-v|--vertical-label string] [-w|--width pixels]\n"
102 "\t\t[-h|--height pixels] [-o|--logarithmic]\n"
103 "\t\t[-u|--upper-limit value] [-z|--lazy]\n"
104 "\t\t[-l|--lower-limit value] [-r|--rigid]\n"
105 "\t\t[-g|--no-legend]\n"
106 "\t\t[-F|--force-rules-legend]\n"
107 "\t\t[-j|--only-graph]\n";
109 "\t\t[-n|--font FONTTAG:size:font]\n"
110 "\t\t[-m|--zoom factor]\n"
111 "\t\t[-A|--alt-autoscale]\n"
112 "\t\t[-M|--alt-autoscale-max]\n"
113 "\t\t[-R|--font-render-mode {normal,light,mono}]\n"
114 "\t\t[-B|--font-smoothing-threshold size]\n"
115 "\t\t[-E|--slope-mode]\n"
116 "\t\t[-N|--no-gridfit]\n"
117 "\t\t[-X|--units-exponent value]\n"
118 "\t\t[-L|--units-length value]\n"
119 "\t\t[-S|--step seconds]\n"
120 "\t\t[-f|--imginfo printfstr]\n"
121 "\t\t[-a|--imgformat PNG]\n"
122 "\t\t[-c|--color COLORTAG#rrggbb[aa]] [-t|--title string]\n"
123 "\t\t[-W|--watermark string]\n"
124 "\t\t[DEF:vname=rrd:ds-name:CF]\n";
126 "\t\t[CDEF:vname=rpn-expression]\n"
127 "\t\t[VDEF:vdefname=rpn-expression]\n"
128 "\t\t[PRINT:vdefname:format]\n"
129 "\t\t[GPRINT:vdefname:format]\n"
130 "\t\t[COMMENT:text]\n"
131 "\t\t[SHIFT:vname:offset]\n"
132 "\t\t[TICK:vname#rrggbb[aa][:[fraction][:legend]]]\n"
133 "\t\t[HRULE:value#rrggbb[aa][:legend]]\n"
134 "\t\t[VRULE:value#rrggbb[aa][:legend]]\n"
135 "\t\t[LINE[width]:vname[#rrggbb[aa][:[legend][:STACK]]]]\n"
136 "\t\t[AREA:vname[#rrggbb[aa][:[legend][:STACK]]]]\n"
137 "\t\t[PRINT:vname:CF:format] (deprecated)\n"
138 "\t\t[GPRINT:vname:CF:format] (deprecated)\n"
139 "\t\t[STACK:vname[#rrggbb[aa][:legend]]] (deprecated)\n\n";
142 " * tune - Modify some basic properties of an RRD\n\n"
143 "\trrdtool tune filename\n"
144 "\t\t[--heartbeat|-h ds-name:heartbeat]\n"
145 "\t\t[--data-source-type|-d ds-name:DST]\n"
146 "\t\t[--data-source-rename|-r old-name:new-name]\n"
147 "\t\t[--minimum|-i ds-name:min] [--maximum|-a ds-name:max]\n"
148 "\t\t[--deltapos scale-value] [--deltaneg scale-value]\n"
149 "\t\t[--failure-threshold integer]\n"
150 "\t\t[--window-length integer]\n"
151 "\t\t[--alpha adaptation-parameter]\n";
153 " * tune - Modify some basic properties of an RRD\n\n"
154 "\t\t[--beta adaptation-parameter]\n"
155 "\t\t[--gamma adaptation-parameter]\n"
156 "\t\t[--gamma-deviation adaptation-parameter]\n"
157 "\t\t[--aberrant-reset ds-name]\n\n";
160 " * resize - alter the length of one of the RRAs in an RRD\n\n"
161 "\trrdtool resize filename rranum GROW|SHRINK rows\n\n";
164 "* xport - generate XML dump from one or several RRD\n\n"
165 "\trrdtool xport [-s|--start seconds] [-e|--end seconds]\n"
166 "\t\t[-m|--maxrows rows]\n"
167 "\t\t[--step seconds]\n"
169 "\t\t[DEF:vname=rrd:ds-name:CF]\n"
170 "\t\t[CDEF:vname=rpn-expression]\n"
171 "\t\t[XPORT:vname:legend]\n\n";
174 " * quit - closing a session in remote mode\n\n"
175 "\trrdtool quit\n\n";
178 " * ls - lists all *.rrd files in current directory\n\n"
182 " * cd - changes the current directory\n\n"
183 "\trrdtool cd new directory\n\n";
186 " * mkdir - creates a new directory\n\n"
187 "\trrdtool mkdir newdirectoryname\n\n";
190 " * pwd - returns the current working directory\n\n"
194 "RRDtool is distributed under the Terms of the GNU General\n"
195 "Public License Version 2. (www.gnu.org/copyleft/gpl.html)\n\n"
197 "For more information read the RRD manpages\n\n";
199 enum { C_NONE, C_CREATE, C_DUMP, C_INFO, C_RESTORE, C_LAST,
200 C_LASTUPDATE, C_FIRST, C_UPDATE, C_FETCH, C_GRAPH, C_TUNE,
201 C_RESIZE, C_XPORT, C_QUIT, C_LS, C_CD, C_MKDIR, C_PWD,
204 int help_cmd = C_NONE;
208 if (!strcmp(cmd,"create"))
210 else if (!strcmp(cmd,"dump"))
212 else if (!strcmp(cmd,"info"))
214 else if (!strcmp(cmd,"restore"))
215 help_cmd = C_RESTORE;
216 else if (!strcmp(cmd,"last"))
218 else if (!strcmp(cmd,"lastupdate"))
219 help_cmd = C_LASTUPDATE;
220 else if (!strcmp(cmd,"first"))
222 else if (!strcmp(cmd,"update"))
224 else if (!strcmp(cmd,"updatev"))
225 help_cmd = C_UPDATEV;
226 else if (!strcmp(cmd,"fetch"))
228 else if (!strcmp(cmd,"graph"))
230 else if (!strcmp(cmd,"tune"))
232 else if (!strcmp(cmd,"resize"))
234 else if (!strcmp(cmd,"xport"))
236 else if (!strcmp(cmd,"quit"))
238 else if (!strcmp(cmd,"ls"))
240 else if (!strcmp(cmd,"cd"))
242 else if (!strcmp(cmd,"mkdir"))
244 else if (!strcmp(cmd,"pwd"))
247 fputs(help_main, stdout);
251 fputs(help_list, stdout);
253 fputs(help_listremote, stdout);
257 fputs(help_create, stdout);
260 fputs(help_dump, stdout);
263 fputs(help_info, stdout);
266 fputs(help_restore, stdout);
269 fputs(help_last, stdout);
272 fputs(help_lastupdate, stdout);
275 fputs(help_first, stdout);
278 fputs(help_update, stdout);
281 fputs(help_updatev, stdout);
284 fputs(help_fetch, stdout);
287 fputs(help_graph1, stdout);
288 fputs(help_graph2, stdout);
289 fputs(help_graph3, stdout);
292 fputs(help_tune1, stdout);
293 fputs(help_tune2, stdout);
296 fputs(help_resize, stdout);
299 fputs(help_xport, stdout);
302 fputs(help_quit, stdout);
305 fputs(help_ls, stdout);
308 fputs(help_cd, stdout);
311 fputs(help_mkdir, stdout);
314 fputs(help_pwd, stdout);
317 fputs(help_lic, stdout);
320 static char *fgetslong(char **aLinePtr, FILE *stream)
323 size_t bufsize = MAX_LENGTH;
326 if (feof(stream)) return *aLinePtr = 0;
327 if (!(linebuf = malloc(bufsize))) {
328 perror("fgetslong: malloc");
332 while (fgets(linebuf + eolpos, MAX_LENGTH, stream)) {
333 eolpos += strlen(linebuf + eolpos);
334 if (linebuf[eolpos - 1] == '\n') return *aLinePtr = linebuf;
335 bufsize += MAX_LENGTH;
336 if (!(linebuf = realloc(linebuf, bufsize))) {
337 perror("fgetslong: realloc");
341 return *aLinePtr = linebuf[0] ? linebuf : 0;
344 int main(int argc, char *argv[])
349 #ifdef MUST_DISABLE_SIGFPE
350 signal(SIGFPE,SIG_IGN);
352 #ifdef MUST_DISABLE_FPMASK
361 if (((argc == 2)||(argc == 3)) && !strcmp("-",argv[1]))
364 struct rusage myusage;
365 struct timeval starttime;
366 struct timeval currenttime;
368 gettimeofday(&starttime, NULL);
371 if ((argc == 3) && strcmp("",argv[2])){
384 fprintf(stderr,"ERROR: can't change root to '%s' errno=%d\n",
391 fprintf(stderr,"ERROR: change root is not supported by your OS "
392 "or at least by this copy of rrdtool\n");
399 if (strcmp(firstdir,"")){
402 fprintf(stderr,"ERROR: %s\n",rrd_strerror(errno));
407 while (fgetslong(&aLine, stdin)){
408 if ((argc = CountArgs(aLine)) == 0) {
409 printf("ERROR: not enough arguments\n");
411 if ((myargv = (char **) malloc((argc+1) *
412 sizeof(char *))) == NULL) {
416 if ((argc=CreateArgs(argv[0], aLine, argc, myargv)) < 0) {
417 printf("ERROR: creating arguments\n");
419 int ret = HandleInputLine(argc, myargv, stdout);
425 getrusage(RUSAGE_SELF,&myusage);
426 gettimeofday(¤ttime,NULL);
427 printf("OK u:%1.2f s:%1.2f r:%1.2f\n",
428 (double)myusage.ru_utime.tv_sec+
429 (double)myusage.ru_utime.tv_usec/1000000.0,
430 (double)myusage.ru_stime.tv_sec+
431 (double)myusage.ru_stime.tv_usec/1000000.0,
432 (double)(currenttime.tv_sec-starttime.tv_sec)
433 +(double)(currenttime.tv_usec-starttime.tv_usec)
441 fflush(stdout); /* this is important for pipes to work */
450 else if (argc == 3 && !strcmp(argv[1],"help"))
456 exit(HandleInputLine(argc, argv, stderr));
461 /* HandleInputLine is NOT thread safe - due to readdir issues,
462 resolving them portably is not really simple. */
463 int HandleInputLine(int argc, char **argv, FILE* out)
465 #if defined(HAVE_OPENDIR) && defined (HAVE_READDIR)
466 DIR *curdir; /* to read current dir with ls */
469 #if defined(HAVE_SYS_STAT_H)
472 char* cwd; /* To hold current working dir on call to pwd */
474 /* Reset errno to 0 before we start.
479 if (argc>1 && strcmp("quit", argv[1]) == 0){
481 printf("ERROR: invalid parameter count for quit\n");
486 #if defined(HAVE_OPENDIR) && defined(HAVE_READDIR) && defined(HAVE_CHDIR)
487 if (argc>1 && strcmp("cd", argv[1]) == 0){
489 printf("ERROR: invalid parameter count for cd\n");
492 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
493 if (getuid()==0 && ! ChangeRoot){
494 printf("ERROR: chdir security problem - rrdtool is running as "
495 "root but not chroot!\n");
501 printf("ERROR: %s\n",rrd_strerror(errno));
506 if (argc>1 && strcmp("pwd", argv[1]) == 0){
508 printf("ERROR: invalid parameter count for pwd\n");
511 cwd = getcwd(NULL, MAXPATH);
513 printf("ERROR: %s\n",rrd_strerror(errno));
520 if (argc>1 && strcmp("mkdir", argv[1]) == 0){
522 printf("ERROR: invalid parameter count for mkdir\n");
525 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
526 if (getuid()==0 && ! ChangeRoot){
527 printf("ERROR: mkdir security problem - rrdtool is running as "
528 "root but not chroot!\n");
534 printf("ERROR: %s\n",rrd_strerror(errno));
539 if (argc>1 && strcmp("ls", argv[1]) == 0){
541 printf("ERROR: invalid parameter count for ls\n");
544 if ((curdir=opendir("."))!=NULL){
545 while((dent=readdir(curdir))!=NULL){
546 if (!stat(dent->d_name,&st)){
547 if (S_ISDIR(st.st_mode)){
548 printf("d %s\n",dent->d_name);
550 if (strlen(dent->d_name)>4 && S_ISREG(st.st_mode)){
551 if (!strcmp(dent->d_name+NAMLEN(dent)-4,".rrd") ||
552 !strcmp(dent->d_name+NAMLEN(dent)-4,".RRD")){
553 printf("- %s\n",dent->d_name);
561 printf("ERROR: %s\n",rrd_strerror(errno));
566 #endif /* opendir and readdir */
570 || strcmp("help", argv[1]) == 0
571 || strcmp("--help", argv[1]) == 0
572 || strcmp("-help", argv[1]) == 0
573 || strcmp("-?", argv[1]) == 0
574 || strcmp("-h", argv[1]) == 0 ) {
579 if (strcmp("create", argv[1]) == 0)
580 rrd_create(argc-1, &argv[1]);
581 else if (strcmp("dump", argv[1]) == 0)
582 rrd_dump(argc-1, &argv[1]);
583 else if (strcmp("info", argv[1]) == 0
584 || strcmp("updatev", argv[1]) == 0){
586 if (strcmp("info",argv[1]) == 0)
587 data=rrd_info(argc-1, &argv[1]);
589 data=rrd_update_v(argc-1, &argv[1]);
592 printf ("%s = ", data->key);
595 switch (data->type) {
597 if (isnan (data->value.u_val))
600 printf ("%0.10e", data->value.u_val);
603 printf ("%lu", data->value.u_cnt);
606 printf ("%d", data->value.u_int);
609 printf ("\"%s\"", data->value.u_str);
610 free(data->value.u_str);
620 else if (strcmp("--version", argv[1]) == 0 ||
621 strcmp("version", argv[1]) == 0 ||
622 strcmp("v", argv[1]) == 0 ||
623 strcmp("-v", argv[1]) == 0 ||
624 strcmp("-version", argv[1]) == 0 )
625 printf("RRDtool " PACKAGE_VERSION " Copyright by Tobi Oetiker, 1997-2005 (%f)\n",
627 else if (strcmp("restore", argv[1]) == 0)
628 rrd_restore(argc-1, &argv[1]);
629 else if (strcmp("resize", argv[1]) == 0)
630 rrd_resize(argc-1, &argv[1]);
631 else if (strcmp("last", argv[1]) == 0)
632 printf("%ld\n",rrd_last(argc-1, &argv[1]));
633 else if (strcmp("lastupdate", argv[1]) == 0) {
637 unsigned long ds_cnt,
639 if (rrd_lastupdate(argc-1, &argv[1], &last_update,
640 &ds_cnt, &ds_namv, &last_ds) == 0) {
641 for (i=0; i<ds_cnt; i++)
642 printf(" %s", ds_namv[i]);
644 printf("%10lu:", last_update);
645 for (i=0; i<ds_cnt; i++) {
646 printf(" %s", last_ds[i]);
654 } else if (strcmp("first", argv[1]) == 0)
655 printf("%ld\n",rrd_first(argc-1, &argv[1]));
656 else if (strcmp("update", argv[1]) == 0)
657 rrd_update(argc-1, &argv[1]);
658 else if (strcmp("fetch", argv[1]) == 0) {
659 time_t start,end, ti;
660 unsigned long step, ds_cnt,i,ii;
661 rrd_value_t *data,*datai;
663 if (rrd_fetch(argc-1, &argv[1],&start,&end,&step,&ds_cnt,&ds_namv,&data) != -1) {
666 for (i = 0; i<ds_cnt;i++)
667 printf("%20s",ds_namv[i]);
669 for (ti = start+step; ti <= end; ti += step){
670 printf("%10lu:", ti);
671 for (ii = 0; ii < ds_cnt; ii++)
672 printf(" %0.10e", *(datai++));
675 for (i=0;i<ds_cnt;i++)
680 } else if (strcmp("xport", argv[1]) == 0) {
682 unsigned long int j = 0;
683 time_t start,end, ti;
684 unsigned long step, col_cnt,row_cnt;
685 rrd_value_t *data,*ptr;
689 size_t vtag_s = strlen(COL_DATA_TAG) + 10;
690 char *vtag = malloc(vtag_s);
691 for ( i = 2; i < argc; i++){
692 if (strcmp("--enumds", argv[i]) == 0)
696 if(rrd_xport(argc-1, &argv[1], &xxsize,&start,&end,&step,&col_cnt,&legend_v,&data) != -1) {
697 row_cnt = (end-start)/step;
699 printf("<?xml version=\"1.0\" encoding=\"%s\"?>\n\n", XML_ENCODING);
700 printf("<%s>\n", ROOT_TAG);
701 printf(" <%s>\n", META_TAG);
702 printf(" <%s>%lu</%s>\n", META_START_TAG, start+step, META_START_TAG);
703 printf(" <%s>%lu</%s>\n", META_STEP_TAG, step, META_STEP_TAG);
704 printf(" <%s>%lu</%s>\n", META_END_TAG, end, META_END_TAG);
705 printf(" <%s>%lu</%s>\n", META_ROWS_TAG, row_cnt, META_ROWS_TAG);
706 printf(" <%s>%lu</%s>\n", META_COLS_TAG, col_cnt, META_COLS_TAG);
707 printf(" <%s>\n", LEGEND_TAG);
708 for (j = 0; j < col_cnt; j++) {
711 printf(" <%s>%s</%s>\n", LEGEND_ENTRY_TAG, entry, LEGEND_ENTRY_TAG);
715 printf(" </%s>\n", LEGEND_TAG);
716 printf(" </%s>\n", META_TAG);
717 printf(" <%s>\n", DATA_TAG);
718 for (ti = start+step; ti <= end; ti += step) {
719 printf (" <%s>", DATA_ROW_TAG);
720 printf ("<%s>%lu</%s>", COL_TIME_TAG, ti, COL_TIME_TAG);
721 for (j = 0; j < col_cnt; j++) {
722 rrd_value_t newval = DNAN;
724 snprintf(vtag,vtag_s,"%s%lu", COL_DATA_TAG, j);
726 snprintf(vtag,vtag_s,"%s",COL_DATA_TAG);
730 printf("<%s>NaN</%s>", vtag,vtag);
732 printf("<%s>%0.10e</%s>", vtag, newval, vtag);
736 printf("</%s>\n", DATA_ROW_TAG);
739 printf(" </%s>\n", DATA_TAG);
740 printf("</%s>\n", ROOT_TAG);
744 else if (strcmp("graph", argv[1]) == 0) {
746 #ifdef notused /*XXX*/
747 const char *imgfile = argv[2]; /* rrd_graph changes argv pointer */
752 int tostdout = (strcmp(argv[2],"-") == 0);
754 for (i=2;i<argc;i++){
755 if (strcmp(argv[i],"--imginfo") == 0 || strcmp(argv[i],"-f") == 0){
760 if( rrd_graph(argc-1, &argv[1], &calcpr, &xsize, &ysize, NULL, &ymin, &ymax) != -1 ) {
761 if (!tostdout && !imginfo)
762 printf ("%dx%d\n",xsize,ysize);
764 for(i=0;calcpr[i];i++){
766 printf("%s\n",calcpr[i]);
773 } else if (strcmp("tune", argv[1]) == 0)
774 rrd_tune(argc-1, &argv[1]);
776 rrd_set_error("unknown function '%s'",argv[1]);
778 if (rrd_test_error()) {
779 fprintf(out, "ERROR: %s\n",rrd_get_error());
786 int CountArgs(char *aLine)
791 while (aLine[i] == ' ') i++;
792 while (aLine[i] != 0){
793 if((aLine[i]== ' ') && inarg){
796 if((aLine[i]!= ' ') && ! inarg){
806 * CreateArgs - take a string (aLine) and tokenize
808 int CreateArgs(char *pName, char *aLine, int argc, char **argv)
817 /* remove trailing space and newlines */
818 while (len && aLine[len] <= ' ') {
819 aLine[len] = 0 ; len--;
821 /* sikp leading blanks */
822 while (*aLine && *aLine <= ' ') aLine++;
849 pargv[argc++] = putP;
857 pargv[argc++] = putP;