1 /*****************************************************************************
2 * RRDtool 1.2.6 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 1.2.6 Copyright 1997-2005 by Tobias Oetiker <tobi@oetiker.ch>\n"
26 #if defined(WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
27 " Compiled " __DATE__ " " __TIME__ "\n\n"
29 " Compiled " MAKE_TIMESTAMP "\n\n"
31 "Usage: rrdtool [options] command command_options\n\n";
34 "Valid commands: create, update, updatev, graph, dump, restore,\n"
35 "\t\tlast, first, info, fetch, tune, resize, xport\n\n";
37 char help_listremote[] =
38 "Valid remote commands: quit, ls, cd, mkdir\n\n";
42 "* create - create a new RRD\n\n"
43 "\trrdtool create filename [--start|-b start time]\n"
44 "\t\t[--step|-s step]\n"
45 "\t\t[DS:ds-name:DST:dst arguments]\n"
46 "\t\t[RRA:CF:cf arguments]\n\n";
49 "* dump - dump an RRD to XML\n\n"
50 "\trrdtool dump filename.rrd >filename.xml\n\n";
53 "* info - returns the configuration and status of the RRD\n\n"
54 "\trrdtool info filename.rrd\n\n";
57 "* restore - restore an RRD file from its XML form\n\n"
58 "\trrdtool restore [--range-check|-r] [--force-overwrite|-f] filename.xml filename.rrd\n\n";
61 "* last - show last update time for RRD\n\n"
62 "\trrdtool last filename.rrd\n\n";
65 "* first - show first update time for RRA within an RRD\n\n"
66 "\trrdtool first filename.rrd [--rraindex number]\n\n";
69 "* update - update an RRD\n\n"
70 "\trrdtool update filename\n"
71 "\t\t--template|-t ds-name:ds-name:...\n"
72 "\t\ttime|N:value[:value...]\n\n"
73 "\t\tat-time@value[:value...]\n\n"
74 "\t\t[ time:value[:value...] ..]\n\n";
77 "* updatev - a verbose version of update\n"
78 "\treturns information about values, RRAs, and datasources updated\n\n"
79 "\trrdtool updatev filename\n"
80 "\t\t--template|-t ds-name:ds-name:...\n"
81 "\t\ttime|N:value[:value...]\n\n"
82 "\t\tat-time@value[:value...]\n\n"
83 "\t\t[ time:value[:value...] ..]\n\n";
86 "* fetch - fetch data out of an RRD\n\n"
87 "\trrdtool fetch filename.rrd CF\n"
88 "\t\t[-r|--resolution resolution]\n"
89 "\t\t[-s|--start start] [-e|--end end]\n\n";
91 /* break up very large strings (help_graph, help_tune) for ISO C89 compliance*/
94 "* graph - generate a graph from one or several RRD\n\n"
95 "\trrdtool graph filename [-s|--start seconds] [-e|--end seconds]\n"
96 "\t\t[-x|--x-grid x-axis grid and label]\n"
97 "\t\t[-Y|--alt-y-grid]\n"
98 "\t\t[-y|--y-grid y-axis grid and label]\n"
99 "\t\t[-v|--vertical-label string] [-w|--width pixels]\n"
100 "\t\t[-h|--height pixels] [-o|--logarithmic]\n"
101 "\t\t[-u|--upper-limit value] [-z|--lazy]\n"
102 "\t\t[-l|--lower-limit value] [-r|--rigid]\n"
103 "\t\t[-g|--no-legend]\n"
104 "\t\t[-F|--force-rules-legend]\n"
105 "\t\t[-j|--only-graph]\n";
107 "\t\t[-n|--font FONTTAG:size:font]\n"
108 "\t\t[-m|--zoom factor]\n"
109 "\t\t[-A|--alt-autoscale]\n"
110 "\t\t[-M|--alt-autoscale-max]\n"
111 "\t\t[-R|--font-render-mode {normal,light,mono}]\n"
112 "\t\t[-B|--font-smoothing-threshold size]\n"
113 "\t\t[-E|--slope-mode]\n"
114 "\t\t[-N|--no-gridfit]\n"
115 "\t\t[-X|--units-exponent value]\n"
116 "\t\t[-L|--units-length value]\n"
117 "\t\t[-S|--step seconds]\n"
118 "\t\t[-f|--imginfo printfstr]\n"
119 "\t\t[-a|--imgformat PNG]\n"
120 "\t\t[-c|--color COLORTAG#rrggbb[aa]] [-t|--title string]\n"
121 "\t\t[DEF:vname=rrd:ds-name:CF]\n"
122 "\t\t[CDEF:vname=rpn-expression]\n";
124 "\t\t[VDEF:vdefname=rpn-expression]\n"
125 "\t\t[PRINT:vdefname:format]\n"
126 "\t\t[GPRINT:vdefname:format]\n"
127 "\t\t[COMMENT:text]\n"
128 "\t\t[SHIFT:vname:offset]\n"
129 "\t\t[TICK:vname#rrggbb[aa][:[fraction][:legend]]]\n"
130 "\t\t[HRULE:value#rrggbb[aa][:legend]]\n"
131 "\t\t[VRULE:value#rrggbb[aa][:legend]]\n"
132 "\t\t[LINE[width]:vname[#rrggbb[aa][:[legend][:STACK]]]]\n"
133 "\t\t[AREA:vname[#rrggbb[aa][:[legend][:STACK]]]]\n"
134 "\t\t[PRINT:vname:CF:format] (deprecated)\n"
135 "\t\t[GPRINT:vname:CF:format] (deprecated)\n"
136 "\t\t[STACK:vname[#rrggbb[aa][:legend]]] (deprecated)\n\n";
139 " * tune - Modify some basic properties of an RRD\n\n"
140 "\trrdtool tune filename\n"
141 "\t\t[--heartbeat|-h ds-name:heartbeat]\n"
142 "\t\t[--data-source-type|-d ds-name:DST]\n"
143 "\t\t[--data-source-rename|-r old-name:new-name]\n"
144 "\t\t[--minimum|-i ds-name:min] [--maximum|-a ds-name:max]\n"
145 "\t\t[--deltapos scale-value] [--deltaneg scale-value]\n"
146 "\t\t[--failure-threshold integer]\n"
147 "\t\t[--window-length integer]\n"
148 "\t\t[--alpha adaptation-parameter]\n";
150 " * tune - Modify some basic properties of an RRD\n\n"
151 "\t\t[--beta adaptation-parameter]\n"
152 "\t\t[--gamma adaptation-parameter]\n"
153 "\t\t[--gamma-deviation adaptation-parameter]\n"
154 "\t\t[--aberrant-reset ds-name]\n\n";
157 " * resize - alter the length of one of the RRAs in an RRD\n\n"
158 "\trrdtool resize filename rranum GROW|SHRINK rows\n\n";
161 "* xport - generate XML dump from one or several RRD\n\n"
162 "\trrdtool xport [-s|--start seconds] [-e|--end seconds]\n"
163 "\t\t[-m|--maxrows rows]\n"
164 "\t\t[--step seconds]\n"
165 "\t\t[DEF:vname=rrd:ds-name:CF]\n"
166 "\t\t[CDEF:vname=rpn-expression]\n"
167 "\t\t[XPORT:vname:legend]\n\n";
170 " * quit - closing a session in remote mode\n\n"
171 "\trrdtool quit\n\n";
174 " * ls - lists all *.rrd files in current directory\n\n"
178 " * cd - changes the current directory\n\n"
179 "\trrdtool cd new directory\n\n";
182 " * mkdir - creates a new directory\n\n"
183 "\trrdtool mkdir newdirectoryname\n\n";
186 "RRDtool is distributed under the Terms of the GNU General\n"
187 "Public License Version 2. (www.gnu.org/copyleft/gpl.html)\n\n"
189 "For more information read the RRD manpages\n\n";
191 enum { C_NONE, C_CREATE, C_DUMP, C_INFO, C_RESTORE, C_LAST, C_FIRST,
192 C_UPDATE, C_FETCH, C_GRAPH, C_TUNE, C_RESIZE, C_XPORT,
193 C_QUIT, C_LS, C_CD, C_MKDIR, C_UPDATEV };
195 int help_cmd = C_NONE;
199 if (!strcmp(cmd,"create"))
201 else if (!strcmp(cmd,"dump"))
203 else if (!strcmp(cmd,"info"))
205 else if (!strcmp(cmd,"restore"))
206 help_cmd = C_RESTORE;
207 else if (!strcmp(cmd,"last"))
209 else if (!strcmp(cmd,"first"))
211 else if (!strcmp(cmd,"update"))
213 else if (!strcmp(cmd,"updatev"))
214 help_cmd = C_UPDATEV;
215 else if (!strcmp(cmd,"fetch"))
217 else if (!strcmp(cmd,"graph"))
219 else if (!strcmp(cmd,"tune"))
221 else if (!strcmp(cmd,"resize"))
223 else if (!strcmp(cmd,"xport"))
225 else if (!strcmp(cmd,"quit"))
227 else if (!strcmp(cmd,"ls"))
229 else if (!strcmp(cmd,"cd"))
231 else if (!strcmp(cmd,"mkdir"))
234 fputs(help_main, stdout);
238 fputs(help_list, stdout);
240 fputs(help_listremote, stdout);
244 fputs(help_create, stdout);
247 fputs(help_dump, stdout);
250 fputs(help_info, stdout);
253 fputs(help_restore, stdout);
256 fputs(help_last, stdout);
259 fputs(help_first, stdout);
262 fputs(help_update, stdout);
265 fputs(help_updatev, stdout);
268 fputs(help_fetch, stdout);
271 fputs(help_graph1, stdout);
272 fputs(help_graph2, stdout);
273 fputs(help_graph3, stdout);
276 fputs(help_tune1, stdout);
277 fputs(help_tune2, stdout);
280 fputs(help_resize, stdout);
283 fputs(help_xport, stdout);
286 fputs(help_quit, stdout);
289 fputs(help_ls, stdout);
292 fputs(help_cd, stdout);
295 fputs(help_mkdir, stdout);
298 fputs(help_lic, stdout);
302 int main(int argc, char *argv[])
305 char aLine[MAX_LENGTH];
309 #ifdef MUST_DISABLE_SIGFPE
310 signal(SIGFPE,SIG_IGN);
312 #ifdef MUST_DISABLE_FPMASK
321 if (((argc == 2)||(argc == 3)) && !strcmp("-",argv[1]))
324 struct rusage myusage;
325 struct timeval starttime;
326 struct timeval currenttime;
329 tz.tz_minuteswest =0;
331 gettimeofday(&starttime,&tz);
335 if ((argc == 3) && strcmp("",argv[2])){
339 fprintf(stderr,"ERROR: can't change root to '%s' errno=%d\n",
350 if (strcmp(firstdir,"")){
353 fprintf(stderr,"ERROR: %s\n",rrd_strerror(errno));
358 fprintf(stderr,"ERROR: change root is not supported by your OS "
359 "or at least by this copy of rrdtool\n");
363 while (fgets(aLine, sizeof(aLine)-1, stdin)){
364 if ((argc = CountArgs(aLine)) == 0) {
365 fprintf(stderr,"ERROR: not enough arguments\n");
367 if ((myargv = (char **) malloc((argc+1) *
368 sizeof(char *))) == NULL) {
372 if ((argc=CreateArgs(argv[0], aLine, argc, myargv)) < 0) {
373 fprintf(stderr, "ERROR: creating arguments\n");
377 HandleInputLine(argc, myargv, stdout);
381 getrusage(RUSAGE_SELF,&myusage);
382 gettimeofday(¤ttime,&tz);
383 printf("OK u:%1.2f s:%1.2f r:%1.2f\n",
384 (double)myusage.ru_utime.tv_sec+
385 (double)myusage.ru_utime.tv_usec/1000000.0,
386 (double)myusage.ru_stime.tv_sec+
387 (double)myusage.ru_stime.tv_usec/1000000.0,
388 (double)(currenttime.tv_sec-starttime.tv_sec)
389 +(double)(currenttime.tv_usec-starttime.tv_usec)
394 fflush(stdout); /* this is important for pipes to work */
402 else if (argc == 3 && !strcmp(argv[1],"help"))
408 exit(HandleInputLine(argc, argv, stderr));
413 /* HandleInputLine is NOT thread safe - due to readdir issues,
414 resolving them portably is not really simple. */
415 int HandleInputLine(int argc, char **argv, FILE* out)
417 #if defined(HAVE_OPENDIR) && defined (HAVE_READDIR)
418 DIR *curdir; /* to read current dir with ls */
421 #if defined(HAVE_SYS_STAT_H)
426 if (argc>1 && strcmp("quit", argv[1]) == 0){
428 printf("ERROR: invalid parameter count for quit\n");
433 #if defined(HAVE_OPENDIR) && defined(HAVE_READDIR) && defined(HAVE_CHDIR)
434 if (argc>1 && strcmp("cd", argv[1]) == 0){
436 printf("ERROR: invalid parameter count for cd\n");
439 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
440 if (getuid()==0 && ! ChangeRoot){
441 printf("ERROR: chdir security problem - rrdtool is running as "
442 "root an no chroot!\n");
448 printf("ERROR: %s\n",rrd_strerror(errno));
452 if (argc>1 && strcmp("mkdir", argv[1]) == 0){
454 printf("ERROR: invalid parameter count for mkdir\n");
457 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
458 if (getuid()==0 && ! ChangeRoot){
459 printf("ERROR: mkdir security problem - rrdtool is running as "
460 "root an no chroot!\n");
466 printf("ERROR: %s\n",rrd_strerror(errno));
470 if (argc>1 && strcmp("ls", argv[1]) == 0){
472 printf("ERROR: invalid parameter count for ls\n");
475 if ((curdir=opendir("."))!=NULL){
476 while((dent=readdir(curdir))!=NULL){
477 if (!stat(dent->d_name,&st)){
478 if (S_ISDIR(st.st_mode)){
479 printf("d %s\n",dent->d_name);
481 if (strlen(dent->d_name)>4 && S_ISREG(st.st_mode)){
482 if (!strcmp(dent->d_name+NAMLEN(dent)-4,".rrd") ||
483 !strcmp(dent->d_name+NAMLEN(dent)-4,".RRD")){
484 printf("- %s\n",dent->d_name);
491 printf("ERROR: %s\n",rrd_strerror(errno));
496 #endif /* opendir and readdir */
500 || strcmp("help", argv[1]) == 0
501 || strcmp("--help", argv[1]) == 0
502 || strcmp("-help", argv[1]) == 0
503 || strcmp("-?", argv[1]) == 0
504 || strcmp("-h", argv[1]) == 0 ) {
509 if (strcmp("create", argv[1]) == 0)
510 rrd_create(argc-1, &argv[1]);
511 else if (strcmp("dump", argv[1]) == 0)
512 rrd_dump(argc-1, &argv[1]);
513 else if (strcmp("info", argv[1]) == 0
514 || strcmp("updatev", argv[1]) == 0){
516 if (strcmp("info",argv[1]) == 0)
517 data=rrd_info(argc-1, &argv[1]);
519 data=rrd_update_v(argc-1, &argv[1]);
522 printf ("%s = ", data->key);
525 switch (data->type) {
527 if (isnan (data->value.u_val))
530 printf ("%0.10e", data->value.u_val);
533 printf ("%lu", data->value.u_cnt);
536 printf ("%d", data->value.u_int);
539 printf ("\"%s\"", data->value.u_str);
540 free(data->value.u_str);
550 else if (strcmp("--version", argv[1]) == 0 ||
551 strcmp("version", argv[1]) == 0 ||
552 strcmp("v", argv[1]) == 0 ||
553 strcmp("-v", argv[1]) == 0 ||
554 strcmp("-version", argv[1]) == 0 )
555 printf("RRDtool 1.2.6 Copyright by Tobi Oetiker, 1997-2005\n");
556 else if (strcmp("restore", argv[1]) == 0)
557 rrd_restore(argc-1, &argv[1]);
558 else if (strcmp("resize", argv[1]) == 0)
559 rrd_resize(argc-1, &argv[1]);
560 else if (strcmp("last", argv[1]) == 0)
561 printf("%ld\n",rrd_last(argc-1, &argv[1]));
562 else if (strcmp("first", argv[1]) == 0)
563 printf("%ld\n",rrd_first(argc-1, &argv[1]));
564 else if (strcmp("update", argv[1]) == 0)
565 rrd_update(argc-1, &argv[1]);
566 else if (strcmp("fetch", argv[1]) == 0) {
567 time_t start,end, ti;
568 unsigned long step, ds_cnt,i,ii;
569 rrd_value_t *data,*datai;
571 if (rrd_fetch(argc-1, &argv[1],&start,&end,&step,&ds_cnt,&ds_namv,&data) != -1) {
574 for (i = 0; i<ds_cnt;i++)
575 printf("%20s",ds_namv[i]);
577 for (ti = start+step; ti <= end; ti += step){
578 printf("%10lu:", ti);
579 for (ii = 0; ii < ds_cnt; ii++)
580 printf(" %0.10e", *(datai++));
583 for (i=0;i<ds_cnt;i++)
588 } else if (strcmp("xport", argv[1]) == 0) {
590 unsigned long int j = 0;
591 time_t start,end, ti;
592 unsigned long step, col_cnt,row_cnt;
593 rrd_value_t *data,*ptr;
595 if(rrd_xport(argc-1, &argv[1], &xxsize,&start,&end,&step,&col_cnt,&legend_v,&data) != -1) {
596 row_cnt = (end-start)/step;
598 printf("<?xml version=\"1.0\" encoding=\"%s\"?>\n\n", XML_ENCODING);
599 printf("<%s>\n", ROOT_TAG);
600 printf(" <%s>\n", META_TAG);
601 printf(" <%s>%lu</%s>\n", META_START_TAG, start+step, META_START_TAG);
602 printf(" <%s>%lu</%s>\n", META_STEP_TAG, step, META_STEP_TAG);
603 printf(" <%s>%lu</%s>\n", META_END_TAG, end, META_END_TAG);
604 printf(" <%s>%lu</%s>\n", META_ROWS_TAG, row_cnt, META_ROWS_TAG);
605 printf(" <%s>%lu</%s>\n", META_COLS_TAG, col_cnt, META_COLS_TAG);
606 printf(" <%s>\n", LEGEND_TAG);
607 for (j = 0; j < col_cnt; j++) {
610 printf(" <%s>%s</%s>\n", LEGEND_ENTRY_TAG, entry, LEGEND_ENTRY_TAG);
614 printf(" </%s>\n", LEGEND_TAG);
615 printf(" </%s>\n", META_TAG);
616 printf(" <%s>\n", DATA_TAG);
617 for (ti = start+step; ti <= end; ti += step) {
618 printf (" <%s>", DATA_ROW_TAG);
619 printf ("<%s>%lu</%s>", COL_TIME_TAG, ti, COL_TIME_TAG);
620 for (j = 0; j < col_cnt; j++) {
621 rrd_value_t newval = DNAN;
624 printf("<%s>NaN</%s>", COL_DATA_TAG, COL_DATA_TAG);
626 printf("<%s>%0.10e</%s>", COL_DATA_TAG, newval, COL_DATA_TAG);
630 printf("</%s>\n", DATA_ROW_TAG);
633 printf(" </%s>\n", DATA_TAG);
634 printf("</%s>\n", ROOT_TAG);
637 else if (strcmp("graph", argv[1]) == 0) {
639 #ifdef notused /*XXX*/
640 const char *imgfile = argv[2]; /* rrd_graph changes argv pointer */
645 int tostdout = (strcmp(argv[2],"-") == 0);
646 if( rrd_graph(argc-1, &argv[1], &calcpr, &xsize, &ysize, NULL, &ymin, &ymax) != -1 ) {
648 printf ("%dx%d\n",xsize,ysize);
650 for(i=0;calcpr[i];i++){
652 printf("%s\n",calcpr[i]);
659 } else if (strcmp("tune", argv[1]) == 0)
660 rrd_tune(argc-1, &argv[1]);
662 rrd_set_error("unknown function '%s'",argv[1]);
664 if (rrd_test_error()) {
665 fprintf(out, "ERROR: %s\n",rrd_get_error());
672 int CountArgs(char *aLine)
677 while (aLine[i] == ' ') i++;
678 while (aLine[i] != 0){
679 if((aLine[i]== ' ') && inarg){
682 if((aLine[i]!= ' ') && ! inarg){
692 * CreateArgs - take a string (aLine) and tokenize
694 int CreateArgs(char *pName, char *aLine, int argc, char **argv)
703 /* remove trailing space and newlines */
704 while (len && aLine[len] <= ' ') {
705 aLine[len] = 0 ; len--;
707 /* sikp leading blanks */
708 while (*aLine && *aLine <= ' ') aLine++;
735 pargv[argc++] = putP;
743 pargv[argc++] = putP;