1 /*****************************************************************************
2 * RRDtool 1.2.11 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-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);
334 if ((argc == 3) && strcmp("",argv[2])){
339 fprintf(stderr,"ERROR: can't change root to '%s' errno=%d\n",
346 fprintf(stderr,"ERROR: change root is not supported by your OS "
347 "or at least by this copy of rrdtool\n");
354 if (strcmp(firstdir,"")){
357 fprintf(stderr,"ERROR: %s\n",rrd_strerror(errno));
362 while (fgets(aLine, sizeof(aLine)-1, stdin)){
363 if ((argc = CountArgs(aLine)) == 0) {
364 fprintf(stderr,"ERROR: not enough arguments\n");
366 if ((myargv = (char **) malloc((argc+1) *
367 sizeof(char *))) == NULL) {
371 if ((argc=CreateArgs(argv[0], aLine, argc, myargv)) < 0) {
372 printf("ERROR: creating arguments\n");
374 int ret = HandleInputLine(argc, myargv, stdout);
380 getrusage(RUSAGE_SELF,&myusage);
381 gettimeofday(¤ttime,&tz);
382 printf("OK u:%1.2f s:%1.2f r:%1.2f\n",
383 (double)myusage.ru_utime.tv_sec+
384 (double)myusage.ru_utime.tv_usec/1000000.0,
385 (double)myusage.ru_stime.tv_sec+
386 (double)myusage.ru_stime.tv_usec/1000000.0,
387 (double)(currenttime.tv_sec-starttime.tv_sec)
388 +(double)(currenttime.tv_usec-starttime.tv_usec)
396 fflush(stdout); /* this is important for pipes to work */
404 else if (argc == 3 && !strcmp(argv[1],"help"))
410 exit(HandleInputLine(argc, argv, stderr));
415 /* HandleInputLine is NOT thread safe - due to readdir issues,
416 resolving them portably is not really simple. */
417 int HandleInputLine(int argc, char **argv, FILE* out)
419 #if defined(HAVE_OPENDIR) && defined (HAVE_READDIR)
420 DIR *curdir; /* to read current dir with ls */
423 #if defined(HAVE_SYS_STAT_H)
428 if (argc>1 && strcmp("quit", argv[1]) == 0){
430 printf("ERROR: invalid parameter count for quit\n");
435 #if defined(HAVE_OPENDIR) && defined(HAVE_READDIR) && defined(HAVE_CHDIR)
436 if (argc>1 && strcmp("cd", argv[1]) == 0){
438 printf("ERROR: invalid parameter count for cd\n");
441 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
442 if (getuid()==0 && ! ChangeRoot){
443 printf("ERROR: chdir security problem - rrdtool is running as "
444 "root an no chroot!\n");
450 printf("ERROR: %s\n",rrd_strerror(errno));
455 if (argc>1 && strcmp("mkdir", argv[1]) == 0){
457 printf("ERROR: invalid parameter count for mkdir\n");
460 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
461 if (getuid()==0 && ! ChangeRoot){
462 printf("ERROR: mkdir security problem - rrdtool is running as "
463 "root an no chroot!\n");
469 printf("ERROR: %s\n",rrd_strerror(errno));
474 if (argc>1 && strcmp("ls", argv[1]) == 0){
476 printf("ERROR: invalid parameter count for ls\n");
479 if ((curdir=opendir("."))!=NULL){
480 while((dent=readdir(curdir))!=NULL){
481 if (!stat(dent->d_name,&st)){
482 if (S_ISDIR(st.st_mode)){
483 printf("d %s\n",dent->d_name);
485 if (strlen(dent->d_name)>4 && S_ISREG(st.st_mode)){
486 if (!strcmp(dent->d_name+NAMLEN(dent)-4,".rrd") ||
487 !strcmp(dent->d_name+NAMLEN(dent)-4,".RRD")){
488 printf("- %s\n",dent->d_name);
495 printf("ERROR: %s\n",rrd_strerror(errno));
500 #endif /* opendir and readdir */
504 || strcmp("help", argv[1]) == 0
505 || strcmp("--help", argv[1]) == 0
506 || strcmp("-help", argv[1]) == 0
507 || strcmp("-?", argv[1]) == 0
508 || strcmp("-h", argv[1]) == 0 ) {
513 if (strcmp("create", argv[1]) == 0)
514 rrd_create(argc-1, &argv[1]);
515 else if (strcmp("dump", argv[1]) == 0)
516 rrd_dump(argc-1, &argv[1]);
517 else if (strcmp("info", argv[1]) == 0
518 || strcmp("updatev", argv[1]) == 0){
520 if (strcmp("info",argv[1]) == 0)
521 data=rrd_info(argc-1, &argv[1]);
523 data=rrd_update_v(argc-1, &argv[1]);
526 printf ("%s = ", data->key);
529 switch (data->type) {
531 if (isnan (data->value.u_val))
534 printf ("%0.10e", data->value.u_val);
537 printf ("%lu", data->value.u_cnt);
540 printf ("%d", data->value.u_int);
543 printf ("\"%s\"", data->value.u_str);
544 free(data->value.u_str);
554 else if (strcmp("--version", argv[1]) == 0 ||
555 strcmp("version", argv[1]) == 0 ||
556 strcmp("v", argv[1]) == 0 ||
557 strcmp("-v", argv[1]) == 0 ||
558 strcmp("-version", argv[1]) == 0 )
559 printf("RRDtool " PACKAGE_VERSION " Copyright by Tobi Oetiker, 1997-2005 (%f)\n",
561 else if (strcmp("restore", argv[1]) == 0)
562 rrd_restore(argc-1, &argv[1]);
563 else if (strcmp("resize", argv[1]) == 0)
564 rrd_resize(argc-1, &argv[1]);
565 else if (strcmp("last", argv[1]) == 0)
566 printf("%ld\n",rrd_last(argc-1, &argv[1]));
567 else if (strcmp("first", argv[1]) == 0)
568 printf("%ld\n",rrd_first(argc-1, &argv[1]));
569 else if (strcmp("update", argv[1]) == 0)
570 rrd_update(argc-1, &argv[1]);
571 else if (strcmp("fetch", argv[1]) == 0) {
572 time_t start,end, ti;
573 unsigned long step, ds_cnt,i,ii;
574 rrd_value_t *data,*datai;
576 if (rrd_fetch(argc-1, &argv[1],&start,&end,&step,&ds_cnt,&ds_namv,&data) != -1) {
579 for (i = 0; i<ds_cnt;i++)
580 printf("%20s",ds_namv[i]);
582 for (ti = start+step; ti <= end; ti += step){
583 printf("%10lu:", ti);
584 for (ii = 0; ii < ds_cnt; ii++)
585 printf(" %0.10e", *(datai++));
588 for (i=0;i<ds_cnt;i++)
593 } else if (strcmp("xport", argv[1]) == 0) {
595 unsigned long int j = 0;
596 time_t start,end, ti;
597 unsigned long step, col_cnt,row_cnt;
598 rrd_value_t *data,*ptr;
600 if(rrd_xport(argc-1, &argv[1], &xxsize,&start,&end,&step,&col_cnt,&legend_v,&data) != -1) {
601 row_cnt = (end-start)/step;
603 printf("<?xml version=\"1.0\" encoding=\"%s\"?>\n\n", XML_ENCODING);
604 printf("<%s>\n", ROOT_TAG);
605 printf(" <%s>\n", META_TAG);
606 printf(" <%s>%lu</%s>\n", META_START_TAG, start+step, META_START_TAG);
607 printf(" <%s>%lu</%s>\n", META_STEP_TAG, step, META_STEP_TAG);
608 printf(" <%s>%lu</%s>\n", META_END_TAG, end, META_END_TAG);
609 printf(" <%s>%lu</%s>\n", META_ROWS_TAG, row_cnt, META_ROWS_TAG);
610 printf(" <%s>%lu</%s>\n", META_COLS_TAG, col_cnt, META_COLS_TAG);
611 printf(" <%s>\n", LEGEND_TAG);
612 for (j = 0; j < col_cnt; j++) {
615 printf(" <%s>%s</%s>\n", LEGEND_ENTRY_TAG, entry, LEGEND_ENTRY_TAG);
619 printf(" </%s>\n", LEGEND_TAG);
620 printf(" </%s>\n", META_TAG);
621 printf(" <%s>\n", DATA_TAG);
622 for (ti = start+step; ti <= end; ti += step) {
623 printf (" <%s>", DATA_ROW_TAG);
624 printf ("<%s>%lu</%s>", COL_TIME_TAG, ti, COL_TIME_TAG);
625 for (j = 0; j < col_cnt; j++) {
626 rrd_value_t newval = DNAN;
629 printf("<%s>NaN</%s>", COL_DATA_TAG, COL_DATA_TAG);
631 printf("<%s>%0.10e</%s>", COL_DATA_TAG, newval, COL_DATA_TAG);
635 printf("</%s>\n", DATA_ROW_TAG);
638 printf(" </%s>\n", DATA_TAG);
639 printf("</%s>\n", ROOT_TAG);
642 else if (strcmp("graph", argv[1]) == 0) {
644 #ifdef notused /*XXX*/
645 const char *imgfile = argv[2]; /* rrd_graph changes argv pointer */
650 int tostdout = (strcmp(argv[2],"-") == 0);
651 if( rrd_graph(argc-1, &argv[1], &calcpr, &xsize, &ysize, NULL, &ymin, &ymax) != -1 ) {
653 printf ("%dx%d\n",xsize,ysize);
655 for(i=0;calcpr[i];i++){
657 printf("%s\n",calcpr[i]);
664 } else if (strcmp("tune", argv[1]) == 0)
665 rrd_tune(argc-1, &argv[1]);
667 rrd_set_error("unknown function '%s'",argv[1]);
669 if (rrd_test_error()) {
670 fprintf(out, "ERROR: %s\n",rrd_get_error());
677 int CountArgs(char *aLine)
682 while (aLine[i] == ' ') i++;
683 while (aLine[i] != 0){
684 if((aLine[i]== ' ') && inarg){
687 if((aLine[i]!= ' ') && ! inarg){
697 * CreateArgs - take a string (aLine) and tokenize
699 int CreateArgs(char *pName, char *aLine, int argc, char **argv)
708 /* remove trailing space and newlines */
709 while (len && aLine[len] <= ' ') {
710 aLine[len] = 0 ; len--;
712 /* sikp leading blanks */
713 while (*aLine && *aLine <= ' ') aLine++;
740 pargv[argc++] = putP;
748 pargv[argc++] = putP;