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);
298 static char *fgetslong(char **aLinePtr, FILE *stream)
301 size_t bufsize = MAX_LENGTH;
304 if (feof(stream)) return *aLinePtr = 0;
305 if (!(linebuf = malloc(bufsize))) {
306 perror("fgetslong: malloc");
310 while (fgets(linebuf + eolpos, MAX_LENGTH, stream)) {
311 eolpos += strlen(linebuf + eolpos);
312 if (linebuf[eolpos - 1] == '\n') return *aLinePtr = linebuf;
313 bufsize += MAX_LENGTH;
314 if (!(linebuf = realloc(linebuf, bufsize))) {
315 perror("fgetslong: realloc");
319 return *aLinePtr = linebuf[0] ? linebuf : 0;
322 int main(int argc, char *argv[])
327 #ifdef MUST_DISABLE_SIGFPE
328 signal(SIGFPE,SIG_IGN);
330 #ifdef MUST_DISABLE_FPMASK
339 if (((argc == 2)||(argc == 3)) && !strcmp("-",argv[1]))
342 struct rusage myusage;
343 struct timeval starttime;
344 struct timeval currenttime;
347 tz.tz_minuteswest =0;
349 gettimeofday(&starttime,&tz);
352 if ((argc == 3) && strcmp("",argv[2])){
365 fprintf(stderr,"ERROR: can't change root to '%s' errno=%d\n",
372 fprintf(stderr,"ERROR: change root is not supported by your OS "
373 "or at least by this copy of rrdtool\n");
380 if (strcmp(firstdir,"")){
383 fprintf(stderr,"ERROR: %s\n",rrd_strerror(errno));
388 while (fgetslong(&aLine, stdin)){
389 if ((argc = CountArgs(aLine)) == 0) {
390 printf("ERROR: not enough arguments\n");
392 if ((myargv = (char **) malloc((argc+1) *
393 sizeof(char *))) == NULL) {
397 if ((argc=CreateArgs(argv[0], aLine, argc, myargv)) < 0) {
398 printf("ERROR: creating arguments\n");
400 int ret = HandleInputLine(argc, myargv, stdout);
406 getrusage(RUSAGE_SELF,&myusage);
407 gettimeofday(¤ttime,&tz);
408 printf("OK u:%1.2f s:%1.2f r:%1.2f\n",
409 (double)myusage.ru_utime.tv_sec+
410 (double)myusage.ru_utime.tv_usec/1000000.0,
411 (double)myusage.ru_stime.tv_sec+
412 (double)myusage.ru_stime.tv_usec/1000000.0,
413 (double)(currenttime.tv_sec-starttime.tv_sec)
414 +(double)(currenttime.tv_usec-starttime.tv_usec)
422 fflush(stdout); /* this is important for pipes to work */
431 else if (argc == 3 && !strcmp(argv[1],"help"))
437 exit(HandleInputLine(argc, argv, stderr));
442 /* HandleInputLine is NOT thread safe - due to readdir issues,
443 resolving them portably is not really simple. */
444 int HandleInputLine(int argc, char **argv, FILE* out)
446 #if defined(HAVE_OPENDIR) && defined (HAVE_READDIR)
447 DIR *curdir; /* to read current dir with ls */
450 #if defined(HAVE_SYS_STAT_H)
455 if (argc>1 && strcmp("quit", argv[1]) == 0){
457 printf("ERROR: invalid parameter count for quit\n");
462 #if defined(HAVE_OPENDIR) && defined(HAVE_READDIR) && defined(HAVE_CHDIR)
463 if (argc>1 && strcmp("cd", argv[1]) == 0){
465 printf("ERROR: invalid parameter count for cd\n");
468 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
469 if (getuid()==0 && ! ChangeRoot){
470 printf("ERROR: chdir security problem - rrdtool is running as "
471 "root but not chroot!\n");
477 printf("ERROR: %s\n",rrd_strerror(errno));
482 if (argc>1 && strcmp("mkdir", argv[1]) == 0){
484 printf("ERROR: invalid parameter count for mkdir\n");
487 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
488 if (getuid()==0 && ! ChangeRoot){
489 printf("ERROR: mkdir security problem - rrdtool is running as "
490 "root but not chroot!\n");
496 printf("ERROR: %s\n",rrd_strerror(errno));
501 if (argc>1 && strcmp("ls", argv[1]) == 0){
503 printf("ERROR: invalid parameter count for ls\n");
506 if ((curdir=opendir("."))!=NULL){
507 while((dent=readdir(curdir))!=NULL){
508 if (!stat(dent->d_name,&st)){
509 if (S_ISDIR(st.st_mode)){
510 printf("d %s\n",dent->d_name);
512 if (strlen(dent->d_name)>4 && S_ISREG(st.st_mode)){
513 if (!strcmp(dent->d_name+NAMLEN(dent)-4,".rrd") ||
514 !strcmp(dent->d_name+NAMLEN(dent)-4,".RRD")){
515 printf("- %s\n",dent->d_name);
522 printf("ERROR: %s\n",rrd_strerror(errno));
527 #endif /* opendir and readdir */
531 || strcmp("help", argv[1]) == 0
532 || strcmp("--help", argv[1]) == 0
533 || strcmp("-help", argv[1]) == 0
534 || strcmp("-?", argv[1]) == 0
535 || strcmp("-h", argv[1]) == 0 ) {
540 if (strcmp("create", argv[1]) == 0)
541 rrd_create(argc-1, &argv[1]);
542 else if (strcmp("dump", argv[1]) == 0)
543 rrd_dump(argc-1, &argv[1]);
544 else if (strcmp("info", argv[1]) == 0
545 || strcmp("updatev", argv[1]) == 0){
547 if (strcmp("info",argv[1]) == 0)
548 data=rrd_info(argc-1, &argv[1]);
550 data=rrd_update_v(argc-1, &argv[1]);
553 printf ("%s = ", data->key);
556 switch (data->type) {
558 if (isnan (data->value.u_val))
561 printf ("%0.10e", data->value.u_val);
564 printf ("%lu", data->value.u_cnt);
567 printf ("%d", data->value.u_int);
570 printf ("\"%s\"", data->value.u_str);
571 free(data->value.u_str);
581 else if (strcmp("--version", argv[1]) == 0 ||
582 strcmp("version", argv[1]) == 0 ||
583 strcmp("v", argv[1]) == 0 ||
584 strcmp("-v", argv[1]) == 0 ||
585 strcmp("-version", argv[1]) == 0 )
586 printf("RRDtool " PACKAGE_VERSION " Copyright by Tobi Oetiker, 1997-2005 (%f)\n",
588 else if (strcmp("restore", argv[1]) == 0)
589 rrd_restore(argc-1, &argv[1]);
590 else if (strcmp("resize", argv[1]) == 0)
591 rrd_resize(argc-1, &argv[1]);
592 else if (strcmp("last", argv[1]) == 0)
593 printf("%ld\n",rrd_last(argc-1, &argv[1]));
594 else if (strcmp("first", argv[1]) == 0)
595 printf("%ld\n",rrd_first(argc-1, &argv[1]));
596 else if (strcmp("update", argv[1]) == 0)
597 rrd_update(argc-1, &argv[1]);
598 else if (strcmp("fetch", argv[1]) == 0) {
599 time_t start,end, ti;
600 unsigned long step, ds_cnt,i,ii;
601 rrd_value_t *data,*datai;
603 if (rrd_fetch(argc-1, &argv[1],&start,&end,&step,&ds_cnt,&ds_namv,&data) != -1) {
606 for (i = 0; i<ds_cnt;i++)
607 printf("%20s",ds_namv[i]);
609 for (ti = start+step; ti <= end; ti += step){
610 printf("%10lu:", ti);
611 for (ii = 0; ii < ds_cnt; ii++)
612 printf(" %0.10e", *(datai++));
615 for (i=0;i<ds_cnt;i++)
620 } else if (strcmp("xport", argv[1]) == 0) {
622 unsigned long int j = 0;
623 time_t start,end, ti;
624 unsigned long step, col_cnt,row_cnt;
625 rrd_value_t *data,*ptr;
627 if(rrd_xport(argc-1, &argv[1], &xxsize,&start,&end,&step,&col_cnt,&legend_v,&data) != -1) {
628 row_cnt = (end-start)/step;
630 printf("<?xml version=\"1.0\" encoding=\"%s\"?>\n\n", XML_ENCODING);
631 printf("<%s>\n", ROOT_TAG);
632 printf(" <%s>\n", META_TAG);
633 printf(" <%s>%lu</%s>\n", META_START_TAG, start+step, META_START_TAG);
634 printf(" <%s>%lu</%s>\n", META_STEP_TAG, step, META_STEP_TAG);
635 printf(" <%s>%lu</%s>\n", META_END_TAG, end, META_END_TAG);
636 printf(" <%s>%lu</%s>\n", META_ROWS_TAG, row_cnt, META_ROWS_TAG);
637 printf(" <%s>%lu</%s>\n", META_COLS_TAG, col_cnt, META_COLS_TAG);
638 printf(" <%s>\n", LEGEND_TAG);
639 for (j = 0; j < col_cnt; j++) {
642 printf(" <%s>%s</%s>\n", LEGEND_ENTRY_TAG, entry, LEGEND_ENTRY_TAG);
646 printf(" </%s>\n", LEGEND_TAG);
647 printf(" </%s>\n", META_TAG);
648 printf(" <%s>\n", DATA_TAG);
649 for (ti = start+step; ti <= end; ti += step) {
650 printf (" <%s>", DATA_ROW_TAG);
651 printf ("<%s>%lu</%s>", COL_TIME_TAG, ti, COL_TIME_TAG);
652 for (j = 0; j < col_cnt; j++) {
653 rrd_value_t newval = DNAN;
656 printf("<%s>NaN</%s>", COL_DATA_TAG, COL_DATA_TAG);
658 printf("<%s>%0.10e</%s>", COL_DATA_TAG, newval, COL_DATA_TAG);
662 printf("</%s>\n", DATA_ROW_TAG);
665 printf(" </%s>\n", DATA_TAG);
666 printf("</%s>\n", ROOT_TAG);
669 else if (strcmp("graph", argv[1]) == 0) {
671 #ifdef notused /*XXX*/
672 const char *imgfile = argv[2]; /* rrd_graph changes argv pointer */
677 int tostdout = (strcmp(argv[2],"-") == 0);
679 for (i=2;i<argc;i++){
680 if (strcmp(argv[i],"--imginfo") == 0 || strcmp(argv[i],"-f") == 0){
685 if( rrd_graph(argc-1, &argv[1], &calcpr, &xsize, &ysize, NULL, &ymin, &ymax) != -1 ) {
686 if (!tostdout && !imginfo)
687 printf ("%dx%d\n",xsize,ysize);
689 for(i=0;calcpr[i];i++){
691 printf("%s\n",calcpr[i]);
698 } else if (strcmp("tune", argv[1]) == 0)
699 rrd_tune(argc-1, &argv[1]);
701 rrd_set_error("unknown function '%s'",argv[1]);
703 if (rrd_test_error()) {
704 fprintf(out, "ERROR: %s\n",rrd_get_error());
711 int CountArgs(char *aLine)
716 while (aLine[i] == ' ') i++;
717 while (aLine[i] != 0){
718 if((aLine[i]== ' ') && inarg){
721 if((aLine[i]!= ' ') && ! inarg){
731 * CreateArgs - take a string (aLine) and tokenize
733 int CreateArgs(char *pName, char *aLine, int argc, char **argv)
742 /* remove trailing space and newlines */
743 while (len && aLine[len] <= ' ') {
744 aLine[len] = 0 ; len--;
746 /* sikp leading blanks */
747 while (*aLine && *aLine <= ' ') aLine++;
774 pargv[argc++] = putP;
782 pargv[argc++] = putP;