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[DEF:vname=rrd:ds-name:CF]\n"
164 "\t\t[CDEF:vname=rpn-expression]\n"
165 "\t\t[XPORT:vname:legend]\n\n";
168 " * quit - closing a session in remote mode\n\n"
169 "\trrdtool quit\n\n";
172 " * ls - lists all *.rrd files in current directory\n\n"
176 " * cd - changes the current directory\n\n"
177 "\trrdtool cd new directory\n\n";
180 " * mkdir - creates a new directory\n\n"
181 "\trrdtool mkdir newdirectoryname\n\n";
184 " * pwd - returns the current working directory\n\n"
188 "RRDtool is distributed under the Terms of the GNU General\n"
189 "Public License Version 2. (www.gnu.org/copyleft/gpl.html)\n\n"
191 "For more information read the RRD manpages\n\n";
193 enum { C_NONE, C_CREATE, C_DUMP, C_INFO, C_RESTORE, C_LAST, C_FIRST,
194 C_UPDATE, C_FETCH, C_GRAPH, C_TUNE, C_RESIZE, C_XPORT,
195 C_QUIT, C_LS, C_CD, C_MKDIR, C_PWD, C_UPDATEV };
197 int help_cmd = C_NONE;
201 if (!strcmp(cmd,"create"))
203 else if (!strcmp(cmd,"dump"))
205 else if (!strcmp(cmd,"info"))
207 else if (!strcmp(cmd,"restore"))
208 help_cmd = C_RESTORE;
209 else if (!strcmp(cmd,"last"))
211 else if (!strcmp(cmd,"first"))
213 else if (!strcmp(cmd,"update"))
215 else if (!strcmp(cmd,"updatev"))
216 help_cmd = C_UPDATEV;
217 else if (!strcmp(cmd,"fetch"))
219 else if (!strcmp(cmd,"graph"))
221 else if (!strcmp(cmd,"tune"))
223 else if (!strcmp(cmd,"resize"))
225 else if (!strcmp(cmd,"xport"))
227 else if (!strcmp(cmd,"quit"))
229 else if (!strcmp(cmd,"ls"))
231 else if (!strcmp(cmd,"cd"))
233 else if (!strcmp(cmd,"mkdir"))
235 else if (!strcmp(cmd,"pwd"))
238 fputs(help_main, stdout);
242 fputs(help_list, stdout);
244 fputs(help_listremote, stdout);
248 fputs(help_create, stdout);
251 fputs(help_dump, stdout);
254 fputs(help_info, stdout);
257 fputs(help_restore, stdout);
260 fputs(help_last, stdout);
263 fputs(help_first, stdout);
266 fputs(help_update, stdout);
269 fputs(help_updatev, stdout);
272 fputs(help_fetch, stdout);
275 fputs(help_graph1, stdout);
276 fputs(help_graph2, stdout);
277 fputs(help_graph3, stdout);
280 fputs(help_tune1, stdout);
281 fputs(help_tune2, stdout);
284 fputs(help_resize, stdout);
287 fputs(help_xport, stdout);
290 fputs(help_quit, stdout);
293 fputs(help_ls, stdout);
296 fputs(help_cd, stdout);
299 fputs(help_mkdir, stdout);
302 fputs(help_pwd, stdout);
305 fputs(help_lic, stdout);
308 static char *fgetslong(char **aLinePtr, FILE *stream)
311 size_t bufsize = MAX_LENGTH;
314 if (feof(stream)) return *aLinePtr = 0;
315 if (!(linebuf = malloc(bufsize))) {
316 perror("fgetslong: malloc");
320 while (fgets(linebuf + eolpos, MAX_LENGTH, stream)) {
321 eolpos += strlen(linebuf + eolpos);
322 if (linebuf[eolpos - 1] == '\n') return *aLinePtr = linebuf;
323 bufsize += MAX_LENGTH;
324 if (!(linebuf = realloc(linebuf, bufsize))) {
325 perror("fgetslong: realloc");
329 return *aLinePtr = linebuf[0] ? linebuf : 0;
332 int main(int argc, char *argv[])
337 #ifdef MUST_DISABLE_SIGFPE
338 signal(SIGFPE,SIG_IGN);
340 #ifdef MUST_DISABLE_FPMASK
349 if (((argc == 2)||(argc == 3)) && !strcmp("-",argv[1]))
352 struct rusage myusage;
353 struct timeval starttime;
354 struct timeval currenttime;
357 tz.tz_minuteswest =0;
359 gettimeofday(&starttime,&tz);
362 if ((argc == 3) && strcmp("",argv[2])){
375 fprintf(stderr,"ERROR: can't change root to '%s' errno=%d\n",
382 fprintf(stderr,"ERROR: change root is not supported by your OS "
383 "or at least by this copy of rrdtool\n");
390 if (strcmp(firstdir,"")){
393 fprintf(stderr,"ERROR: %s\n",rrd_strerror(errno));
398 while (fgetslong(&aLine, stdin)){
399 if ((argc = CountArgs(aLine)) == 0) {
400 printf("ERROR: not enough arguments\n");
402 if ((myargv = (char **) malloc((argc+1) *
403 sizeof(char *))) == NULL) {
407 if ((argc=CreateArgs(argv[0], aLine, argc, myargv)) < 0) {
408 printf("ERROR: creating arguments\n");
410 int ret = HandleInputLine(argc, myargv, stdout);
416 getrusage(RUSAGE_SELF,&myusage);
417 gettimeofday(¤ttime,&tz);
418 printf("OK u:%1.2f s:%1.2f r:%1.2f\n",
419 (double)myusage.ru_utime.tv_sec+
420 (double)myusage.ru_utime.tv_usec/1000000.0,
421 (double)myusage.ru_stime.tv_sec+
422 (double)myusage.ru_stime.tv_usec/1000000.0,
423 (double)(currenttime.tv_sec-starttime.tv_sec)
424 +(double)(currenttime.tv_usec-starttime.tv_usec)
432 fflush(stdout); /* this is important for pipes to work */
441 else if (argc == 3 && !strcmp(argv[1],"help"))
447 exit(HandleInputLine(argc, argv, stderr));
452 /* HandleInputLine is NOT thread safe - due to readdir issues,
453 resolving them portably is not really simple. */
454 int HandleInputLine(int argc, char **argv, FILE* out)
456 #if defined(HAVE_OPENDIR) && defined (HAVE_READDIR)
457 DIR *curdir; /* to read current dir with ls */
460 #if defined(HAVE_SYS_STAT_H)
463 char* cwd; /* To hold current working dir on call to pwd */
465 /* Reset errno to 0 before we start.
470 if (argc>1 && strcmp("quit", argv[1]) == 0){
472 printf("ERROR: invalid parameter count for quit\n");
477 #if defined(HAVE_OPENDIR) && defined(HAVE_READDIR) && defined(HAVE_CHDIR)
478 if (argc>1 && strcmp("cd", argv[1]) == 0){
480 printf("ERROR: invalid parameter count for cd\n");
483 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
484 if (getuid()==0 && ! ChangeRoot){
485 printf("ERROR: chdir security problem - rrdtool is running as "
486 "root but not chroot!\n");
492 printf("ERROR: %s\n",rrd_strerror(errno));
497 if (argc>1 && strcmp("pwd", argv[1]) == 0){
499 printf("ERROR: invalid parameter count for pwd\n");
502 cwd = getcwd(NULL, MAXPATH);
504 printf("ERROR: %s\n",rrd_strerror(errno));
511 if (argc>1 && strcmp("mkdir", argv[1]) == 0){
513 printf("ERROR: invalid parameter count for mkdir\n");
516 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
517 if (getuid()==0 && ! ChangeRoot){
518 printf("ERROR: mkdir security problem - rrdtool is running as "
519 "root but not chroot!\n");
525 printf("ERROR: %s\n",rrd_strerror(errno));
530 if (argc>1 && strcmp("ls", argv[1]) == 0){
532 printf("ERROR: invalid parameter count for ls\n");
535 if ((curdir=opendir("."))!=NULL){
536 while((dent=readdir(curdir))!=NULL){
537 if (!stat(dent->d_name,&st)){
538 if (S_ISDIR(st.st_mode)){
539 printf("d %s\n",dent->d_name);
541 if (strlen(dent->d_name)>4 && S_ISREG(st.st_mode)){
542 if (!strcmp(dent->d_name+NAMLEN(dent)-4,".rrd") ||
543 !strcmp(dent->d_name+NAMLEN(dent)-4,".RRD")){
544 printf("- %s\n",dent->d_name);
552 printf("ERROR: %s\n",rrd_strerror(errno));
557 #endif /* opendir and readdir */
561 || strcmp("help", argv[1]) == 0
562 || strcmp("--help", argv[1]) == 0
563 || strcmp("-help", argv[1]) == 0
564 || strcmp("-?", argv[1]) == 0
565 || strcmp("-h", argv[1]) == 0 ) {
570 if (strcmp("create", argv[1]) == 0)
571 rrd_create(argc-1, &argv[1]);
572 else if (strcmp("dump", argv[1]) == 0)
573 rrd_dump(argc-1, &argv[1]);
574 else if (strcmp("info", argv[1]) == 0
575 || strcmp("updatev", argv[1]) == 0){
577 if (strcmp("info",argv[1]) == 0)
578 data=rrd_info(argc-1, &argv[1]);
580 data=rrd_update_v(argc-1, &argv[1]);
583 printf ("%s = ", data->key);
586 switch (data->type) {
588 if (isnan (data->value.u_val))
591 printf ("%0.10e", data->value.u_val);
594 printf ("%lu", data->value.u_cnt);
597 printf ("%d", data->value.u_int);
600 printf ("\"%s\"", data->value.u_str);
601 free(data->value.u_str);
611 else if (strcmp("--version", argv[1]) == 0 ||
612 strcmp("version", argv[1]) == 0 ||
613 strcmp("v", argv[1]) == 0 ||
614 strcmp("-v", argv[1]) == 0 ||
615 strcmp("-version", argv[1]) == 0 )
616 printf("RRDtool " PACKAGE_VERSION " Copyright by Tobi Oetiker, 1997-2005 (%f)\n",
618 else if (strcmp("restore", argv[1]) == 0)
619 rrd_restore(argc-1, &argv[1]);
620 else if (strcmp("resize", argv[1]) == 0)
621 rrd_resize(argc-1, &argv[1]);
622 else if (strcmp("last", argv[1]) == 0)
623 printf("%ld\n",rrd_last(argc-1, &argv[1]));
624 else if (strcmp("first", argv[1]) == 0)
625 printf("%ld\n",rrd_first(argc-1, &argv[1]));
626 else if (strcmp("update", argv[1]) == 0)
627 rrd_update(argc-1, &argv[1]);
628 else if (strcmp("fetch", argv[1]) == 0) {
629 time_t start,end, ti;
630 unsigned long step, ds_cnt,i,ii;
631 rrd_value_t *data,*datai;
633 if (rrd_fetch(argc-1, &argv[1],&start,&end,&step,&ds_cnt,&ds_namv,&data) != -1) {
636 for (i = 0; i<ds_cnt;i++)
637 printf("%20s",ds_namv[i]);
639 for (ti = start+step; ti <= end; ti += step){
640 printf("%10lu:", ti);
641 for (ii = 0; ii < ds_cnt; ii++)
642 printf(" %0.10e", *(datai++));
645 for (i=0;i<ds_cnt;i++)
650 } else if (strcmp("xport", argv[1]) == 0) {
652 unsigned long int j = 0;
653 time_t start,end, ti;
654 unsigned long step, col_cnt,row_cnt;
655 rrd_value_t *data,*ptr;
660 vtag = malloc( strlen(COL_DATA_TAG)+10);
661 for ( i = 2; i < argc; i++){
662 if (strcmp("--enumds", argv[i]) == 0)
666 if(rrd_xport(argc-1, &argv[1], &xxsize,&start,&end,&step,&col_cnt,&legend_v,&data) != -1) {
667 row_cnt = (end-start)/step;
669 printf("<?xml version=\"1.0\" encoding=\"%s\"?>\n\n", XML_ENCODING);
670 printf("<%s>\n", ROOT_TAG);
671 printf(" <%s>\n", META_TAG);
672 printf(" <%s>%lu</%s>\n", META_START_TAG, start+step, META_START_TAG);
673 printf(" <%s>%lu</%s>\n", META_STEP_TAG, step, META_STEP_TAG);
674 printf(" <%s>%lu</%s>\n", META_END_TAG, end, META_END_TAG);
675 printf(" <%s>%lu</%s>\n", META_ROWS_TAG, row_cnt, META_ROWS_TAG);
676 printf(" <%s>%lu</%s>\n", META_COLS_TAG, col_cnt, META_COLS_TAG);
677 printf(" <%s>\n", LEGEND_TAG);
678 for (j = 0; j < col_cnt; j++) {
681 printf(" <%s>%s</%s>\n", LEGEND_ENTRY_TAG, entry, LEGEND_ENTRY_TAG);
685 printf(" </%s>\n", LEGEND_TAG);
686 printf(" </%s>\n", META_TAG);
687 printf(" <%s>\n", DATA_TAG);
688 for (ti = start+step; ti <= end; ti += step) {
689 printf (" <%s>", DATA_ROW_TAG);
690 printf ("<%s>%lu</%s>", COL_TIME_TAG, ti, COL_TIME_TAG);
691 for (j = 0; j < col_cnt; j++) {
692 rrd_value_t newval = DNAN;
694 snprintf(vtag,15,"%s%lu", COL_DATA_TAG, j);
696 snprintf(vtag,15,"%s",COL_DATA_TAG);
700 printf("<%s>NaN</%s>", vtag,vtag);
702 printf("<%s>%0.10e</%s>", vtag, newval, vtag);
706 printf("</%s>\n", DATA_ROW_TAG);
709 printf(" </%s>\n", DATA_TAG);
710 printf("</%s>\n", ROOT_TAG);
714 else if (strcmp("graph", argv[1]) == 0) {
716 #ifdef notused /*XXX*/
717 const char *imgfile = argv[2]; /* rrd_graph changes argv pointer */
722 int tostdout = (strcmp(argv[2],"-") == 0);
724 for (i=2;i<argc;i++){
725 if (strcmp(argv[i],"--imginfo") == 0 || strcmp(argv[i],"-f") == 0){
730 if( rrd_graph(argc-1, &argv[1], &calcpr, &xsize, &ysize, NULL, &ymin, &ymax) != -1 ) {
731 if (!tostdout && !imginfo)
732 printf ("%dx%d\n",xsize,ysize);
734 for(i=0;calcpr[i];i++){
736 printf("%s\n",calcpr[i]);
743 } else if (strcmp("tune", argv[1]) == 0)
744 rrd_tune(argc-1, &argv[1]);
746 rrd_set_error("unknown function '%s'",argv[1]);
748 if (rrd_test_error()) {
749 fprintf(out, "ERROR: %s\n",rrd_get_error());
756 int CountArgs(char *aLine)
761 while (aLine[i] == ' ') i++;
762 while (aLine[i] != 0){
763 if((aLine[i]== ' ') && inarg){
766 if((aLine[i]!= ' ') && ! inarg){
776 * CreateArgs - take a string (aLine) and tokenize
778 int CreateArgs(char *pName, char *aLine, int argc, char **argv)
787 /* remove trailing space and newlines */
788 while (len && aLine[len] <= ' ') {
789 aLine[len] = 0 ; len--;
791 /* sikp leading blanks */
792 while (*aLine && *aLine <= ' ') aLine++;
819 pargv[argc++] = putP;
827 pargv[argc++] = putP;