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, 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 "* 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[--resolution|-r resolution]\n"
85 "\t\t[--start|-s start] [--end|-e 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[--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";
101 "\t\t[-j|--only-graph]\n"
102 "\t\t[--font FONTTAG:size:font]\n"
103 "\t\t[--zoom factor]\n"
104 "\t\t[--alt-autoscale]\n"
105 "\t\t[--alt-autoscale-max]\n"
106 "\t\t[--units-exponent value]\n"
107 "\t\t[--step seconds]\n"
108 "\t\t[-f|--imginfo printfstr]\n"
109 "\t\t[-a|--imgformat PNG]\n"
110 "\t\t[-c|--color COLORTAG#rrggbb[aa]] [-t|--title string]\n";
112 "\t\t[DEF:vname=rrd:ds-name:CF]\n"
113 "\t\t[CDEF:vname=rpn-expression]\n"
114 "\t\t[PRINT:vname:CF:format]\n"
115 "\t\t[GPRINT:vname:CF:format]\n"
116 "\t\t[HRULE:value#rrggbb[aa][:legend]]\n"
117 "\t\t[VRULE:value#rrggbb[aa][:legend]]\n"
118 "\t\t[LINE{1|2|3}:vname[#rrggbb[aa][:legend]]]\n"
119 "\t\t[AREA:vname[#rrggbb[aa][:legend]]]\n"
120 "\t\t[STACK:vname[#rrggbb[aa][:legend]]]\n\n";
123 " * tune - Modify some basic properties of an RRD\n\n"
124 "\trrdtool tune filename\n"
125 "\t\t[--heartbeat|-h ds-name:heartbeat]\n"
126 "\t\t[--data-source-type|-d ds-name:DST]\n"
127 "\t\t[--data-source-rename|-r old-name:new-name]\n"
128 "\t\t[--minimum|-i ds-name:min] [--maximum|-a ds-name:max]\n"
129 "\t\t[--deltapos scale-value] [--deltaneg scale-value]\n"
130 "\t\t[--failure-threshold integer]\n"
131 "\t\t[--window-length integer]\n"
132 "\t\t[--alpha adaptation-parameter]\n";
134 " * tune - Modify some basic properties of an RRD\n\n"
135 "\t\t[--beta adaptation-parameter]\n"
136 "\t\t[--gamma adaptation-parameter]\n"
137 "\t\t[--gamma-deviation adaptation-parameter]\n"
138 "\t\t[--aberrant-reset ds-name]\n\n";
141 " * resize - alter the length of one of the RRAs in an RRD\n\n"
142 "\trrdtool resize filename rranum GROW|SHRINK rows\n\n";
145 "* xport - generate XML dump from one or several RRD\n\n"
146 "\trrdtool xport [-s|--start seconds] [-e|--end seconds]\n"
147 "\t\t[-m|--maxrows rows]\n"
148 "\t\t[--step seconds]\n"
149 "\t\t[DEF:vname=rrd:ds-name:CF]\n"
150 "\t\t[CDEF:vname=rpn-expression]\n"
151 "\t\t[XPORT:vname:legend]\n\n";
154 " * quit - closing a session in remote mode\n\n"
155 "\trrdtool quit\n\n";
158 " * ls - lists all *.rrd files in current directory\n\n"
162 " * cd - changes the current directory\n\n"
163 "\trrdtool cd new directory\n\n";
166 " * mkdir - creates a new directory\n\n"
167 "\trrdtool mkdir newdirectoryname\n\n";
170 "RRDtool is distributed under the Terms of the GNU General\n"
171 "Public License Version 2. (www.gnu.org/copyleft/gpl.html)\n\n"
173 "For more information read the RRD manpages\n\n";
175 enum { C_NONE, C_CREATE, C_DUMP, C_INFO, C_RESTORE, C_LAST,
176 C_UPDATE, C_FETCH, C_GRAPH, C_TUNE, C_RESIZE, C_XPORT,
177 C_QUIT, C_LS, C_CD, C_MKDIR, C_UPDATEV };
179 int help_cmd = C_NONE;
183 if (!strcmp(cmd,"create"))
185 else if (!strcmp(cmd,"dump"))
187 else if (!strcmp(cmd,"info"))
189 else if (!strcmp(cmd,"restore"))
190 help_cmd = C_RESTORE;
191 else if (!strcmp(cmd,"last"))
193 else if (!strcmp(cmd,"update"))
195 else if (!strcmp(cmd,"updatev"))
196 help_cmd = C_UPDATEV;
197 else if (!strcmp(cmd,"fetch"))
199 else if (!strcmp(cmd,"graph"))
201 else if (!strcmp(cmd,"tune"))
203 else if (!strcmp(cmd,"resize"))
205 else if (!strcmp(cmd,"xport"))
207 else if (!strcmp(cmd,"quit"))
209 else if (!strcmp(cmd,"ls"))
211 else if (!strcmp(cmd,"cd"))
213 else if (!strcmp(cmd,"mkdir"))
216 fputs(help_main, stdout);
220 fputs(help_list, stdout);
222 fputs(help_listremote, stdout);
226 fputs(help_create, stdout);
229 fputs(help_dump, stdout);
232 fputs(help_info, stdout);
235 fputs(help_restore, stdout);
238 fputs(help_last, stdout);
241 fputs(help_update, stdout);
244 fputs(help_updatev, stdout);
247 fputs(help_fetch, stdout);
250 fputs(help_graph1, stdout);
251 fputs(help_graph2, stdout);
252 fputs(help_graph3, stdout);
255 fputs(help_tune1, stdout);
256 fputs(help_tune2, stdout);
259 fputs(help_resize, stdout);
262 fputs(help_xport, stdout);
265 fputs(help_quit, stdout);
268 fputs(help_ls, stdout);
271 fputs(help_cd, stdout);
274 fputs(help_mkdir, stdout);
277 fputs(help_lic, stdout);
281 int main(int argc, char *argv[])
284 char aLine[MAX_LENGTH];
288 #ifdef MUST_DISABLE_SIGFPE
289 signal(SIGFPE,SIG_IGN);
291 #ifdef MUST_DISABLE_FPMASK
300 if (((argc == 2)||(argc == 3)) && !strcmp("-",argv[1]))
303 struct rusage myusage;
304 struct timeval starttime;
305 struct timeval currenttime;
308 tz.tz_minuteswest =0;
310 gettimeofday(&starttime,&tz);
314 if ((argc == 3) && strcmp("",argv[2])){
318 fprintf(stderr,"ERROR: can't change root to '%s' errno=%d\n",
329 if (strcmp(firstdir,"")){
332 fprintf(stderr,"ERROR: %s\n",rrd_strerror(errno));
337 fprintf(stderr,"ERROR: change root is not supported by your OS "
338 "or at least by this copy of rrdtool\n");
342 while (fgets(aLine, sizeof(aLine)-1, stdin)){
343 if ((argc = CountArgs(aLine)) == 0) {
344 fprintf(stderr,"ERROR: not enough arguments\n");
346 if ((myargv = (char **) malloc((argc+1) *
347 sizeof(char *))) == NULL) {
351 if ((argc=CreateArgs(argv[0], aLine, argc, myargv)) < 0) {
352 fprintf(stderr, "ERROR: creating arguments\n");
356 if (HandleInputLine(argc, myargv, stdout))
361 getrusage(RUSAGE_SELF,&myusage);
362 gettimeofday(¤ttime,&tz);
363 printf("OK u:%1.2f s:%1.2f r:%1.2f\n",
364 (double)myusage.ru_utime.tv_sec+
365 (double)myusage.ru_utime.tv_usec/1000000.0,
366 (double)myusage.ru_stime.tv_sec+
367 (double)myusage.ru_stime.tv_usec/1000000.0,
368 (double)(currenttime.tv_sec-starttime.tv_sec)
369 +(double)(currenttime.tv_usec-starttime.tv_usec)
374 fflush(stdout); /* this is important for pipes to work */
382 else if (argc == 3 && !strcmp(argv[1],"help"))
388 HandleInputLine(argc, argv, stderr);
392 /* HandleInputLine is NOT thread safe - due to readdir issues,
393 resolving them portably is not really simple. */
394 int HandleInputLine(int argc, char **argv, FILE* out)
396 #if defined(HAVE_OPENDIR) && defined (HAVE_READDIR)
397 DIR *curdir; /* to read current dir with ls */
400 #if defined(HAVE_SYS_STAT_H)
403 optind=0; /* reset gnu getopt */
404 opterr=0; /* no error messages */
407 if (argc>1 && strcmp("quit", argv[1]) == 0){
409 printf("ERROR: invalid parameter count for quit\n");
414 #if defined(HAVE_OPENDIR) && defined(HAVE_READDIR) && defined(HAVE_CHDIR)
415 if (argc>1 && strcmp("cd", argv[1]) == 0){
417 printf("ERROR: invalid parameter count for cd\n");
420 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
421 if (getuid()==0 && ! ChangeRoot){
422 printf("ERROR: chdir security problem - rrdtool is running as "
423 "root an no chroot!\n");
429 printf("ERROR: %s\n",rrd_strerror(errno));
433 if (argc>1 && strcmp("mkdir", argv[1]) == 0){
435 printf("ERROR: invalid parameter count for mkdir\n");
438 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
439 if (getuid()==0 && ! ChangeRoot){
440 printf("ERROR: mkdir security problem - rrdtool is running as "
441 "root an no chroot!\n");
447 printf("ERROR: %s\n",rrd_strerror(errno));
451 if (argc>1 && strcmp("ls", argv[1]) == 0){
453 printf("ERROR: invalid parameter count for ls\n");
456 if ((curdir=opendir("."))!=NULL){
457 while((dent=readdir(curdir))!=NULL){
458 if (!stat(dent->d_name,&st)){
459 if (S_ISDIR(st.st_mode)){
460 printf("d %s\n",dent->d_name);
462 if (strlen(dent->d_name)>4 && S_ISREG(st.st_mode)){
463 if (!strcmp(dent->d_name+NAMLEN(dent)-4,".rrd") ||
464 !strcmp(dent->d_name+NAMLEN(dent)-4,".RRD")){
465 printf("- %s\n",dent->d_name);
472 printf("ERROR: %s\n",rrd_strerror(errno));
477 #endif /* opendir and readdir */
481 || strcmp("help", argv[1]) == 0
482 || strcmp("--help", argv[1]) == 0
483 || strcmp("-help", argv[1]) == 0
484 || strcmp("-?", argv[1]) == 0
485 || strcmp("-h", argv[1]) == 0 ) {
490 if (strcmp("create", argv[1]) == 0)
491 rrd_create(argc-1, &argv[1]);
492 else if (strcmp("dump", argv[1]) == 0)
493 rrd_dump(argc-1, &argv[1]);
494 else if (strcmp("info", argv[1]) == 0
495 || strcmp("updatev", argv[1]) == 0){
497 if (strcmp("info",argv[1]) == 0)
498 data=rrd_info(argc-1, &argv[1]);
500 data=rrd_update_v(argc-1, &argv[1]);
503 printf ("%s = ", data->key);
506 switch (data->type) {
508 if (isnan (data->value.u_val))
511 printf ("%0.10e", data->value.u_val);
514 printf ("%lu", data->value.u_cnt);
517 printf ("%d", data->value.u_int);
520 printf ("\"%s\"", data->value.u_str);
521 free(data->value.u_str);
531 else if (strcmp("--version", argv[1]) == 0 ||
532 strcmp("version", argv[1]) == 0 ||
533 strcmp("v", argv[1]) == 0 ||
534 strcmp("-v", argv[1]) == 0 ||
535 strcmp("-version", argv[1]) == 0 )
536 printf("RRDtool 1.1.x Copyright (C) 1997-2004 by Tobias Oetiker <tobi@oetiker.ch>\n");
537 else if (strcmp("restore", argv[1]) == 0)
538 rrd_restore(argc-1, &argv[1]);
539 else if (strcmp("resize", argv[1]) == 0)
540 rrd_resize(argc-1, &argv[1]);
541 else if (strcmp("last", argv[1]) == 0)
542 printf("%ld\n",rrd_last(argc-1, argv[1]));
543 else if (strcmp("update", argv[1]) == 0)
544 rrd_update(argc-1, &argv[1]);
545 else if (strcmp("fetch", argv[1]) == 0) {
546 time_t start,end, ti;
547 unsigned long step, ds_cnt,i,ii;
548 rrd_value_t *data,*datai;
550 if (rrd_fetch(argc-1, &argv[1],&start,&end,&step,&ds_cnt,&ds_namv,&data) != -1) {
553 for (i = 0; i<ds_cnt;i++)
554 printf("%20s",ds_namv[i]);
556 for (ti = start+step; ti <= end; ti += step){
557 printf("%10lu:", ti);
558 for (ii = 0; ii < ds_cnt; ii++)
559 printf(" %0.10e", *(datai++));
562 for (i=0;i<ds_cnt;i++)
567 } else if (strcmp("xport", argv[1]) == 0) {
569 unsigned long int j = 0;
570 time_t start,end, ti;
571 unsigned long step, col_cnt,row_cnt;
572 rrd_value_t *data,*ptr;
574 if(rrd_xport(argc-1, &argv[1], &xxsize,&start,&end,&step,&col_cnt,&legend_v,&data) != -1) {
575 row_cnt = (end-start)/step;
577 printf("<?xml version=\"1.0\" encoding=\"%s\"?>\n\n", XML_ENCODING);
578 printf("<%s>\n", ROOT_TAG);
579 printf(" <%s>\n", META_TAG);
580 printf(" <%s>%lu</%s>\n", META_START_TAG, start+step, META_START_TAG);
581 printf(" <%s>%lu</%s>\n", META_STEP_TAG, step, META_STEP_TAG);
582 printf(" <%s>%lu</%s>\n", META_END_TAG, end, META_END_TAG);
583 printf(" <%s>%lu</%s>\n", META_ROWS_TAG, row_cnt, META_ROWS_TAG);
584 printf(" <%s>%lu</%s>\n", META_COLS_TAG, col_cnt, META_COLS_TAG);
585 printf(" <%s>\n", LEGEND_TAG);
586 for (j = 0; j < col_cnt; j++) {
589 printf(" <%s>%s</%s>\n", LEGEND_ENTRY_TAG, entry, LEGEND_ENTRY_TAG);
593 printf(" </%s>\n", LEGEND_TAG);
594 printf(" </%s>\n", META_TAG);
595 printf(" <%s>\n", DATA_TAG);
596 for (ti = start+step; ti <= end; ti += step) {
597 printf (" <%s>", DATA_ROW_TAG);
598 printf ("<%s>%lu</%s>", COL_TIME_TAG, ti, COL_TIME_TAG);
599 for (j = 0; j < col_cnt; j++) {
600 rrd_value_t newval = DNAN;
603 printf("<%s>NaN</%s>", COL_DATA_TAG, COL_DATA_TAG);
605 printf("<%s>%0.10e</%s>", COL_DATA_TAG, newval, COL_DATA_TAG);
609 printf("</%s>\n", DATA_ROW_TAG);
612 printf(" </%s>\n", DATA_TAG);
613 printf("</%s>\n", ROOT_TAG);
616 else if (strcmp("graph", argv[1]) == 0) {
618 #ifdef notused /*XXX*/
619 const char *imgfile = argv[2]; /* rrd_graph changes argv pointer */
623 int tostdout = (strcmp(argv[2],"-") == 0);
624 if( rrd_graph(argc-1, &argv[1], &calcpr, &xsize, &ysize, NULL) != -1 ) {
626 printf ("%dx%d\n",xsize,ysize);
628 for(i=0;calcpr[i];i++){
630 printf("%s\n",calcpr[i]);
637 } else if (strcmp("tune", argv[1]) == 0)
638 rrd_tune(argc-1, &argv[1]);
640 rrd_set_error("unknown function '%s'",argv[1]);
642 if (rrd_test_error()) {
643 fprintf(out, "ERROR: %s\n",rrd_get_error());
649 int CountArgs(char *aLine)
654 while (aLine[i] == ' ') i++;
655 while (aLine[i] != 0){
656 if((aLine[i]== ' ') && inarg){
659 if((aLine[i]!= ' ') && ! inarg){
669 * CreateArgs - take a string (aLine) and tokenize
671 int CreateArgs(char *pName, char *aLine, int argc, char **argv)
680 /* remove trailing space and newlines */
681 while (len && aLine[len] <= ' ') {
682 aLine[len] = 0 ; len--;
684 /* sikp leading blanks */
685 while (*aLine && *aLine <= ' ') aLine++;
712 pargv[argc++] = putP;
720 pargv[argc++] = putP;