1 /*****************************************************************************
2 * RRDtool 1.2rc8 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.2rc8 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[--resolution|-r resolution]\n"
89 "\t\t[--start|-s start] [--end|-e 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[--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";
106 "\t\t[-j|--only-graph]\n"
107 "\t\t[--font FONTTAG:size:font]\n"
108 "\t\t[--zoom factor]\n"
109 "\t\t[--alt-autoscale]\n"
110 "\t\t[--alt-autoscale-max]\n"
111 "\t\t[--no-gridfit]\n"
112 "\t\t[--units-exponent value]\n"
113 "\t\t[--units-length value]\n"
114 "\t\t[--step seconds]\n"
115 "\t\t[-f|--imginfo printfstr]\n"
116 "\t\t[-a|--imgformat PNG]\n"
117 "\t\t[-c|--color COLORTAG#rrggbb[aa]] [-t|--title string]\n";
119 "\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:vname:CF:format]\n"
123 "\t\t[GPRINT:vname:CF:format]\n"
124 "\t\t[PRINT:vdefname:format]\n"
125 "\t\t[GPRINT:vdefname:format]\n"
126 "\t\t[HRULE:value#rrggbb[aa][:legend]]\n"
127 "\t\t[VRULE:value#rrggbb[aa][:legend]]\n"
128 "\t\t[LINE{1|2|3}:vname[#rrggbb[aa][:legend]][:STACK]]\n"
129 "\t\t[AREA:vname[#rrggbb[aa][:legend]][:STACK]]\n"
130 "\t\t[STACK:vname[#rrggbb[aa][:legend]]]\n\n";
133 " * tune - Modify some basic properties of an RRD\n\n"
134 "\trrdtool tune filename\n"
135 "\t\t[--heartbeat|-h ds-name:heartbeat]\n"
136 "\t\t[--data-source-type|-d ds-name:DST]\n"
137 "\t\t[--data-source-rename|-r old-name:new-name]\n"
138 "\t\t[--minimum|-i ds-name:min] [--maximum|-a ds-name:max]\n"
139 "\t\t[--deltapos scale-value] [--deltaneg scale-value]\n"
140 "\t\t[--failure-threshold integer]\n"
141 "\t\t[--window-length integer]\n"
142 "\t\t[--alpha adaptation-parameter]\n";
144 " * tune - Modify some basic properties of an RRD\n\n"
145 "\t\t[--beta adaptation-parameter]\n"
146 "\t\t[--gamma adaptation-parameter]\n"
147 "\t\t[--gamma-deviation adaptation-parameter]\n"
148 "\t\t[--aberrant-reset ds-name]\n\n";
151 " * resize - alter the length of one of the RRAs in an RRD\n\n"
152 "\trrdtool resize filename rranum GROW|SHRINK rows\n\n";
155 "* xport - generate XML dump from one or several RRD\n\n"
156 "\trrdtool xport [-s|--start seconds] [-e|--end seconds]\n"
157 "\t\t[-m|--maxrows rows]\n"
158 "\t\t[--step seconds]\n"
159 "\t\t[DEF:vname=rrd:ds-name:CF]\n"
160 "\t\t[CDEF:vname=rpn-expression]\n"
161 "\t\t[XPORT:vname:legend]\n\n";
164 " * quit - closing a session in remote mode\n\n"
165 "\trrdtool quit\n\n";
168 " * ls - lists all *.rrd files in current directory\n\n"
172 " * cd - changes the current directory\n\n"
173 "\trrdtool cd new directory\n\n";
176 " * mkdir - creates a new directory\n\n"
177 "\trrdtool mkdir newdirectoryname\n\n";
180 "RRDtool is distributed under the Terms of the GNU General\n"
181 "Public License Version 2. (www.gnu.org/copyleft/gpl.html)\n\n"
183 "For more information read the RRD manpages\n\n";
185 enum { C_NONE, C_CREATE, C_DUMP, C_INFO, C_RESTORE, C_LAST, C_FIRST,
186 C_UPDATE, C_FETCH, C_GRAPH, C_TUNE, C_RESIZE, C_XPORT,
187 C_QUIT, C_LS, C_CD, C_MKDIR, C_UPDATEV };
189 int help_cmd = C_NONE;
193 if (!strcmp(cmd,"create"))
195 else if (!strcmp(cmd,"dump"))
197 else if (!strcmp(cmd,"info"))
199 else if (!strcmp(cmd,"restore"))
200 help_cmd = C_RESTORE;
201 else if (!strcmp(cmd,"last"))
203 else if (!strcmp(cmd,"first"))
205 else if (!strcmp(cmd,"update"))
207 else if (!strcmp(cmd,"updatev"))
208 help_cmd = C_UPDATEV;
209 else if (!strcmp(cmd,"fetch"))
211 else if (!strcmp(cmd,"graph"))
213 else if (!strcmp(cmd,"tune"))
215 else if (!strcmp(cmd,"resize"))
217 else if (!strcmp(cmd,"xport"))
219 else if (!strcmp(cmd,"quit"))
221 else if (!strcmp(cmd,"ls"))
223 else if (!strcmp(cmd,"cd"))
225 else if (!strcmp(cmd,"mkdir"))
228 fputs(help_main, stdout);
232 fputs(help_list, stdout);
234 fputs(help_listremote, stdout);
238 fputs(help_create, stdout);
241 fputs(help_dump, stdout);
244 fputs(help_info, stdout);
247 fputs(help_restore, stdout);
250 fputs(help_last, stdout);
253 fputs(help_first, stdout);
256 fputs(help_update, stdout);
259 fputs(help_updatev, stdout);
262 fputs(help_fetch, stdout);
265 fputs(help_graph1, stdout);
266 fputs(help_graph2, stdout);
267 fputs(help_graph3, stdout);
270 fputs(help_tune1, stdout);
271 fputs(help_tune2, stdout);
274 fputs(help_resize, stdout);
277 fputs(help_xport, stdout);
280 fputs(help_quit, stdout);
283 fputs(help_ls, stdout);
286 fputs(help_cd, stdout);
289 fputs(help_mkdir, stdout);
292 fputs(help_lic, stdout);
296 int main(int argc, char *argv[])
299 char aLine[MAX_LENGTH];
303 #ifdef MUST_DISABLE_SIGFPE
304 signal(SIGFPE,SIG_IGN);
306 #ifdef MUST_DISABLE_FPMASK
315 if (((argc == 2)||(argc == 3)) && !strcmp("-",argv[1]))
318 struct rusage myusage;
319 struct timeval starttime;
320 struct timeval currenttime;
323 tz.tz_minuteswest =0;
325 gettimeofday(&starttime,&tz);
329 if ((argc == 3) && strcmp("",argv[2])){
333 fprintf(stderr,"ERROR: can't change root to '%s' errno=%d\n",
344 if (strcmp(firstdir,"")){
347 fprintf(stderr,"ERROR: %s\n",rrd_strerror(errno));
352 fprintf(stderr,"ERROR: change root is not supported by your OS "
353 "or at least by this copy of rrdtool\n");
357 while (fgets(aLine, sizeof(aLine)-1, stdin)){
358 if ((argc = CountArgs(aLine)) == 0) {
359 fprintf(stderr,"ERROR: not enough arguments\n");
361 if ((myargv = (char **) malloc((argc+1) *
362 sizeof(char *))) == NULL) {
366 if ((argc=CreateArgs(argv[0], aLine, argc, myargv)) < 0) {
367 fprintf(stderr, "ERROR: creating arguments\n");
371 if (HandleInputLine(argc, myargv, stdout))
376 getrusage(RUSAGE_SELF,&myusage);
377 gettimeofday(¤ttime,&tz);
378 printf("OK u:%1.2f s:%1.2f r:%1.2f\n",
379 (double)myusage.ru_utime.tv_sec+
380 (double)myusage.ru_utime.tv_usec/1000000.0,
381 (double)myusage.ru_stime.tv_sec+
382 (double)myusage.ru_stime.tv_usec/1000000.0,
383 (double)(currenttime.tv_sec-starttime.tv_sec)
384 +(double)(currenttime.tv_usec-starttime.tv_usec)
389 fflush(stdout); /* this is important for pipes to work */
397 else if (argc == 3 && !strcmp(argv[1],"help"))
403 exit(HandleInputLine(argc, argv, stderr));
408 /* HandleInputLine is NOT thread safe - due to readdir issues,
409 resolving them portably is not really simple. */
410 int HandleInputLine(int argc, char **argv, FILE* out)
412 #if defined(HAVE_OPENDIR) && defined (HAVE_READDIR)
413 DIR *curdir; /* to read current dir with ls */
416 #if defined(HAVE_SYS_STAT_H)
419 optind=0; /* reset gnu getopt */
420 opterr=0; /* no error messages */
423 if (argc>1 && strcmp("quit", argv[1]) == 0){
425 printf("ERROR: invalid parameter count for quit\n");
430 #if defined(HAVE_OPENDIR) && defined(HAVE_READDIR) && defined(HAVE_CHDIR)
431 if (argc>1 && strcmp("cd", argv[1]) == 0){
433 printf("ERROR: invalid parameter count for cd\n");
436 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
437 if (getuid()==0 && ! ChangeRoot){
438 printf("ERROR: chdir security problem - rrdtool is running as "
439 "root an no chroot!\n");
445 printf("ERROR: %s\n",rrd_strerror(errno));
449 if (argc>1 && strcmp("mkdir", argv[1]) == 0){
451 printf("ERROR: invalid parameter count for mkdir\n");
454 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
455 if (getuid()==0 && ! ChangeRoot){
456 printf("ERROR: mkdir security problem - rrdtool is running as "
457 "root an no chroot!\n");
463 printf("ERROR: %s\n",rrd_strerror(errno));
467 if (argc>1 && strcmp("ls", argv[1]) == 0){
469 printf("ERROR: invalid parameter count for ls\n");
472 if ((curdir=opendir("."))!=NULL){
473 while((dent=readdir(curdir))!=NULL){
474 if (!stat(dent->d_name,&st)){
475 if (S_ISDIR(st.st_mode)){
476 printf("d %s\n",dent->d_name);
478 if (strlen(dent->d_name)>4 && S_ISREG(st.st_mode)){
479 if (!strcmp(dent->d_name+NAMLEN(dent)-4,".rrd") ||
480 !strcmp(dent->d_name+NAMLEN(dent)-4,".RRD")){
481 printf("- %s\n",dent->d_name);
488 printf("ERROR: %s\n",rrd_strerror(errno));
493 #endif /* opendir and readdir */
497 || strcmp("help", argv[1]) == 0
498 || strcmp("--help", argv[1]) == 0
499 || strcmp("-help", argv[1]) == 0
500 || strcmp("-?", argv[1]) == 0
501 || strcmp("-h", argv[1]) == 0 ) {
506 if (strcmp("create", argv[1]) == 0)
507 rrd_create(argc-1, &argv[1]);
508 else if (strcmp("dump", argv[1]) == 0)
509 rrd_dump(argc-1, &argv[1]);
510 else if (strcmp("info", argv[1]) == 0
511 || strcmp("updatev", argv[1]) == 0){
513 if (strcmp("info",argv[1]) == 0)
514 data=rrd_info(argc-1, &argv[1]);
516 data=rrd_update_v(argc-1, &argv[1]);
519 printf ("%s = ", data->key);
522 switch (data->type) {
524 if (isnan (data->value.u_val))
527 printf ("%0.10e", data->value.u_val);
530 printf ("%lu", data->value.u_cnt);
533 printf ("%d", data->value.u_int);
536 printf ("\"%s\"", data->value.u_str);
537 free(data->value.u_str);
547 else if (strcmp("--version", argv[1]) == 0 ||
548 strcmp("version", argv[1]) == 0 ||
549 strcmp("v", argv[1]) == 0 ||
550 strcmp("-v", argv[1]) == 0 ||
551 strcmp("-version", argv[1]) == 0 )
552 printf("RRDtool 1.2rc8 Copyright by Tobi Oetiker, 1997-2005\n");
553 else if (strcmp("restore", argv[1]) == 0)
554 rrd_restore(argc-1, &argv[1]);
555 else if (strcmp("resize", argv[1]) == 0)
556 rrd_resize(argc-1, &argv[1]);
557 else if (strcmp("last", argv[1]) == 0)
558 printf("%ld\n",rrd_last(argc-1, &argv[1]));
559 else if (strcmp("first", argv[1]) == 0)
560 printf("%ld\n",rrd_first(argc-1, &argv[1]));
561 else if (strcmp("update", argv[1]) == 0)
562 rrd_update(argc-1, &argv[1]);
563 else if (strcmp("fetch", argv[1]) == 0) {
564 time_t start,end, ti;
565 unsigned long step, ds_cnt,i,ii;
566 rrd_value_t *data,*datai;
568 if (rrd_fetch(argc-1, &argv[1],&start,&end,&step,&ds_cnt,&ds_namv,&data) != -1) {
571 for (i = 0; i<ds_cnt;i++)
572 printf("%20s",ds_namv[i]);
574 for (ti = start+step; ti <= end; ti += step){
575 printf("%10lu:", ti);
576 for (ii = 0; ii < ds_cnt; ii++)
577 printf(" %0.10e", *(datai++));
580 for (i=0;i<ds_cnt;i++)
585 } else if (strcmp("xport", argv[1]) == 0) {
587 unsigned long int j = 0;
588 time_t start,end, ti;
589 unsigned long step, col_cnt,row_cnt;
590 rrd_value_t *data,*ptr;
592 if(rrd_xport(argc-1, &argv[1], &xxsize,&start,&end,&step,&col_cnt,&legend_v,&data) != -1) {
593 row_cnt = (end-start)/step;
595 printf("<?xml version=\"1.0\" encoding=\"%s\"?>\n\n", XML_ENCODING);
596 printf("<%s>\n", ROOT_TAG);
597 printf(" <%s>\n", META_TAG);
598 printf(" <%s>%lu</%s>\n", META_START_TAG, start+step, META_START_TAG);
599 printf(" <%s>%lu</%s>\n", META_STEP_TAG, step, META_STEP_TAG);
600 printf(" <%s>%lu</%s>\n", META_END_TAG, end, META_END_TAG);
601 printf(" <%s>%lu</%s>\n", META_ROWS_TAG, row_cnt, META_ROWS_TAG);
602 printf(" <%s>%lu</%s>\n", META_COLS_TAG, col_cnt, META_COLS_TAG);
603 printf(" <%s>\n", LEGEND_TAG);
604 for (j = 0; j < col_cnt; j++) {
607 printf(" <%s>%s</%s>\n", LEGEND_ENTRY_TAG, entry, LEGEND_ENTRY_TAG);
611 printf(" </%s>\n", LEGEND_TAG);
612 printf(" </%s>\n", META_TAG);
613 printf(" <%s>\n", DATA_TAG);
614 for (ti = start+step; ti <= end; ti += step) {
615 printf (" <%s>", DATA_ROW_TAG);
616 printf ("<%s>%lu</%s>", COL_TIME_TAG, ti, COL_TIME_TAG);
617 for (j = 0; j < col_cnt; j++) {
618 rrd_value_t newval = DNAN;
621 printf("<%s>NaN</%s>", COL_DATA_TAG, COL_DATA_TAG);
623 printf("<%s>%0.10e</%s>", COL_DATA_TAG, newval, COL_DATA_TAG);
627 printf("</%s>\n", DATA_ROW_TAG);
630 printf(" </%s>\n", DATA_TAG);
631 printf("</%s>\n", ROOT_TAG);
634 else if (strcmp("graph", argv[1]) == 0) {
636 #ifdef notused /*XXX*/
637 const char *imgfile = argv[2]; /* rrd_graph changes argv pointer */
642 int tostdout = (strcmp(argv[2],"-") == 0);
643 if( rrd_graph(argc-1, &argv[1], &calcpr, &xsize, &ysize, NULL, &ymin, &ymax) != -1 ) {
645 printf ("%dx%d\n",xsize,ysize);
647 for(i=0;calcpr[i];i++){
649 printf("%s\n",calcpr[i]);
656 } else if (strcmp("tune", argv[1]) == 0)
657 rrd_tune(argc-1, &argv[1]);
659 rrd_set_error("unknown function '%s'",argv[1]);
661 if (rrd_test_error()) {
662 fprintf(out, "ERROR: %s\n",rrd_get_error());
669 int CountArgs(char *aLine)
674 while (aLine[i] == ' ') i++;
675 while (aLine[i] != 0){
676 if((aLine[i]== ' ') && inarg){
679 if((aLine[i]!= ' ') && ! inarg){
689 * CreateArgs - take a string (aLine) and tokenize
691 int CreateArgs(char *pName, char *aLine, int argc, char **argv)
700 /* remove trailing space and newlines */
701 while (len && aLine[len] <= ' ') {
702 aLine[len] = 0 ; len--;
704 /* sikp leading blanks */
705 while (*aLine && *aLine <= ' ') aLine++;
732 pargv[argc++] = putP;
740 pargv[argc++] = putP;