1 /*****************************************************************************
2 * RRDtool 1.2rc6 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.2rc6 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[--units-exponent value]\n"
112 "\t\t[--step seconds]\n"
113 "\t\t[-f|--imginfo printfstr]\n"
114 "\t\t[-a|--imgformat PNG]\n"
115 "\t\t[-c|--color COLORTAG#rrggbb[aa]] [-t|--title string]\n";
117 "\t\t[DEF:vname=rrd:ds-name:CF]\n"
118 "\t\t[CDEF:vname=rpn-expression]\n"
119 "\t\t[VDEF:vdefname=rpn-expression]\n"
120 "\t\t[PRINT:vname:CF:format]\n"
121 "\t\t[GPRINT:vname:CF:format]\n"
122 "\t\t[PRINT:vdefname:format]\n"
123 "\t\t[GPRINT:vdefname:format]\n"
124 "\t\t[HRULE:value#rrggbb[aa][:legend]]\n"
125 "\t\t[VRULE:value#rrggbb[aa][:legend]]\n"
126 "\t\t[LINE{1|2|3}:vname[#rrggbb[aa][:legend]][:STACK]]\n"
127 "\t\t[AREA:vname[#rrggbb[aa][:legend]][:STACK]]\n"
128 "\t\t[STACK:vname[#rrggbb[aa][:legend]]]\n\n";
131 " * tune - Modify some basic properties of an RRD\n\n"
132 "\trrdtool tune filename\n"
133 "\t\t[--heartbeat|-h ds-name:heartbeat]\n"
134 "\t\t[--data-source-type|-d ds-name:DST]\n"
135 "\t\t[--data-source-rename|-r old-name:new-name]\n"
136 "\t\t[--minimum|-i ds-name:min] [--maximum|-a ds-name:max]\n"
137 "\t\t[--deltapos scale-value] [--deltaneg scale-value]\n"
138 "\t\t[--failure-threshold integer]\n"
139 "\t\t[--window-length integer]\n"
140 "\t\t[--alpha adaptation-parameter]\n";
142 " * tune - Modify some basic properties of an RRD\n\n"
143 "\t\t[--beta adaptation-parameter]\n"
144 "\t\t[--gamma adaptation-parameter]\n"
145 "\t\t[--gamma-deviation adaptation-parameter]\n"
146 "\t\t[--aberrant-reset ds-name]\n\n";
149 " * resize - alter the length of one of the RRAs in an RRD\n\n"
150 "\trrdtool resize filename rranum GROW|SHRINK rows\n\n";
153 "* xport - generate XML dump from one or several RRD\n\n"
154 "\trrdtool xport [-s|--start seconds] [-e|--end seconds]\n"
155 "\t\t[-m|--maxrows rows]\n"
156 "\t\t[--step seconds]\n"
157 "\t\t[DEF:vname=rrd:ds-name:CF]\n"
158 "\t\t[CDEF:vname=rpn-expression]\n"
159 "\t\t[XPORT:vname:legend]\n\n";
162 " * quit - closing a session in remote mode\n\n"
163 "\trrdtool quit\n\n";
166 " * ls - lists all *.rrd files in current directory\n\n"
170 " * cd - changes the current directory\n\n"
171 "\trrdtool cd new directory\n\n";
174 " * mkdir - creates a new directory\n\n"
175 "\trrdtool mkdir newdirectoryname\n\n";
178 "RRDtool is distributed under the Terms of the GNU General\n"
179 "Public License Version 2. (www.gnu.org/copyleft/gpl.html)\n\n"
181 "For more information read the RRD manpages\n\n";
183 enum { C_NONE, C_CREATE, C_DUMP, C_INFO, C_RESTORE, C_LAST, C_FIRST,
184 C_UPDATE, C_FETCH, C_GRAPH, C_TUNE, C_RESIZE, C_XPORT,
185 C_QUIT, C_LS, C_CD, C_MKDIR, C_UPDATEV };
187 int help_cmd = C_NONE;
191 if (!strcmp(cmd,"create"))
193 else if (!strcmp(cmd,"dump"))
195 else if (!strcmp(cmd,"info"))
197 else if (!strcmp(cmd,"restore"))
198 help_cmd = C_RESTORE;
199 else if (!strcmp(cmd,"last"))
201 else if (!strcmp(cmd,"first"))
203 else if (!strcmp(cmd,"update"))
205 else if (!strcmp(cmd,"updatev"))
206 help_cmd = C_UPDATEV;
207 else if (!strcmp(cmd,"fetch"))
209 else if (!strcmp(cmd,"graph"))
211 else if (!strcmp(cmd,"tune"))
213 else if (!strcmp(cmd,"resize"))
215 else if (!strcmp(cmd,"xport"))
217 else if (!strcmp(cmd,"quit"))
219 else if (!strcmp(cmd,"ls"))
221 else if (!strcmp(cmd,"cd"))
223 else if (!strcmp(cmd,"mkdir"))
226 fputs(help_main, stdout);
230 fputs(help_list, stdout);
232 fputs(help_listremote, stdout);
236 fputs(help_create, stdout);
239 fputs(help_dump, stdout);
242 fputs(help_info, stdout);
245 fputs(help_restore, stdout);
248 fputs(help_last, stdout);
251 fputs(help_first, stdout);
254 fputs(help_update, stdout);
257 fputs(help_updatev, stdout);
260 fputs(help_fetch, stdout);
263 fputs(help_graph1, stdout);
264 fputs(help_graph2, stdout);
265 fputs(help_graph3, stdout);
268 fputs(help_tune1, stdout);
269 fputs(help_tune2, stdout);
272 fputs(help_resize, stdout);
275 fputs(help_xport, stdout);
278 fputs(help_quit, stdout);
281 fputs(help_ls, stdout);
284 fputs(help_cd, stdout);
287 fputs(help_mkdir, stdout);
290 fputs(help_lic, stdout);
294 int main(int argc, char *argv[])
297 char aLine[MAX_LENGTH];
301 #ifdef MUST_DISABLE_SIGFPE
302 signal(SIGFPE,SIG_IGN);
304 #ifdef MUST_DISABLE_FPMASK
313 if (((argc == 2)||(argc == 3)) && !strcmp("-",argv[1]))
316 struct rusage myusage;
317 struct timeval starttime;
318 struct timeval currenttime;
321 tz.tz_minuteswest =0;
323 gettimeofday(&starttime,&tz);
327 if ((argc == 3) && strcmp("",argv[2])){
331 fprintf(stderr,"ERROR: can't change root to '%s' errno=%d\n",
342 if (strcmp(firstdir,"")){
345 fprintf(stderr,"ERROR: %s\n",rrd_strerror(errno));
350 fprintf(stderr,"ERROR: change root is not supported by your OS "
351 "or at least by this copy of rrdtool\n");
355 while (fgets(aLine, sizeof(aLine)-1, stdin)){
356 if ((argc = CountArgs(aLine)) == 0) {
357 fprintf(stderr,"ERROR: not enough arguments\n");
359 if ((myargv = (char **) malloc((argc+1) *
360 sizeof(char *))) == NULL) {
364 if ((argc=CreateArgs(argv[0], aLine, argc, myargv)) < 0) {
365 fprintf(stderr, "ERROR: creating arguments\n");
369 if (HandleInputLine(argc, myargv, stdout))
374 getrusage(RUSAGE_SELF,&myusage);
375 gettimeofday(¤ttime,&tz);
376 printf("OK u:%1.2f s:%1.2f r:%1.2f\n",
377 (double)myusage.ru_utime.tv_sec+
378 (double)myusage.ru_utime.tv_usec/1000000.0,
379 (double)myusage.ru_stime.tv_sec+
380 (double)myusage.ru_stime.tv_usec/1000000.0,
381 (double)(currenttime.tv_sec-starttime.tv_sec)
382 +(double)(currenttime.tv_usec-starttime.tv_usec)
387 fflush(stdout); /* this is important for pipes to work */
395 else if (argc == 3 && !strcmp(argv[1],"help"))
401 exit(HandleInputLine(argc, argv, stderr));
406 /* HandleInputLine is NOT thread safe - due to readdir issues,
407 resolving them portably is not really simple. */
408 int HandleInputLine(int argc, char **argv, FILE* out)
410 #if defined(HAVE_OPENDIR) && defined (HAVE_READDIR)
411 DIR *curdir; /* to read current dir with ls */
414 #if defined(HAVE_SYS_STAT_H)
417 optind=0; /* reset gnu getopt */
418 opterr=0; /* no error messages */
421 if (argc>1 && strcmp("quit", argv[1]) == 0){
423 printf("ERROR: invalid parameter count for quit\n");
428 #if defined(HAVE_OPENDIR) && defined(HAVE_READDIR) && defined(HAVE_CHDIR)
429 if (argc>1 && strcmp("cd", argv[1]) == 0){
431 printf("ERROR: invalid parameter count for cd\n");
434 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
435 if (getuid()==0 && ! ChangeRoot){
436 printf("ERROR: chdir security problem - rrdtool is running as "
437 "root an no chroot!\n");
443 printf("ERROR: %s\n",rrd_strerror(errno));
447 if (argc>1 && strcmp("mkdir", argv[1]) == 0){
449 printf("ERROR: invalid parameter count for mkdir\n");
452 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
453 if (getuid()==0 && ! ChangeRoot){
454 printf("ERROR: mkdir security problem - rrdtool is running as "
455 "root an no chroot!\n");
461 printf("ERROR: %s\n",rrd_strerror(errno));
465 if (argc>1 && strcmp("ls", argv[1]) == 0){
467 printf("ERROR: invalid parameter count for ls\n");
470 if ((curdir=opendir("."))!=NULL){
471 while((dent=readdir(curdir))!=NULL){
472 if (!stat(dent->d_name,&st)){
473 if (S_ISDIR(st.st_mode)){
474 printf("d %s\n",dent->d_name);
476 if (strlen(dent->d_name)>4 && S_ISREG(st.st_mode)){
477 if (!strcmp(dent->d_name+NAMLEN(dent)-4,".rrd") ||
478 !strcmp(dent->d_name+NAMLEN(dent)-4,".RRD")){
479 printf("- %s\n",dent->d_name);
486 printf("ERROR: %s\n",rrd_strerror(errno));
491 #endif /* opendir and readdir */
495 || strcmp("help", argv[1]) == 0
496 || strcmp("--help", argv[1]) == 0
497 || strcmp("-help", argv[1]) == 0
498 || strcmp("-?", argv[1]) == 0
499 || strcmp("-h", argv[1]) == 0 ) {
504 if (strcmp("create", argv[1]) == 0)
505 rrd_create(argc-1, &argv[1]);
506 else if (strcmp("dump", argv[1]) == 0)
507 rrd_dump(argc-1, &argv[1]);
508 else if (strcmp("info", argv[1]) == 0
509 || strcmp("updatev", argv[1]) == 0){
511 if (strcmp("info",argv[1]) == 0)
512 data=rrd_info(argc-1, &argv[1]);
514 data=rrd_update_v(argc-1, &argv[1]);
517 printf ("%s = ", data->key);
520 switch (data->type) {
522 if (isnan (data->value.u_val))
525 printf ("%0.10e", data->value.u_val);
528 printf ("%lu", data->value.u_cnt);
531 printf ("%d", data->value.u_int);
534 printf ("\"%s\"", data->value.u_str);
535 free(data->value.u_str);
545 else if (strcmp("--version", argv[1]) == 0 ||
546 strcmp("version", argv[1]) == 0 ||
547 strcmp("v", argv[1]) == 0 ||
548 strcmp("-v", argv[1]) == 0 ||
549 strcmp("-version", argv[1]) == 0 )
550 printf("RRDtool 1.2rc6 Copyright by Tobi Oetiker, 1997-2005\n");
551 else if (strcmp("restore", argv[1]) == 0)
552 rrd_restore(argc-1, &argv[1]);
553 else if (strcmp("resize", argv[1]) == 0)
554 rrd_resize(argc-1, &argv[1]);
555 else if (strcmp("last", argv[1]) == 0)
556 printf("%ld\n",rrd_last(argc-1, &argv[1]));
557 else if (strcmp("first", argv[1]) == 0)
558 printf("%ld\n",rrd_first(argc-1, &argv[1]));
559 else if (strcmp("update", argv[1]) == 0)
560 rrd_update(argc-1, &argv[1]);
561 else if (strcmp("fetch", argv[1]) == 0) {
562 time_t start,end, ti;
563 unsigned long step, ds_cnt,i,ii;
564 rrd_value_t *data,*datai;
566 if (rrd_fetch(argc-1, &argv[1],&start,&end,&step,&ds_cnt,&ds_namv,&data) != -1) {
569 for (i = 0; i<ds_cnt;i++)
570 printf("%20s",ds_namv[i]);
572 for (ti = start+step; ti <= end; ti += step){
573 printf("%10lu:", ti);
574 for (ii = 0; ii < ds_cnt; ii++)
575 printf(" %0.10e", *(datai++));
578 for (i=0;i<ds_cnt;i++)
583 } else if (strcmp("xport", argv[1]) == 0) {
585 unsigned long int j = 0;
586 time_t start,end, ti;
587 unsigned long step, col_cnt,row_cnt;
588 rrd_value_t *data,*ptr;
590 if(rrd_xport(argc-1, &argv[1], &xxsize,&start,&end,&step,&col_cnt,&legend_v,&data) != -1) {
591 row_cnt = (end-start)/step;
593 printf("<?xml version=\"1.0\" encoding=\"%s\"?>\n\n", XML_ENCODING);
594 printf("<%s>\n", ROOT_TAG);
595 printf(" <%s>\n", META_TAG);
596 printf(" <%s>%lu</%s>\n", META_START_TAG, start+step, META_START_TAG);
597 printf(" <%s>%lu</%s>\n", META_STEP_TAG, step, META_STEP_TAG);
598 printf(" <%s>%lu</%s>\n", META_END_TAG, end, META_END_TAG);
599 printf(" <%s>%lu</%s>\n", META_ROWS_TAG, row_cnt, META_ROWS_TAG);
600 printf(" <%s>%lu</%s>\n", META_COLS_TAG, col_cnt, META_COLS_TAG);
601 printf(" <%s>\n", LEGEND_TAG);
602 for (j = 0; j < col_cnt; j++) {
605 printf(" <%s>%s</%s>\n", LEGEND_ENTRY_TAG, entry, LEGEND_ENTRY_TAG);
609 printf(" </%s>\n", LEGEND_TAG);
610 printf(" </%s>\n", META_TAG);
611 printf(" <%s>\n", DATA_TAG);
612 for (ti = start+step; ti <= end; ti += step) {
613 printf (" <%s>", DATA_ROW_TAG);
614 printf ("<%s>%lu</%s>", COL_TIME_TAG, ti, COL_TIME_TAG);
615 for (j = 0; j < col_cnt; j++) {
616 rrd_value_t newval = DNAN;
619 printf("<%s>NaN</%s>", COL_DATA_TAG, COL_DATA_TAG);
621 printf("<%s>%0.10e</%s>", COL_DATA_TAG, newval, COL_DATA_TAG);
625 printf("</%s>\n", DATA_ROW_TAG);
628 printf(" </%s>\n", DATA_TAG);
629 printf("</%s>\n", ROOT_TAG);
632 else if (strcmp("graph", argv[1]) == 0) {
634 #ifdef notused /*XXX*/
635 const char *imgfile = argv[2]; /* rrd_graph changes argv pointer */
640 int tostdout = (strcmp(argv[2],"-") == 0);
641 if( rrd_graph(argc-1, &argv[1], &calcpr, &xsize, &ysize, NULL, &ymin, &ymax) != -1 ) {
643 printf ("%dx%d\n",xsize,ysize);
645 for(i=0;calcpr[i];i++){
647 printf("%s\n",calcpr[i]);
654 } else if (strcmp("tune", argv[1]) == 0)
655 rrd_tune(argc-1, &argv[1]);
657 rrd_set_error("unknown function '%s'",argv[1]);
659 if (rrd_test_error()) {
660 fprintf(out, "ERROR: %s\n",rrd_get_error());
667 int CountArgs(char *aLine)
672 while (aLine[i] == ' ') i++;
673 while (aLine[i] != 0){
674 if((aLine[i]== ' ') && inarg){
677 if((aLine[i]!= ' ') && ! inarg){
687 * CreateArgs - take a string (aLine) and tokenize
689 int CreateArgs(char *pName, char *aLine, int argc, char **argv)
698 /* remove trailing space and newlines */
699 while (len && aLine[len] <= ' ') {
700 aLine[len] = 0 ; len--;
702 /* sikp leading blanks */
703 while (*aLine && *aLine <= ' ') aLine++;
730 pargv[argc++] = putP;
738 pargv[argc++] = putP;