1 /*****************************************************************************
2 * RRDtool 1.2.19 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;
369 tz.tz_minuteswest =0;
371 gettimeofday(&starttime,&tz);
374 if ((argc == 3) && strcmp("",argv[2])){
387 fprintf(stderr,"ERROR: can't change root to '%s' errno=%d\n",
394 fprintf(stderr,"ERROR: change root is not supported by your OS "
395 "or at least by this copy of rrdtool\n");
402 if (strcmp(firstdir,"")){
405 fprintf(stderr,"ERROR: %s\n",rrd_strerror(errno));
410 while (fgetslong(&aLine, stdin)){
411 if ((argc = CountArgs(aLine)) == 0) {
412 printf("ERROR: not enough arguments\n");
414 if ((myargv = (char **) malloc((argc+1) *
415 sizeof(char *))) == NULL) {
419 if ((argc=CreateArgs(argv[0], aLine, argc, myargv)) < 0) {
420 printf("ERROR: creating arguments\n");
422 int ret = HandleInputLine(argc, myargv, stdout);
428 getrusage(RUSAGE_SELF,&myusage);
429 gettimeofday(¤ttime,&tz);
430 printf("OK u:%1.2f s:%1.2f r:%1.2f\n",
431 (double)myusage.ru_utime.tv_sec+
432 (double)myusage.ru_utime.tv_usec/1000000.0,
433 (double)myusage.ru_stime.tv_sec+
434 (double)myusage.ru_stime.tv_usec/1000000.0,
435 (double)(currenttime.tv_sec-starttime.tv_sec)
436 +(double)(currenttime.tv_usec-starttime.tv_usec)
444 fflush(stdout); /* this is important for pipes to work */
453 else if (argc == 3 && !strcmp(argv[1],"help"))
459 exit(HandleInputLine(argc, argv, stderr));
464 /* HandleInputLine is NOT thread safe - due to readdir issues,
465 resolving them portably is not really simple. */
466 int HandleInputLine(int argc, char **argv, FILE* out)
468 #if defined(HAVE_OPENDIR) && defined (HAVE_READDIR)
469 DIR *curdir; /* to read current dir with ls */
472 #if defined(HAVE_SYS_STAT_H)
475 char* cwd; /* To hold current working dir on call to pwd */
477 /* Reset errno to 0 before we start.
482 if (argc>1 && strcmp("quit", argv[1]) == 0){
484 printf("ERROR: invalid parameter count for quit\n");
489 #if defined(HAVE_OPENDIR) && defined(HAVE_READDIR) && defined(HAVE_CHDIR)
490 if (argc>1 && strcmp("cd", argv[1]) == 0){
492 printf("ERROR: invalid parameter count for cd\n");
495 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
496 if (getuid()==0 && ! ChangeRoot){
497 printf("ERROR: chdir security problem - rrdtool is running as "
498 "root but not chroot!\n");
504 printf("ERROR: %s\n",rrd_strerror(errno));
509 if (argc>1 && strcmp("pwd", argv[1]) == 0){
511 printf("ERROR: invalid parameter count for pwd\n");
514 cwd = getcwd(NULL, MAXPATH);
516 printf("ERROR: %s\n",rrd_strerror(errno));
523 if (argc>1 && strcmp("mkdir", argv[1]) == 0){
525 printf("ERROR: invalid parameter count for mkdir\n");
528 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
529 if (getuid()==0 && ! ChangeRoot){
530 printf("ERROR: mkdir security problem - rrdtool is running as "
531 "root but not chroot!\n");
537 printf("ERROR: %s\n",rrd_strerror(errno));
542 if (argc>1 && strcmp("ls", argv[1]) == 0){
544 printf("ERROR: invalid parameter count for ls\n");
547 if ((curdir=opendir("."))!=NULL){
548 while((dent=readdir(curdir))!=NULL){
549 if (!stat(dent->d_name,&st)){
550 if (S_ISDIR(st.st_mode)){
551 printf("d %s\n",dent->d_name);
553 if (strlen(dent->d_name)>4 && S_ISREG(st.st_mode)){
554 if (!strcmp(dent->d_name+NAMLEN(dent)-4,".rrd") ||
555 !strcmp(dent->d_name+NAMLEN(dent)-4,".RRD")){
556 printf("- %s\n",dent->d_name);
564 printf("ERROR: %s\n",rrd_strerror(errno));
569 #endif /* opendir and readdir */
573 || strcmp("help", argv[1]) == 0
574 || strcmp("--help", argv[1]) == 0
575 || strcmp("-help", argv[1]) == 0
576 || strcmp("-?", argv[1]) == 0
577 || strcmp("-h", argv[1]) == 0 ) {
582 if (strcmp("create", argv[1]) == 0)
583 rrd_create(argc-1, &argv[1]);
584 else if (strcmp("dump", argv[1]) == 0)
585 rrd_dump(argc-1, &argv[1]);
586 else if (strcmp("info", argv[1]) == 0
587 || strcmp("updatev", argv[1]) == 0){
589 if (strcmp("info",argv[1]) == 0)
590 data=rrd_info(argc-1, &argv[1]);
592 data=rrd_update_v(argc-1, &argv[1]);
595 printf ("%s = ", data->key);
598 switch (data->type) {
600 if (isnan (data->value.u_val))
603 printf ("%0.10e", data->value.u_val);
606 printf ("%lu", data->value.u_cnt);
609 printf ("%d", data->value.u_int);
612 printf ("\"%s\"", data->value.u_str);
613 free(data->value.u_str);
623 else if (strcmp("--version", argv[1]) == 0 ||
624 strcmp("version", argv[1]) == 0 ||
625 strcmp("v", argv[1]) == 0 ||
626 strcmp("-v", argv[1]) == 0 ||
627 strcmp("-version", argv[1]) == 0 )
628 printf("RRDtool " PACKAGE_VERSION " Copyright by Tobi Oetiker, 1997-2005 (%f)\n",
630 else if (strcmp("restore", argv[1]) == 0)
631 rrd_restore(argc-1, &argv[1]);
632 else if (strcmp("resize", argv[1]) == 0)
633 rrd_resize(argc-1, &argv[1]);
634 else if (strcmp("last", argv[1]) == 0)
635 printf("%ld\n",rrd_last(argc-1, &argv[1]));
636 else if (strcmp("lastupdate", argv[1]) == 0) {
640 unsigned long ds_cnt,
642 if (rrd_lastupdate(argc-1, &argv[1], &last_update,
643 &ds_cnt, &ds_namv, &last_ds) == 0) {
644 for (i=0; i<ds_cnt; i++)
645 printf(" %s", ds_namv[i]);
647 printf("%10lu:", last_update);
648 for (i=0; i<ds_cnt; i++) {
649 printf(" %s", last_ds[i]);
657 } else if (strcmp("first", argv[1]) == 0)
658 printf("%ld\n",rrd_first(argc-1, &argv[1]));
659 else if (strcmp("update", argv[1]) == 0)
660 rrd_update(argc-1, &argv[1]);
661 else if (strcmp("fetch", argv[1]) == 0) {
662 time_t start,end, ti;
663 unsigned long step, ds_cnt,i,ii;
664 rrd_value_t *data,*datai;
666 if (rrd_fetch(argc-1, &argv[1],&start,&end,&step,&ds_cnt,&ds_namv,&data) != -1) {
669 for (i = 0; i<ds_cnt;i++)
670 printf("%20s",ds_namv[i]);
672 for (ti = start+step; ti <= end; ti += step){
673 printf("%10lu:", ti);
674 for (ii = 0; ii < ds_cnt; ii++)
675 printf(" %0.10e", *(datai++));
678 for (i=0;i<ds_cnt;i++)
683 } else if (strcmp("xport", argv[1]) == 0) {
685 unsigned long int j = 0;
686 time_t start,end, ti;
687 unsigned long step, col_cnt,row_cnt;
688 rrd_value_t *data,*ptr;
693 vtag = malloc( strlen(COL_DATA_TAG)+10);
694 for ( i = 2; i < argc; i++){
695 if (strcmp("--enumds", argv[i]) == 0)
699 if(rrd_xport(argc-1, &argv[1], &xxsize,&start,&end,&step,&col_cnt,&legend_v,&data) != -1) {
700 row_cnt = (end-start)/step;
702 printf("<?xml version=\"1.0\" encoding=\"%s\"?>\n\n", XML_ENCODING);
703 printf("<%s>\n", ROOT_TAG);
704 printf(" <%s>\n", META_TAG);
705 printf(" <%s>%lu</%s>\n", META_START_TAG, start+step, META_START_TAG);
706 printf(" <%s>%lu</%s>\n", META_STEP_TAG, step, META_STEP_TAG);
707 printf(" <%s>%lu</%s>\n", META_END_TAG, end, META_END_TAG);
708 printf(" <%s>%lu</%s>\n", META_ROWS_TAG, row_cnt, META_ROWS_TAG);
709 printf(" <%s>%lu</%s>\n", META_COLS_TAG, col_cnt, META_COLS_TAG);
710 printf(" <%s>\n", LEGEND_TAG);
711 for (j = 0; j < col_cnt; j++) {
714 printf(" <%s>%s</%s>\n", LEGEND_ENTRY_TAG, entry, LEGEND_ENTRY_TAG);
718 printf(" </%s>\n", LEGEND_TAG);
719 printf(" </%s>\n", META_TAG);
720 printf(" <%s>\n", DATA_TAG);
721 for (ti = start+step; ti <= end; ti += step) {
722 printf (" <%s>", DATA_ROW_TAG);
723 printf ("<%s>%lu</%s>", COL_TIME_TAG, ti, COL_TIME_TAG);
724 for (j = 0; j < col_cnt; j++) {
725 rrd_value_t newval = DNAN;
727 snprintf(vtag,sizeof(vtag),"%s%lu", COL_DATA_TAG, j);
729 snprintf(vtag,sizeof(vtag),"%s",COL_DATA_TAG);
733 printf("<%s>NaN</%s>", vtag,vtag);
735 printf("<%s>%0.10e</%s>", vtag, newval, vtag);
739 printf("</%s>\n", DATA_ROW_TAG);
742 printf(" </%s>\n", DATA_TAG);
743 printf("</%s>\n", ROOT_TAG);
747 else if (strcmp("graph", argv[1]) == 0) {
749 #ifdef notused /*XXX*/
750 const char *imgfile = argv[2]; /* rrd_graph changes argv pointer */
755 int tostdout = (strcmp(argv[2],"-") == 0);
757 for (i=2;i<argc;i++){
758 if (strcmp(argv[i],"--imginfo") == 0 || strcmp(argv[i],"-f") == 0){
763 if( rrd_graph(argc-1, &argv[1], &calcpr, &xsize, &ysize, NULL, &ymin, &ymax) != -1 ) {
764 if (!tostdout && !imginfo)
765 printf ("%dx%d\n",xsize,ysize);
767 for(i=0;calcpr[i];i++){
769 printf("%s\n",calcpr[i]);
776 } else if (strcmp("tune", argv[1]) == 0)
777 rrd_tune(argc-1, &argv[1]);
779 rrd_set_error("unknown function '%s'",argv[1]);
781 if (rrd_test_error()) {
782 fprintf(out, "ERROR: %s\n",rrd_get_error());
789 int CountArgs(char *aLine)
794 while (aLine[i] == ' ') i++;
795 while (aLine[i] != 0){
796 if((aLine[i]== ' ') && inarg){
799 if((aLine[i]!= ' ') && ! inarg){
809 * CreateArgs - take a string (aLine) and tokenize
811 int CreateArgs(char *pName, char *aLine, int argc, char **argv)
820 /* remove trailing space and newlines */
821 while (len && aLine[len] <= ' ') {
822 aLine[len] = 0 ; len--;
824 /* sikp leading blanks */
825 while (*aLine && *aLine <= ' ') aLine++;
852 pargv[argc++] = putP;
860 pargv[argc++] = putP;