1 /*****************************************************************************
2 * RRDtool 1.2rc5 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 1.2rc5 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[--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 exit(HandleInputLine(argc, argv, stderr));
403 /* HandleInputLine is NOT thread safe - due to readdir issues,
404 resolving them portably is not really simple. */
405 int HandleInputLine(int argc, char **argv, FILE* out)
407 #if defined(HAVE_OPENDIR) && defined (HAVE_READDIR)
408 DIR *curdir; /* to read current dir with ls */
411 #if defined(HAVE_SYS_STAT_H)
414 optind=0; /* reset gnu getopt */
415 opterr=0; /* no error messages */
418 if (argc>1 && strcmp("quit", argv[1]) == 0){
420 printf("ERROR: invalid parameter count for quit\n");
425 #if defined(HAVE_OPENDIR) && defined(HAVE_READDIR) && defined(HAVE_CHDIR)
426 if (argc>1 && strcmp("cd", argv[1]) == 0){
428 printf("ERROR: invalid parameter count for cd\n");
431 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
432 if (getuid()==0 && ! ChangeRoot){
433 printf("ERROR: chdir security problem - rrdtool is running as "
434 "root an no chroot!\n");
440 printf("ERROR: %s\n",rrd_strerror(errno));
444 if (argc>1 && strcmp("mkdir", argv[1]) == 0){
446 printf("ERROR: invalid parameter count for mkdir\n");
449 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
450 if (getuid()==0 && ! ChangeRoot){
451 printf("ERROR: mkdir security problem - rrdtool is running as "
452 "root an no chroot!\n");
458 printf("ERROR: %s\n",rrd_strerror(errno));
462 if (argc>1 && strcmp("ls", argv[1]) == 0){
464 printf("ERROR: invalid parameter count for ls\n");
467 if ((curdir=opendir("."))!=NULL){
468 while((dent=readdir(curdir))!=NULL){
469 if (!stat(dent->d_name,&st)){
470 if (S_ISDIR(st.st_mode)){
471 printf("d %s\n",dent->d_name);
473 if (strlen(dent->d_name)>4 && S_ISREG(st.st_mode)){
474 if (!strcmp(dent->d_name+NAMLEN(dent)-4,".rrd") ||
475 !strcmp(dent->d_name+NAMLEN(dent)-4,".RRD")){
476 printf("- %s\n",dent->d_name);
483 printf("ERROR: %s\n",rrd_strerror(errno));
488 #endif /* opendir and readdir */
492 || strcmp("help", argv[1]) == 0
493 || strcmp("--help", argv[1]) == 0
494 || strcmp("-help", argv[1]) == 0
495 || strcmp("-?", argv[1]) == 0
496 || strcmp("-h", argv[1]) == 0 ) {
501 if (strcmp("create", argv[1]) == 0)
502 rrd_create(argc-1, &argv[1]);
503 else if (strcmp("dump", argv[1]) == 0)
504 rrd_dump(argc-1, &argv[1]);
505 else if (strcmp("info", argv[1]) == 0
506 || strcmp("updatev", argv[1]) == 0){
508 if (strcmp("info",argv[1]) == 0)
509 data=rrd_info(argc-1, &argv[1]);
511 data=rrd_update_v(argc-1, &argv[1]);
514 printf ("%s = ", data->key);
517 switch (data->type) {
519 if (isnan (data->value.u_val))
522 printf ("%0.10e", data->value.u_val);
525 printf ("%lu", data->value.u_cnt);
528 printf ("%d", data->value.u_int);
531 printf ("\"%s\"", data->value.u_str);
532 free(data->value.u_str);
542 else if (strcmp("--version", argv[1]) == 0 ||
543 strcmp("version", argv[1]) == 0 ||
544 strcmp("v", argv[1]) == 0 ||
545 strcmp("-v", argv[1]) == 0 ||
546 strcmp("-version", argv[1]) == 0 )
547 printf("RRDtool 1.2rc5 Copyright by Tobi Oetiker, 1997-2005\n");
548 else if (strcmp("restore", argv[1]) == 0)
549 rrd_restore(argc-1, &argv[1]);
550 else if (strcmp("resize", argv[1]) == 0)
551 rrd_resize(argc-1, &argv[1]);
552 else if (strcmp("last", argv[1]) == 0)
553 printf("%ld\n",rrd_last(argc-1, &argv[1]));
554 else if (strcmp("first", argv[1]) == 0)
555 printf("%ld\n",rrd_first(argc-1, &argv[1]));
556 else if (strcmp("update", argv[1]) == 0)
557 rrd_update(argc-1, &argv[1]);
558 else if (strcmp("fetch", argv[1]) == 0) {
559 time_t start,end, ti;
560 unsigned long step, ds_cnt,i,ii;
561 rrd_value_t *data,*datai;
563 if (rrd_fetch(argc-1, &argv[1],&start,&end,&step,&ds_cnt,&ds_namv,&data) != -1) {
566 for (i = 0; i<ds_cnt;i++)
567 printf("%20s",ds_namv[i]);
569 for (ti = start+step; ti <= end; ti += step){
570 printf("%10lu:", ti);
571 for (ii = 0; ii < ds_cnt; ii++)
572 printf(" %0.10e", *(datai++));
575 for (i=0;i<ds_cnt;i++)
580 } else if (strcmp("xport", argv[1]) == 0) {
582 unsigned long int j = 0;
583 time_t start,end, ti;
584 unsigned long step, col_cnt,row_cnt;
585 rrd_value_t *data,*ptr;
587 if(rrd_xport(argc-1, &argv[1], &xxsize,&start,&end,&step,&col_cnt,&legend_v,&data) != -1) {
588 row_cnt = (end-start)/step;
590 printf("<?xml version=\"1.0\" encoding=\"%s\"?>\n\n", XML_ENCODING);
591 printf("<%s>\n", ROOT_TAG);
592 printf(" <%s>\n", META_TAG);
593 printf(" <%s>%lu</%s>\n", META_START_TAG, start+step, META_START_TAG);
594 printf(" <%s>%lu</%s>\n", META_STEP_TAG, step, META_STEP_TAG);
595 printf(" <%s>%lu</%s>\n", META_END_TAG, end, META_END_TAG);
596 printf(" <%s>%lu</%s>\n", META_ROWS_TAG, row_cnt, META_ROWS_TAG);
597 printf(" <%s>%lu</%s>\n", META_COLS_TAG, col_cnt, META_COLS_TAG);
598 printf(" <%s>\n", LEGEND_TAG);
599 for (j = 0; j < col_cnt; j++) {
602 printf(" <%s>%s</%s>\n", LEGEND_ENTRY_TAG, entry, LEGEND_ENTRY_TAG);
606 printf(" </%s>\n", LEGEND_TAG);
607 printf(" </%s>\n", META_TAG);
608 printf(" <%s>\n", DATA_TAG);
609 for (ti = start+step; ti <= end; ti += step) {
610 printf (" <%s>", DATA_ROW_TAG);
611 printf ("<%s>%lu</%s>", COL_TIME_TAG, ti, COL_TIME_TAG);
612 for (j = 0; j < col_cnt; j++) {
613 rrd_value_t newval = DNAN;
616 printf("<%s>NaN</%s>", COL_DATA_TAG, COL_DATA_TAG);
618 printf("<%s>%0.10e</%s>", COL_DATA_TAG, newval, COL_DATA_TAG);
622 printf("</%s>\n", DATA_ROW_TAG);
625 printf(" </%s>\n", DATA_TAG);
626 printf("</%s>\n", ROOT_TAG);
629 else if (strcmp("graph", argv[1]) == 0) {
631 #ifdef notused /*XXX*/
632 const char *imgfile = argv[2]; /* rrd_graph changes argv pointer */
637 int tostdout = (strcmp(argv[2],"-") == 0);
638 if( rrd_graph(argc-1, &argv[1], &calcpr, &xsize, &ysize, NULL, &ymin, &ymax) != -1 ) {
640 printf ("%dx%d\n",xsize,ysize);
642 for(i=0;calcpr[i];i++){
644 printf("%s\n",calcpr[i]);
651 } else if (strcmp("tune", argv[1]) == 0)
652 rrd_tune(argc-1, &argv[1]);
654 rrd_set_error("unknown function '%s'",argv[1]);
656 if (rrd_test_error()) {
657 fprintf(out, "ERROR: %s\n",rrd_get_error());
664 int CountArgs(char *aLine)
669 while (aLine[i] == ' ') i++;
670 while (aLine[i] != 0){
671 if((aLine[i]== ' ') && inarg){
674 if((aLine[i]!= ' ') && ! inarg){
684 * CreateArgs - take a string (aLine) and tokenize
686 int CreateArgs(char *pName, char *aLine, int argc, char **argv)
695 /* remove trailing space and newlines */
696 while (len && aLine[len] <= ' ') {
697 aLine[len] = 0 ; len--;
699 /* sikp leading blanks */
700 while (*aLine && *aLine <= ' ') aLine++;
727 pargv[argc++] = putP;
735 pargv[argc++] = putP;