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"
100 "\t\t[-F|--force-rules-legend]\n";
102 "\t\t[-j|--only-graph]\n"
103 "\t\t[--font FONTTAG:size:font]\n"
104 "\t\t[--zoom factor]\n"
105 "\t\t[--alt-autoscale]\n"
106 "\t\t[--alt-autoscale-max]\n"
107 "\t\t[--units-exponent value]\n"
108 "\t\t[--step seconds]\n"
109 "\t\t[-f|--imginfo printfstr]\n"
110 "\t\t[-a|--imgformat PNG]\n"
111 "\t\t[-c|--color COLORTAG#rrggbb[aa]] [-t|--title string]\n";
113 "\t\t[DEF:vname=rrd:ds-name:CF]\n"
114 "\t\t[CDEF:vname=rpn-expression]\n"
115 "\t\t[PRINT:vname:CF:format]\n"
116 "\t\t[GPRINT:vname:CF:format]\n"
117 "\t\t[HRULE:value#rrggbb[aa][:legend]]\n"
118 "\t\t[VRULE:value#rrggbb[aa][:legend]]\n"
119 "\t\t[LINE{1|2|3}:vname[#rrggbb[aa][:legend]]]\n"
120 "\t\t[AREA:vname[#rrggbb[aa][:legend]]]\n"
121 "\t\t[STACK:vname[#rrggbb[aa][:legend]]]\n\n";
124 " * tune - Modify some basic properties of an RRD\n\n"
125 "\trrdtool tune filename\n"
126 "\t\t[--heartbeat|-h ds-name:heartbeat]\n"
127 "\t\t[--data-source-type|-d ds-name:DST]\n"
128 "\t\t[--data-source-rename|-r old-name:new-name]\n"
129 "\t\t[--minimum|-i ds-name:min] [--maximum|-a ds-name:max]\n"
130 "\t\t[--deltapos scale-value] [--deltaneg scale-value]\n"
131 "\t\t[--failure-threshold integer]\n"
132 "\t\t[--window-length integer]\n"
133 "\t\t[--alpha adaptation-parameter]\n";
135 " * tune - Modify some basic properties of an RRD\n\n"
136 "\t\t[--beta adaptation-parameter]\n"
137 "\t\t[--gamma adaptation-parameter]\n"
138 "\t\t[--gamma-deviation adaptation-parameter]\n"
139 "\t\t[--aberrant-reset ds-name]\n\n";
142 " * resize - alter the length of one of the RRAs in an RRD\n\n"
143 "\trrdtool resize filename rranum GROW|SHRINK rows\n\n";
146 "* xport - generate XML dump from one or several RRD\n\n"
147 "\trrdtool xport [-s|--start seconds] [-e|--end seconds]\n"
148 "\t\t[-m|--maxrows rows]\n"
149 "\t\t[--step seconds]\n"
150 "\t\t[DEF:vname=rrd:ds-name:CF]\n"
151 "\t\t[CDEF:vname=rpn-expression]\n"
152 "\t\t[XPORT:vname:legend]\n\n";
155 " * quit - closing a session in remote mode\n\n"
156 "\trrdtool quit\n\n";
159 " * ls - lists all *.rrd files in current directory\n\n"
163 " * cd - changes the current directory\n\n"
164 "\trrdtool cd new directory\n\n";
167 " * mkdir - creates a new directory\n\n"
168 "\trrdtool mkdir newdirectoryname\n\n";
171 "RRDtool is distributed under the Terms of the GNU General\n"
172 "Public License Version 2. (www.gnu.org/copyleft/gpl.html)\n\n"
174 "For more information read the RRD manpages\n\n";
176 enum { C_NONE, C_CREATE, C_DUMP, C_INFO, C_RESTORE, C_LAST,
177 C_UPDATE, C_FETCH, C_GRAPH, C_TUNE, C_RESIZE, C_XPORT,
178 C_QUIT, C_LS, C_CD, C_MKDIR, C_UPDATEV };
180 int help_cmd = C_NONE;
184 if (!strcmp(cmd,"create"))
186 else if (!strcmp(cmd,"dump"))
188 else if (!strcmp(cmd,"info"))
190 else if (!strcmp(cmd,"restore"))
191 help_cmd = C_RESTORE;
192 else if (!strcmp(cmd,"last"))
194 else if (!strcmp(cmd,"update"))
196 else if (!strcmp(cmd,"updatev"))
197 help_cmd = C_UPDATEV;
198 else if (!strcmp(cmd,"fetch"))
200 else if (!strcmp(cmd,"graph"))
202 else if (!strcmp(cmd,"tune"))
204 else if (!strcmp(cmd,"resize"))
206 else if (!strcmp(cmd,"xport"))
208 else if (!strcmp(cmd,"quit"))
210 else if (!strcmp(cmd,"ls"))
212 else if (!strcmp(cmd,"cd"))
214 else if (!strcmp(cmd,"mkdir"))
217 fputs(help_main, stdout);
221 fputs(help_list, stdout);
223 fputs(help_listremote, stdout);
227 fputs(help_create, stdout);
230 fputs(help_dump, stdout);
233 fputs(help_info, stdout);
236 fputs(help_restore, stdout);
239 fputs(help_last, stdout);
242 fputs(help_update, stdout);
245 fputs(help_updatev, stdout);
248 fputs(help_fetch, stdout);
251 fputs(help_graph1, stdout);
252 fputs(help_graph2, stdout);
253 fputs(help_graph3, stdout);
256 fputs(help_tune1, stdout);
257 fputs(help_tune2, stdout);
260 fputs(help_resize, stdout);
263 fputs(help_xport, stdout);
266 fputs(help_quit, stdout);
269 fputs(help_ls, stdout);
272 fputs(help_cd, stdout);
275 fputs(help_mkdir, stdout);
278 fputs(help_lic, stdout);
282 int main(int argc, char *argv[])
285 char aLine[MAX_LENGTH];
289 #ifdef MUST_DISABLE_SIGFPE
290 signal(SIGFPE,SIG_IGN);
292 #ifdef MUST_DISABLE_FPMASK
301 if (((argc == 2)||(argc == 3)) && !strcmp("-",argv[1]))
304 struct rusage myusage;
305 struct timeval starttime;
306 struct timeval currenttime;
309 tz.tz_minuteswest =0;
311 gettimeofday(&starttime,&tz);
315 if ((argc == 3) && strcmp("",argv[2])){
319 fprintf(stderr,"ERROR: can't change root to '%s' errno=%d\n",
330 if (strcmp(firstdir,"")){
333 fprintf(stderr,"ERROR: %s\n",rrd_strerror(errno));
338 fprintf(stderr,"ERROR: change root is not supported by your OS "
339 "or at least by this copy of rrdtool\n");
343 while (fgets(aLine, sizeof(aLine)-1, stdin)){
344 if ((argc = CountArgs(aLine)) == 0) {
345 fprintf(stderr,"ERROR: not enough arguments\n");
347 if ((myargv = (char **) malloc((argc+1) *
348 sizeof(char *))) == NULL) {
352 if ((argc=CreateArgs(argv[0], aLine, argc, myargv)) < 0) {
353 fprintf(stderr, "ERROR: creating arguments\n");
357 if (HandleInputLine(argc, myargv, stdout))
362 getrusage(RUSAGE_SELF,&myusage);
363 gettimeofday(¤ttime,&tz);
364 printf("OK u:%1.2f s:%1.2f r:%1.2f\n",
365 (double)myusage.ru_utime.tv_sec+
366 (double)myusage.ru_utime.tv_usec/1000000.0,
367 (double)myusage.ru_stime.tv_sec+
368 (double)myusage.ru_stime.tv_usec/1000000.0,
369 (double)(currenttime.tv_sec-starttime.tv_sec)
370 +(double)(currenttime.tv_usec-starttime.tv_usec)
375 fflush(stdout); /* this is important for pipes to work */
383 else if (argc == 3 && !strcmp(argv[1],"help"))
389 if(HandleInputLine(argc, argv, stderr)) {
396 /* HandleInputLine is NOT thread safe - due to readdir issues,
397 resolving them portably is not really simple. */
398 int HandleInputLine(int argc, char **argv, FILE* out)
400 #if defined(HAVE_OPENDIR) && defined (HAVE_READDIR)
401 DIR *curdir; /* to read current dir with ls */
404 #if defined(HAVE_SYS_STAT_H)
407 optind=0; /* reset gnu getopt */
408 opterr=0; /* no error messages */
411 if (argc>1 && strcmp("quit", argv[1]) == 0){
413 printf("ERROR: invalid parameter count for quit\n");
418 #if defined(HAVE_OPENDIR) && defined(HAVE_READDIR) && defined(HAVE_CHDIR)
419 if (argc>1 && strcmp("cd", argv[1]) == 0){
421 printf("ERROR: invalid parameter count for cd\n");
424 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
425 if (getuid()==0 && ! ChangeRoot){
426 printf("ERROR: chdir security problem - rrdtool is running as "
427 "root an no chroot!\n");
433 printf("ERROR: %s\n",rrd_strerror(errno));
437 if (argc>1 && strcmp("mkdir", argv[1]) == 0){
439 printf("ERROR: invalid parameter count for mkdir\n");
442 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
443 if (getuid()==0 && ! ChangeRoot){
444 printf("ERROR: mkdir security problem - rrdtool is running as "
445 "root an no chroot!\n");
451 printf("ERROR: %s\n",rrd_strerror(errno));
455 if (argc>1 && strcmp("ls", argv[1]) == 0){
457 printf("ERROR: invalid parameter count for ls\n");
460 if ((curdir=opendir("."))!=NULL){
461 while((dent=readdir(curdir))!=NULL){
462 if (!stat(dent->d_name,&st)){
463 if (S_ISDIR(st.st_mode)){
464 printf("d %s\n",dent->d_name);
466 if (strlen(dent->d_name)>4 && S_ISREG(st.st_mode)){
467 if (!strcmp(dent->d_name+NAMLEN(dent)-4,".rrd") ||
468 !strcmp(dent->d_name+NAMLEN(dent)-4,".RRD")){
469 printf("- %s\n",dent->d_name);
476 printf("ERROR: %s\n",rrd_strerror(errno));
481 #endif /* opendir and readdir */
485 || strcmp("help", argv[1]) == 0
486 || strcmp("--help", argv[1]) == 0
487 || strcmp("-help", argv[1]) == 0
488 || strcmp("-?", argv[1]) == 0
489 || strcmp("-h", argv[1]) == 0 ) {
494 if (strcmp("create", argv[1]) == 0)
495 rrd_create(argc-1, &argv[1]);
496 else if (strcmp("dump", argv[1]) == 0)
497 rrd_dump(argc-1, &argv[1]);
498 else if (strcmp("info", argv[1]) == 0
499 || strcmp("updatev", argv[1]) == 0){
501 if (strcmp("info",argv[1]) == 0)
502 data=rrd_info(argc-1, &argv[1]);
504 data=rrd_update_v(argc-1, &argv[1]);
507 printf ("%s = ", data->key);
510 switch (data->type) {
512 if (isnan (data->value.u_val))
515 printf ("%0.10e", data->value.u_val);
518 printf ("%lu", data->value.u_cnt);
521 printf ("%d", data->value.u_int);
524 printf ("\"%s\"", data->value.u_str);
525 free(data->value.u_str);
535 else if (strcmp("--version", argv[1]) == 0 ||
536 strcmp("version", argv[1]) == 0 ||
537 strcmp("v", argv[1]) == 0 ||
538 strcmp("-v", argv[1]) == 0 ||
539 strcmp("-version", argv[1]) == 0 )
540 printf("RRDtool 1.1.x Copyright (C) 1997-2004 by Tobias Oetiker <tobi@oetiker.ch>\n");
541 else if (strcmp("restore", argv[1]) == 0)
542 rrd_restore(argc-1, &argv[1]);
543 else if (strcmp("resize", argv[1]) == 0)
544 rrd_resize(argc-1, &argv[1]);
545 else if (strcmp("last", argv[1]) == 0)
546 printf("%ld\n",rrd_last(argc-1, &argv[1]));
547 else if (strcmp("update", argv[1]) == 0)
548 rrd_update(argc-1, &argv[1]);
549 else if (strcmp("fetch", argv[1]) == 0) {
550 time_t start,end, ti;
551 unsigned long step, ds_cnt,i,ii;
552 rrd_value_t *data,*datai;
554 if (rrd_fetch(argc-1, &argv[1],&start,&end,&step,&ds_cnt,&ds_namv,&data) != -1) {
557 for (i = 0; i<ds_cnt;i++)
558 printf("%20s",ds_namv[i]);
560 for (ti = start+step; ti <= end; ti += step){
561 printf("%10lu:", ti);
562 for (ii = 0; ii < ds_cnt; ii++)
563 printf(" %0.10e", *(datai++));
566 for (i=0;i<ds_cnt;i++)
571 } else if (strcmp("xport", argv[1]) == 0) {
573 unsigned long int j = 0;
574 time_t start,end, ti;
575 unsigned long step, col_cnt,row_cnt;
576 rrd_value_t *data,*ptr;
578 if(rrd_xport(argc-1, &argv[1], &xxsize,&start,&end,&step,&col_cnt,&legend_v,&data) != -1) {
579 row_cnt = (end-start)/step;
581 printf("<?xml version=\"1.0\" encoding=\"%s\"?>\n\n", XML_ENCODING);
582 printf("<%s>\n", ROOT_TAG);
583 printf(" <%s>\n", META_TAG);
584 printf(" <%s>%lu</%s>\n", META_START_TAG, start+step, META_START_TAG);
585 printf(" <%s>%lu</%s>\n", META_STEP_TAG, step, META_STEP_TAG);
586 printf(" <%s>%lu</%s>\n", META_END_TAG, end, META_END_TAG);
587 printf(" <%s>%lu</%s>\n", META_ROWS_TAG, row_cnt, META_ROWS_TAG);
588 printf(" <%s>%lu</%s>\n", META_COLS_TAG, col_cnt, META_COLS_TAG);
589 printf(" <%s>\n", LEGEND_TAG);
590 for (j = 0; j < col_cnt; j++) {
593 printf(" <%s>%s</%s>\n", LEGEND_ENTRY_TAG, entry, LEGEND_ENTRY_TAG);
597 printf(" </%s>\n", LEGEND_TAG);
598 printf(" </%s>\n", META_TAG);
599 printf(" <%s>\n", DATA_TAG);
600 for (ti = start+step; ti <= end; ti += step) {
601 printf (" <%s>", DATA_ROW_TAG);
602 printf ("<%s>%lu</%s>", COL_TIME_TAG, ti, COL_TIME_TAG);
603 for (j = 0; j < col_cnt; j++) {
604 rrd_value_t newval = DNAN;
607 printf("<%s>NaN</%s>", COL_DATA_TAG, COL_DATA_TAG);
609 printf("<%s>%0.10e</%s>", COL_DATA_TAG, newval, COL_DATA_TAG);
613 printf("</%s>\n", DATA_ROW_TAG);
616 printf(" </%s>\n", DATA_TAG);
617 printf("</%s>\n", ROOT_TAG);
620 else if (strcmp("graph", argv[1]) == 0) {
622 #ifdef notused /*XXX*/
623 const char *imgfile = argv[2]; /* rrd_graph changes argv pointer */
627 int tostdout = (strcmp(argv[2],"-") == 0);
628 if( rrd_graph(argc-1, &argv[1], &calcpr, &xsize, &ysize, NULL) != -1 ) {
630 printf ("%dx%d\n",xsize,ysize);
632 for(i=0;calcpr[i];i++){
634 printf("%s\n",calcpr[i]);
641 } else if (strcmp("tune", argv[1]) == 0)
642 rrd_tune(argc-1, &argv[1]);
644 rrd_set_error("unknown function '%s'",argv[1]);
646 if (rrd_test_error()) {
647 fprintf(out, "ERROR: %s\n",rrd_get_error());
654 int CountArgs(char *aLine)
659 while (aLine[i] == ' ') i++;
660 while (aLine[i] != 0){
661 if((aLine[i]== ' ') && inarg){
664 if((aLine[i]!= ' ') && ! inarg){
674 * CreateArgs - take a string (aLine) and tokenize
676 int CreateArgs(char *pName, char *aLine, int argc, char **argv)
685 /* remove trailing space and newlines */
686 while (len && aLine[len] <= ' ') {
687 aLine[len] = 0 ; len--;
689 /* sikp leading blanks */
690 while (*aLine && *aLine <= ' ') aLine++;
717 pargv[argc++] = putP;
725 pargv[argc++] = putP;