1 /*****************************************************************************
2 * RRDtool 1.1.x Copyright Tobias Oetiker, 1997 - 2004
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.1.x Copyright 1997-2004 by Tobias Oetiker <tobi@oetiker.ch>\n"
27 " Compiled " MAKE_TIMESTAMP "\n\n"
29 " Compiled " __DATE__ " " __TIME__ "\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[PRINT:vname:CF:format]\n"
120 "\t\t[GPRINT:vname:CF:format]\n"
121 "\t\t[HRULE:value#rrggbb[aa][:legend]]\n"
122 "\t\t[VRULE:value#rrggbb[aa][:legend]]\n"
123 "\t\t[LINE{1|2|3}:vname[#rrggbb[aa][:legend]]]\n"
124 "\t\t[AREA:vname[#rrggbb[aa][:legend]]]\n"
125 "\t\t[STACK:vname[#rrggbb[aa][:legend]]]\n\n";
128 " * tune - Modify some basic properties of an RRD\n\n"
129 "\trrdtool tune filename\n"
130 "\t\t[--heartbeat|-h ds-name:heartbeat]\n"
131 "\t\t[--data-source-type|-d ds-name:DST]\n"
132 "\t\t[--data-source-rename|-r old-name:new-name]\n"
133 "\t\t[--minimum|-i ds-name:min] [--maximum|-a ds-name:max]\n"
134 "\t\t[--deltapos scale-value] [--deltaneg scale-value]\n"
135 "\t\t[--failure-threshold integer]\n"
136 "\t\t[--window-length integer]\n"
137 "\t\t[--alpha adaptation-parameter]\n";
139 " * tune - Modify some basic properties of an RRD\n\n"
140 "\t\t[--beta adaptation-parameter]\n"
141 "\t\t[--gamma adaptation-parameter]\n"
142 "\t\t[--gamma-deviation adaptation-parameter]\n"
143 "\t\t[--aberrant-reset ds-name]\n\n";
146 " * resize - alter the length of one of the RRAs in an RRD\n\n"
147 "\trrdtool resize filename rranum GROW|SHRINK rows\n\n";
150 "* xport - generate XML dump from one or several RRD\n\n"
151 "\trrdtool xport [-s|--start seconds] [-e|--end seconds]\n"
152 "\t\t[-m|--maxrows rows]\n"
153 "\t\t[--step seconds]\n"
154 "\t\t[DEF:vname=rrd:ds-name:CF]\n"
155 "\t\t[CDEF:vname=rpn-expression]\n"
156 "\t\t[XPORT:vname:legend]\n\n";
159 " * quit - closing a session in remote mode\n\n"
160 "\trrdtool quit\n\n";
163 " * ls - lists all *.rrd files in current directory\n\n"
167 " * cd - changes the current directory\n\n"
168 "\trrdtool cd new directory\n\n";
171 " * mkdir - creates a new directory\n\n"
172 "\trrdtool mkdir newdirectoryname\n\n";
175 "RRDtool is distributed under the Terms of the GNU General\n"
176 "Public License Version 2. (www.gnu.org/copyleft/gpl.html)\n\n"
178 "For more information read the RRD manpages\n\n";
180 enum { C_NONE, C_CREATE, C_DUMP, C_INFO, C_RESTORE, C_LAST, C_FIRST,
181 C_UPDATE, C_FETCH, C_GRAPH, C_TUNE, C_RESIZE, C_XPORT,
182 C_QUIT, C_LS, C_CD, C_MKDIR, C_UPDATEV };
184 int help_cmd = C_NONE;
188 if (!strcmp(cmd,"create"))
190 else if (!strcmp(cmd,"dump"))
192 else if (!strcmp(cmd,"info"))
194 else if (!strcmp(cmd,"restore"))
195 help_cmd = C_RESTORE;
196 else if (!strcmp(cmd,"last"))
198 else if (!strcmp(cmd,"first"))
200 else if (!strcmp(cmd,"update"))
202 else if (!strcmp(cmd,"updatev"))
203 help_cmd = C_UPDATEV;
204 else if (!strcmp(cmd,"fetch"))
206 else if (!strcmp(cmd,"graph"))
208 else if (!strcmp(cmd,"tune"))
210 else if (!strcmp(cmd,"resize"))
212 else if (!strcmp(cmd,"xport"))
214 else if (!strcmp(cmd,"quit"))
216 else if (!strcmp(cmd,"ls"))
218 else if (!strcmp(cmd,"cd"))
220 else if (!strcmp(cmd,"mkdir"))
223 fputs(help_main, stdout);
227 fputs(help_list, stdout);
229 fputs(help_listremote, stdout);
233 fputs(help_create, stdout);
236 fputs(help_dump, stdout);
239 fputs(help_info, stdout);
242 fputs(help_restore, stdout);
245 fputs(help_last, stdout);
248 fputs(help_first, stdout);
251 fputs(help_update, stdout);
254 fputs(help_updatev, stdout);
257 fputs(help_fetch, stdout);
260 fputs(help_graph1, stdout);
261 fputs(help_graph2, stdout);
262 fputs(help_graph3, stdout);
265 fputs(help_tune1, stdout);
266 fputs(help_tune2, stdout);
269 fputs(help_resize, stdout);
272 fputs(help_xport, stdout);
275 fputs(help_quit, stdout);
278 fputs(help_ls, stdout);
281 fputs(help_cd, stdout);
284 fputs(help_mkdir, stdout);
287 fputs(help_lic, stdout);
291 int main(int argc, char *argv[])
294 char aLine[MAX_LENGTH];
298 #ifdef MUST_DISABLE_SIGFPE
299 signal(SIGFPE,SIG_IGN);
301 #ifdef MUST_DISABLE_FPMASK
310 if (((argc == 2)||(argc == 3)) && !strcmp("-",argv[1]))
313 struct rusage myusage;
314 struct timeval starttime;
315 struct timeval currenttime;
318 tz.tz_minuteswest =0;
320 gettimeofday(&starttime,&tz);
324 if ((argc == 3) && strcmp("",argv[2])){
328 fprintf(stderr,"ERROR: can't change root to '%s' errno=%d\n",
339 if (strcmp(firstdir,"")){
342 fprintf(stderr,"ERROR: %s\n",rrd_strerror(errno));
347 fprintf(stderr,"ERROR: change root is not supported by your OS "
348 "or at least by this copy of rrdtool\n");
352 while (fgets(aLine, sizeof(aLine)-1, stdin)){
353 if ((argc = CountArgs(aLine)) == 0) {
354 fprintf(stderr,"ERROR: not enough arguments\n");
356 if ((myargv = (char **) malloc((argc+1) *
357 sizeof(char *))) == NULL) {
361 if ((argc=CreateArgs(argv[0], aLine, argc, myargv)) < 0) {
362 fprintf(stderr, "ERROR: creating arguments\n");
366 if (HandleInputLine(argc, myargv, stdout))
371 getrusage(RUSAGE_SELF,&myusage);
372 gettimeofday(¤ttime,&tz);
373 printf("OK u:%1.2f s:%1.2f r:%1.2f\n",
374 (double)myusage.ru_utime.tv_sec+
375 (double)myusage.ru_utime.tv_usec/1000000.0,
376 (double)myusage.ru_stime.tv_sec+
377 (double)myusage.ru_stime.tv_usec/1000000.0,
378 (double)(currenttime.tv_sec-starttime.tv_sec)
379 +(double)(currenttime.tv_usec-starttime.tv_usec)
384 fflush(stdout); /* this is important for pipes to work */
392 else if (argc == 3 && !strcmp(argv[1],"help"))
398 if(HandleInputLine(argc, argv, stderr)) {
405 /* HandleInputLine is NOT thread safe - due to readdir issues,
406 resolving them portably is not really simple. */
407 int HandleInputLine(int argc, char **argv, FILE* out)
409 #if defined(HAVE_OPENDIR) && defined (HAVE_READDIR)
410 DIR *curdir; /* to read current dir with ls */
413 #if defined(HAVE_SYS_STAT_H)
416 optind=0; /* reset gnu getopt */
417 opterr=0; /* no error messages */
420 if (argc>1 && strcmp("quit", argv[1]) == 0){
422 printf("ERROR: invalid parameter count for quit\n");
427 #if defined(HAVE_OPENDIR) && defined(HAVE_READDIR) && defined(HAVE_CHDIR)
428 if (argc>1 && strcmp("cd", argv[1]) == 0){
430 printf("ERROR: invalid parameter count for cd\n");
433 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
434 if (getuid()==0 && ! ChangeRoot){
435 printf("ERROR: chdir security problem - rrdtool is running as "
436 "root an no chroot!\n");
442 printf("ERROR: %s\n",rrd_strerror(errno));
446 if (argc>1 && strcmp("mkdir", argv[1]) == 0){
448 printf("ERROR: invalid parameter count for mkdir\n");
451 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
452 if (getuid()==0 && ! ChangeRoot){
453 printf("ERROR: mkdir security problem - rrdtool is running as "
454 "root an no chroot!\n");
460 printf("ERROR: %s\n",rrd_strerror(errno));
464 if (argc>1 && strcmp("ls", argv[1]) == 0){
466 printf("ERROR: invalid parameter count for ls\n");
469 if ((curdir=opendir("."))!=NULL){
470 while((dent=readdir(curdir))!=NULL){
471 if (!stat(dent->d_name,&st)){
472 if (S_ISDIR(st.st_mode)){
473 printf("d %s\n",dent->d_name);
475 if (strlen(dent->d_name)>4 && S_ISREG(st.st_mode)){
476 if (!strcmp(dent->d_name+NAMLEN(dent)-4,".rrd") ||
477 !strcmp(dent->d_name+NAMLEN(dent)-4,".RRD")){
478 printf("- %s\n",dent->d_name);
485 printf("ERROR: %s\n",rrd_strerror(errno));
490 #endif /* opendir and readdir */
494 || strcmp("help", argv[1]) == 0
495 || strcmp("--help", argv[1]) == 0
496 || strcmp("-help", argv[1]) == 0
497 || strcmp("-?", argv[1]) == 0
498 || strcmp("-h", argv[1]) == 0 ) {
503 if (strcmp("create", argv[1]) == 0)
504 rrd_create(argc-1, &argv[1]);
505 else if (strcmp("dump", argv[1]) == 0)
506 rrd_dump(argc-1, &argv[1]);
507 else if (strcmp("info", argv[1]) == 0
508 || strcmp("updatev", argv[1]) == 0){
510 if (strcmp("info",argv[1]) == 0)
511 data=rrd_info(argc-1, &argv[1]);
513 data=rrd_update_v(argc-1, &argv[1]);
516 printf ("%s = ", data->key);
519 switch (data->type) {
521 if (isnan (data->value.u_val))
524 printf ("%0.10e", data->value.u_val);
527 printf ("%lu", data->value.u_cnt);
530 printf ("%d", data->value.u_int);
533 printf ("\"%s\"", data->value.u_str);
534 free(data->value.u_str);
544 else if (strcmp("--version", argv[1]) == 0 ||
545 strcmp("version", argv[1]) == 0 ||
546 strcmp("v", argv[1]) == 0 ||
547 strcmp("-v", argv[1]) == 0 ||
548 strcmp("-version", argv[1]) == 0 )
549 printf("RRDtool 1.1.x Copyright (C) 1997-2004 by Tobias Oetiker <tobi@oetiker.ch>\n");
550 else if (strcmp("restore", argv[1]) == 0)
551 rrd_restore(argc-1, &argv[1]);
552 else if (strcmp("resize", argv[1]) == 0)
553 rrd_resize(argc-1, &argv[1]);
554 else if (strcmp("last", argv[1]) == 0)
555 printf("%ld\n",rrd_last(argc-1, &argv[1]));
556 else if (strcmp("first", argv[1]) == 0)
557 printf("%ld\n",rrd_first(argc-1, &argv[1]));
558 else if (strcmp("update", argv[1]) == 0)
559 rrd_update(argc-1, &argv[1]);
560 else if (strcmp("fetch", argv[1]) == 0) {
561 time_t start,end, ti;
562 unsigned long step, ds_cnt,i,ii;
563 rrd_value_t *data,*datai;
565 if (rrd_fetch(argc-1, &argv[1],&start,&end,&step,&ds_cnt,&ds_namv,&data) != -1) {
568 for (i = 0; i<ds_cnt;i++)
569 printf("%20s",ds_namv[i]);
571 for (ti = start+step; ti <= end; ti += step){
572 printf("%10lu:", ti);
573 for (ii = 0; ii < ds_cnt; ii++)
574 printf(" %0.10e", *(datai++));
577 for (i=0;i<ds_cnt;i++)
582 } else if (strcmp("xport", argv[1]) == 0) {
584 unsigned long int j = 0;
585 time_t start,end, ti;
586 unsigned long step, col_cnt,row_cnt;
587 rrd_value_t *data,*ptr;
589 if(rrd_xport(argc-1, &argv[1], &xxsize,&start,&end,&step,&col_cnt,&legend_v,&data) != -1) {
590 row_cnt = (end-start)/step;
592 printf("<?xml version=\"1.0\" encoding=\"%s\"?>\n\n", XML_ENCODING);
593 printf("<%s>\n", ROOT_TAG);
594 printf(" <%s>\n", META_TAG);
595 printf(" <%s>%lu</%s>\n", META_START_TAG, start+step, META_START_TAG);
596 printf(" <%s>%lu</%s>\n", META_STEP_TAG, step, META_STEP_TAG);
597 printf(" <%s>%lu</%s>\n", META_END_TAG, end, META_END_TAG);
598 printf(" <%s>%lu</%s>\n", META_ROWS_TAG, row_cnt, META_ROWS_TAG);
599 printf(" <%s>%lu</%s>\n", META_COLS_TAG, col_cnt, META_COLS_TAG);
600 printf(" <%s>\n", LEGEND_TAG);
601 for (j = 0; j < col_cnt; j++) {
604 printf(" <%s>%s</%s>\n", LEGEND_ENTRY_TAG, entry, LEGEND_ENTRY_TAG);
608 printf(" </%s>\n", LEGEND_TAG);
609 printf(" </%s>\n", META_TAG);
610 printf(" <%s>\n", DATA_TAG);
611 for (ti = start+step; ti <= end; ti += step) {
612 printf (" <%s>", DATA_ROW_TAG);
613 printf ("<%s>%lu</%s>", COL_TIME_TAG, ti, COL_TIME_TAG);
614 for (j = 0; j < col_cnt; j++) {
615 rrd_value_t newval = DNAN;
618 printf("<%s>NaN</%s>", COL_DATA_TAG, COL_DATA_TAG);
620 printf("<%s>%0.10e</%s>", COL_DATA_TAG, newval, COL_DATA_TAG);
624 printf("</%s>\n", DATA_ROW_TAG);
627 printf(" </%s>\n", DATA_TAG);
628 printf("</%s>\n", ROOT_TAG);
631 else if (strcmp("graph", argv[1]) == 0) {
633 #ifdef notused /*XXX*/
634 const char *imgfile = argv[2]; /* rrd_graph changes argv pointer */
639 int tostdout = (strcmp(argv[2],"-") == 0);
640 if( rrd_graph(argc-1, &argv[1], &calcpr, &xsize, &ysize, NULL, &ymin, &ymax) != -1 ) {
642 printf ("%dx%d\n",xsize,ysize);
644 for(i=0;calcpr[i];i++){
646 printf("%s\n",calcpr[i]);
653 } else if (strcmp("tune", argv[1]) == 0)
654 rrd_tune(argc-1, &argv[1]);
656 rrd_set_error("unknown function '%s'",argv[1]);
658 if (rrd_test_error()) {
659 fprintf(out, "ERROR: %s\n",rrd_get_error());
666 int CountArgs(char *aLine)
671 while (aLine[i] == ' ') i++;
672 while (aLine[i] != 0){
673 if((aLine[i]== ' ') && inarg){
676 if((aLine[i]!= ' ') && ! inarg){
686 * CreateArgs - take a string (aLine) and tokenize
688 int CreateArgs(char *pName, char *aLine, int argc, char **argv)
697 /* remove trailing space and newlines */
698 while (len && aLine[len] <= ' ') {
699 aLine[len] = 0 ; len--;
701 /* sikp leading blanks */
702 while (*aLine && *aLine <= ' ') aLine++;
729 pargv[argc++] = putP;
737 pargv[argc++] = putP;