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 " 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\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[DEF:vname=rrd:ds-name:CF]\n"
118 "\t\t[CDEF:vname=rpn-expression]\n";
120 "\t\t[VDEF:vdefname=rpn-expression]\n"
121 "\t\t[PRINT:vdefname:format]\n"
122 "\t\t[GPRINT:vdefname:format]\n"
123 "\t\t[COMMENT:text]\n"
124 "\t\t[SHIFT:vname:offset]\n"
125 "\t\t[TICK:vname#rrggbb[aa][:[fraction][:legend]]]\n"
126 "\t\t[HRULE:value#rrggbb[aa][:legend]]\n"
127 "\t\t[VRULE:value#rrggbb[aa][:legend]]\n"
128 "\t\t[LINE[width]:vname[#rrggbb[aa][:[legend][:STACK]]]]\n"
129 "\t\t[AREA:vname[#rrggbb[aa][:[legend][:STACK]]]]\n"
130 "\t\t[PRINT:vname:CF:format] (deprecated)\n"
131 "\t\t[GPRINT:vname:CF:format] (deprecated)\n"
132 "\t\t[STACK:vname[#rrggbb[aa][:legend]]] (deprecated)\n\n";
135 " * tune - Modify some basic properties of an RRD\n\n"
136 "\trrdtool tune filename\n"
137 "\t\t[--heartbeat|-h ds-name:heartbeat]\n"
138 "\t\t[--data-source-type|-d ds-name:DST]\n"
139 "\t\t[--data-source-rename|-r old-name:new-name]\n"
140 "\t\t[--minimum|-i ds-name:min] [--maximum|-a ds-name:max]\n"
141 "\t\t[--deltapos scale-value] [--deltaneg scale-value]\n"
142 "\t\t[--failure-threshold integer]\n"
143 "\t\t[--window-length integer]\n"
144 "\t\t[--alpha adaptation-parameter]\n";
146 " * tune - Modify some basic properties of an RRD\n\n"
147 "\t\t[--beta adaptation-parameter]\n"
148 "\t\t[--gamma adaptation-parameter]\n"
149 "\t\t[--gamma-deviation adaptation-parameter]\n"
150 "\t\t[--aberrant-reset ds-name]\n\n";
153 " * resize - alter the length of one of the RRAs in an RRD\n\n"
154 "\trrdtool resize filename rranum GROW|SHRINK rows\n\n";
157 "* xport - generate XML dump from one or several RRD\n\n"
158 "\trrdtool xport [-s|--start seconds] [-e|--end seconds]\n"
159 "\t\t[-m|--maxrows rows]\n"
160 "\t\t[--step seconds]\n"
161 "\t\t[DEF:vname=rrd:ds-name:CF]\n"
162 "\t\t[CDEF:vname=rpn-expression]\n"
163 "\t\t[XPORT:vname:legend]\n\n";
166 " * quit - closing a session in remote mode\n\n"
167 "\trrdtool quit\n\n";
170 " * ls - lists all *.rrd files in current directory\n\n"
174 " * cd - changes the current directory\n\n"
175 "\trrdtool cd new directory\n\n";
178 " * mkdir - creates a new directory\n\n"
179 "\trrdtool mkdir newdirectoryname\n\n";
182 "RRDtool is distributed under the Terms of the GNU General\n"
183 "Public License Version 2. (www.gnu.org/copyleft/gpl.html)\n\n"
185 "For more information read the RRD manpages\n\n";
187 enum { C_NONE, C_CREATE, C_DUMP, C_INFO, C_RESTORE, C_LAST, C_FIRST,
188 C_UPDATE, C_FETCH, C_GRAPH, C_TUNE, C_RESIZE, C_XPORT,
189 C_QUIT, C_LS, C_CD, C_MKDIR, C_UPDATEV };
191 int help_cmd = C_NONE;
195 if (!strcmp(cmd,"create"))
197 else if (!strcmp(cmd,"dump"))
199 else if (!strcmp(cmd,"info"))
201 else if (!strcmp(cmd,"restore"))
202 help_cmd = C_RESTORE;
203 else if (!strcmp(cmd,"last"))
205 else if (!strcmp(cmd,"first"))
207 else if (!strcmp(cmd,"update"))
209 else if (!strcmp(cmd,"updatev"))
210 help_cmd = C_UPDATEV;
211 else if (!strcmp(cmd,"fetch"))
213 else if (!strcmp(cmd,"graph"))
215 else if (!strcmp(cmd,"tune"))
217 else if (!strcmp(cmd,"resize"))
219 else if (!strcmp(cmd,"xport"))
221 else if (!strcmp(cmd,"quit"))
223 else if (!strcmp(cmd,"ls"))
225 else if (!strcmp(cmd,"cd"))
227 else if (!strcmp(cmd,"mkdir"))
230 fputs(help_main, stdout);
234 fputs(help_list, stdout);
236 fputs(help_listremote, stdout);
240 fputs(help_create, stdout);
243 fputs(help_dump, stdout);
246 fputs(help_info, stdout);
249 fputs(help_restore, stdout);
252 fputs(help_last, stdout);
255 fputs(help_first, stdout);
258 fputs(help_update, stdout);
261 fputs(help_updatev, stdout);
264 fputs(help_fetch, stdout);
267 fputs(help_graph1, stdout);
268 fputs(help_graph2, stdout);
269 fputs(help_graph3, stdout);
272 fputs(help_tune1, stdout);
273 fputs(help_tune2, stdout);
276 fputs(help_resize, stdout);
279 fputs(help_xport, stdout);
282 fputs(help_quit, stdout);
285 fputs(help_ls, stdout);
288 fputs(help_cd, stdout);
291 fputs(help_mkdir, stdout);
294 fputs(help_lic, stdout);
298 int main(int argc, char *argv[])
301 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);
328 if ((argc == 3) && strcmp("",argv[2])){
333 fprintf(stderr,"ERROR: can't change root to '%s' errno=%d\n",
340 fprintf(stderr,"ERROR: change root is not supported by your OS "
341 "or at least by this copy of rrdtool\n");
348 if (strcmp(firstdir,"")){
351 fprintf(stderr,"ERROR: %s\n",rrd_strerror(errno));
356 while (fgets(aLine, sizeof(aLine)-1, stdin)){
357 if ((argc = CountArgs(aLine)) == 0) {
358 fprintf(stderr,"ERROR: not enough arguments\n");
360 if ((myargv = (char **) malloc((argc+1) *
361 sizeof(char *))) == NULL) {
365 if ((argc=CreateArgs(argv[0], aLine, argc, myargv)) < 0) {
366 printf("ERROR: creating arguments\n");
368 int ret = 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)
390 fflush(stdout); /* this is important for pipes to work */
398 else if (argc == 3 && !strcmp(argv[1],"help"))
404 exit(HandleInputLine(argc, argv, stderr));
409 /* HandleInputLine is NOT thread safe - due to readdir issues,
410 resolving them portably is not really simple. */
411 int HandleInputLine(int argc, char **argv, FILE* out)
413 #if defined(HAVE_OPENDIR) && defined (HAVE_READDIR)
414 DIR *curdir; /* to read current dir with ls */
417 #if defined(HAVE_SYS_STAT_H)
422 if (argc>1 && strcmp("quit", argv[1]) == 0){
424 printf("ERROR: invalid parameter count for quit\n");
429 #if defined(HAVE_OPENDIR) && defined(HAVE_READDIR) && defined(HAVE_CHDIR)
430 if (argc>1 && strcmp("cd", argv[1]) == 0){
432 printf("ERROR: invalid parameter count for cd\n");
435 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
436 if (getuid()==0 && ! ChangeRoot){
437 printf("ERROR: chdir security problem - rrdtool is running as "
438 "root an no chroot!\n");
444 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));
468 if (argc>1 && strcmp("ls", argv[1]) == 0){
470 printf("ERROR: invalid parameter count for ls\n");
473 if ((curdir=opendir("."))!=NULL){
474 while((dent=readdir(curdir))!=NULL){
475 if (!stat(dent->d_name,&st)){
476 if (S_ISDIR(st.st_mode)){
477 printf("d %s\n",dent->d_name);
479 if (strlen(dent->d_name)>4 && S_ISREG(st.st_mode)){
480 if (!strcmp(dent->d_name+NAMLEN(dent)-4,".rrd") ||
481 !strcmp(dent->d_name+NAMLEN(dent)-4,".RRD")){
482 printf("- %s\n",dent->d_name);
489 printf("ERROR: %s\n",rrd_strerror(errno));
494 #endif /* opendir and readdir */
498 || strcmp("help", argv[1]) == 0
499 || strcmp("--help", argv[1]) == 0
500 || strcmp("-help", argv[1]) == 0
501 || strcmp("-?", argv[1]) == 0
502 || strcmp("-h", argv[1]) == 0 ) {
507 if (strcmp("create", argv[1]) == 0)
508 rrd_create(argc-1, &argv[1]);
509 else if (strcmp("dump", argv[1]) == 0)
510 rrd_dump(argc-1, &argv[1]);
511 else if (strcmp("info", argv[1]) == 0
512 || strcmp("updatev", argv[1]) == 0){
514 if (strcmp("info",argv[1]) == 0)
515 data=rrd_info(argc-1, &argv[1]);
517 data=rrd_update_v(argc-1, &argv[1]);
520 printf ("%s = ", data->key);
523 switch (data->type) {
525 if (isnan (data->value.u_val))
528 printf ("%0.10e", data->value.u_val);
531 printf ("%lu", data->value.u_cnt);
534 printf ("%d", data->value.u_int);
537 printf ("\"%s\"", data->value.u_str);
538 free(data->value.u_str);
548 else if (strcmp("--version", argv[1]) == 0 ||
549 strcmp("version", argv[1]) == 0 ||
550 strcmp("v", argv[1]) == 0 ||
551 strcmp("-v", argv[1]) == 0 ||
552 strcmp("-version", argv[1]) == 0 )
553 printf("RRDtool " PACKAGE_VERSION " Copyright by Tobi Oetiker, 1997-2005 (%f)\n",
555 else if (strcmp("restore", argv[1]) == 0)
556 rrd_restore(argc-1, &argv[1]);
557 else if (strcmp("resize", argv[1]) == 0)
558 rrd_resize(argc-1, &argv[1]);
559 else if (strcmp("last", argv[1]) == 0)
560 printf("%ld\n",rrd_last(argc-1, &argv[1]));
561 else if (strcmp("first", argv[1]) == 0)
562 printf("%ld\n",rrd_first(argc-1, &argv[1]));
563 else if (strcmp("update", argv[1]) == 0)
564 rrd_update(argc-1, &argv[1]);
565 else if (strcmp("fetch", argv[1]) == 0) {
566 time_t start,end, ti;
567 unsigned long step, ds_cnt,i,ii;
568 rrd_value_t *data,*datai;
570 if (rrd_fetch(argc-1, &argv[1],&start,&end,&step,&ds_cnt,&ds_namv,&data) != -1) {
573 for (i = 0; i<ds_cnt;i++)
574 printf("%20s",ds_namv[i]);
576 for (ti = start+step; ti <= end; ti += step){
577 printf("%10lu:", ti);
578 for (ii = 0; ii < ds_cnt; ii++)
579 printf(" %0.10e", *(datai++));
582 for (i=0;i<ds_cnt;i++)
587 } else if (strcmp("xport", argv[1]) == 0) {
589 unsigned long int j = 0;
590 time_t start,end, ti;
591 unsigned long step, col_cnt,row_cnt;
592 rrd_value_t *data,*ptr;
594 if(rrd_xport(argc-1, &argv[1], &xxsize,&start,&end,&step,&col_cnt,&legend_v,&data) != -1) {
595 row_cnt = (end-start)/step;
597 printf("<?xml version=\"1.0\" encoding=\"%s\"?>\n\n", XML_ENCODING);
598 printf("<%s>\n", ROOT_TAG);
599 printf(" <%s>\n", META_TAG);
600 printf(" <%s>%lu</%s>\n", META_START_TAG, start+step, META_START_TAG);
601 printf(" <%s>%lu</%s>\n", META_STEP_TAG, step, META_STEP_TAG);
602 printf(" <%s>%lu</%s>\n", META_END_TAG, end, META_END_TAG);
603 printf(" <%s>%lu</%s>\n", META_ROWS_TAG, row_cnt, META_ROWS_TAG);
604 printf(" <%s>%lu</%s>\n", META_COLS_TAG, col_cnt, META_COLS_TAG);
605 printf(" <%s>\n", LEGEND_TAG);
606 for (j = 0; j < col_cnt; j++) {
609 printf(" <%s>%s</%s>\n", LEGEND_ENTRY_TAG, entry, LEGEND_ENTRY_TAG);
613 printf(" </%s>\n", LEGEND_TAG);
614 printf(" </%s>\n", META_TAG);
615 printf(" <%s>\n", DATA_TAG);
616 for (ti = start+step; ti <= end; ti += step) {
617 printf (" <%s>", DATA_ROW_TAG);
618 printf ("<%s>%lu</%s>", COL_TIME_TAG, ti, COL_TIME_TAG);
619 for (j = 0; j < col_cnt; j++) {
620 rrd_value_t newval = DNAN;
623 printf("<%s>NaN</%s>", COL_DATA_TAG, COL_DATA_TAG);
625 printf("<%s>%0.10e</%s>", COL_DATA_TAG, newval, COL_DATA_TAG);
629 printf("</%s>\n", DATA_ROW_TAG);
632 printf(" </%s>\n", DATA_TAG);
633 printf("</%s>\n", ROOT_TAG);
636 else if (strcmp("graph", argv[1]) == 0) {
638 #ifdef notused /*XXX*/
639 const char *imgfile = argv[2]; /* rrd_graph changes argv pointer */
644 int tostdout = (strcmp(argv[2],"-") == 0);
645 if( rrd_graph(argc-1, &argv[1], &calcpr, &xsize, &ysize, NULL, &ymin, &ymax) != -1 ) {
647 printf ("%dx%d\n",xsize,ysize);
649 for(i=0;calcpr[i];i++){
651 printf("%s\n",calcpr[i]);
658 } else if (strcmp("tune", argv[1]) == 0)
659 rrd_tune(argc-1, &argv[1]);
661 rrd_set_error("unknown function '%s'",argv[1]);
663 if (rrd_test_error()) {
664 fprintf(out, "ERROR: %s\n",rrd_get_error());
671 int CountArgs(char *aLine)
676 while (aLine[i] == ' ') i++;
677 while (aLine[i] != 0){
678 if((aLine[i]== ' ') && inarg){
681 if((aLine[i]!= ' ') && ! inarg){
691 * CreateArgs - take a string (aLine) and tokenize
693 int CreateArgs(char *pName, char *aLine, int argc, char **argv)
702 /* remove trailing space and newlines */
703 while (len && aLine[len] <= ' ') {
704 aLine[len] = 0 ; len--;
706 /* sikp leading blanks */
707 while (*aLine && *aLine <= ' ') aLine++;
734 pargv[argc++] = putP;
742 pargv[argc++] = putP;