1 /*****************************************************************************
2 * RRDtool 1.1.x Copyright Tobias Oetiker, 1997 - 2002
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-2003 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 verion 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";
88 "* graph - generate a graph from one or several RRD\n\n"
89 "\trrdtool graph filename [-s|--start seconds] [-e|--end seconds]\n"
90 "\t\t[-x|--x-grid x-axis grid and label]\n"
91 "\t\t[--alt-y-grid]\n"
92 "\t\t[-y|--y-grid y-axis grid and label]\n"
93 "\t\t[-v|--vertical-label string] [-w|--width pixels]\n"
94 "\t\t[-h|--height pixels] [-o|--logarithmic]\n"
95 "\t\t[-u|--upper-limit value] [-z|--lazy]\n"
96 "\t\t[-l|--lower-limit value] [-r|--rigid]\n"
97 "\t\t[-g|--no-legend]\n"
98 "\t\t[-j|--only-graph]\n"
99 "\t\t[--font FONTTAG:size:font]\n"
100 "\t\t[--zoom factor]\n"
101 "\t\t[--alt-autoscale]\n"
102 "\t\t[--alt-autoscale-max]\n"
103 "\t\t[--units-exponent value]\n"
104 "\t\t[--step seconds]\n"
105 "\t\t[-f|--imginfo printfstr]\n"
106 "\t\t[-a|--imgformat PNG]\n"
107 "\t\t[-c|--color COLORTAG#rrggbb[aa]] [-t|--title string]\n"
108 "\t\t[DEF:vname=rrd:ds-name:CF]\n"
109 "\t\t[CDEF:vname=rpn-expression]\n"
110 "\t\t[PRINT:vname:CF:format]\n"
111 "\t\t[GPRINT:vname:CF:format]\n"
112 "\t\t[HRULE:value#rrggbb[aa][:legend]]\n"
113 "\t\t[VRULE:value#rrggbb[aa][:legend]]\n"
114 "\t\t[LINE{1|2|3}:vname[#rrggbb[aa][:legend]]]\n"
115 "\t\t[AREA:vname[#rrggbb[aa][:legend]]]\n"
116 "\t\t[STACK:vname[#rrggbb[aa][:legend]]]\n\n";
119 " * tune - Modify some basic properties of an RRD\n\n"
120 "\trrdtool tune filename\n"
121 "\t\t[--heartbeat|-h ds-name:heartbeat]\n"
122 "\t\t[--data-source-type|-d ds-name:DST]\n"
123 "\t\t[--data-source-rename|-r old-name:new-name]\n"
124 "\t\t[--minimum|-i ds-name:min] [--maximum|-a ds-name:max]\n"
125 "\t\t[--deltapos scale-value] [--deltaneg scale-value]\n"
126 "\t\t[--failure-threshold integer]\n"
127 "\t\t[--window-length integer]\n"
128 "\t\t[--alpha adaptation-parameter]\n"
129 "\t\t[--beta adaptation-parameter]\n"
130 "\t\t[--gamma adaptation-parameter]\n"
131 "\t\t[--gamma-deviation adaptation-parameter]\n"
132 "\t\t[--aberrant-reset ds-name]\n\n";
135 " * resize - alter the lenght of one of the RRAs in an RRD\n\n"
136 "\trrdtool resize filename rranum GROW|SHRINK rows\n\n";
139 "* xport - generate XML dump from one or several RRD\n\n"
140 "\trrdtool xport [-s|--start seconds] [-e|--end seconds]\n"
141 "\t\t[-m|--maxrows rows]\n"
142 "\t\t[--step seconds]\n"
143 "\t\t[DEF:vname=rrd:ds-name:CF]\n"
144 "\t\t[CDEF:vname=rpn-expression]\n"
145 "\t\t[XPORT:vname:legend]\n\n";
148 " * quit - closeing a session in remote mode\n\n"
149 "\trrdtool quit\n\n";
152 " * ls - lists all *.rrd files in current directory\n\n"
156 " * cd - changes the current directory\n\n"
157 "\trrdtool cd new direcotry\n\n";
160 " * mkdir - creates a new direcotry\n\n"
161 "\trrdtool mkdir newdirecotryname\n\n";
164 "RRDtool is distributed under the Terms of the GNU General\n"
165 "Public License Version 2. (www.gnu.org/copyleft/gpl.html)\n\n"
167 "For more information read the RRD manpages\n\n";
169 enum { C_NONE, C_CREATE, C_DUMP, C_INFO, C_RESTORE, C_LAST,
170 C_UPDATE, C_FETCH, C_GRAPH, C_TUNE, C_RESIZE, C_XPORT,
171 C_QUIT, C_LS, C_CD, C_MKDIR, C_UPDATEV };
173 int help_cmd = C_NONE;
177 if (!strcmp(cmd,"create"))
179 else if (!strcmp(cmd,"dump"))
181 else if (!strcmp(cmd,"info"))
183 else if (!strcmp(cmd,"restore"))
184 help_cmd = C_RESTORE;
185 else if (!strcmp(cmd,"last"))
187 else if (!strcmp(cmd,"update"))
189 else if (!strcmp(cmd,"updatev"))
190 help_cmd = C_UPDATEV;
191 else if (!strcmp(cmd,"fetch"))
193 else if (!strcmp(cmd,"graph"))
195 else if (!strcmp(cmd,"tune"))
197 else if (!strcmp(cmd,"resize"))
199 else if (!strcmp(cmd,"xport"))
201 else if (!strcmp(cmd,"quit"))
203 else if (!strcmp(cmd,"ls"))
205 else if (!strcmp(cmd,"cd"))
207 else if (!strcmp(cmd,"mkdir"))
210 fputs(help_main, stdout);
214 fputs(help_list, stdout);
216 fputs(help_listremote, stdout);
220 fputs(help_create, stdout);
223 fputs(help_dump, stdout);
226 fputs(help_info, stdout);
229 fputs(help_restore, stdout);
232 fputs(help_last, stdout);
235 fputs(help_update, stdout);
238 fputs(help_updatev, stdout);
241 fputs(help_fetch, stdout);
244 fputs(help_graph, stdout);
247 fputs(help_tune, stdout);
250 fputs(help_resize, stdout);
253 fputs(help_xport, stdout);
256 fputs(help_quit, stdout);
259 fputs(help_ls, stdout);
262 fputs(help_cd, stdout);
265 fputs(help_mkdir, stdout);
268 fputs(help_lic, stdout);
272 int main(int argc, char *argv[])
275 char aLine[MAX_LENGTH];
279 #ifdef MUST_DISABLE_SIGFPE
280 signal(SIGFPE,SIG_IGN);
282 #ifdef MUST_DISABLE_FPMASK
291 if (((argc == 2)||(argc == 3)) && !strcmp("-",argv[1]))
294 struct rusage myusage;
295 struct timeval starttime;
296 struct timeval currenttime;
299 tz.tz_minuteswest =0;
301 gettimeofday(&starttime,&tz);
305 if ((argc == 3) && strcmp("",argv[2])){
309 fprintf(stderr,"ERROR: can't change root to '%s' errno=%d\n",
320 if (strcmp(firstdir,"")){
323 fprintf(stderr,"ERROR: %s\n",strerror(errno));
328 fprintf(stderr,"ERROR: change root is not supported by your OS "
329 "or at least by this copy of rrdtool\n");
333 while (fgets(aLine, sizeof(aLine)-1, stdin)){
334 if ((argc = CountArgs(aLine)) == 0) {
335 fprintf(stderr,"ERROR: not enough arguments\n");
337 if ((myargv = (char **) malloc((argc+1) *
338 sizeof(char *))) == NULL) {
342 if ((argc=CreateArgs(argv[0], aLine, argc, myargv)) < 0) {
343 fprintf(stderr, "ERROR: creating arguments\n");
347 if (HandleInputLine(argc, myargv, stdout))
352 getrusage(RUSAGE_SELF,&myusage);
353 gettimeofday(¤ttime,&tz);
354 printf("OK u:%1.2f s:%1.2f r:%1.2f\n",
355 (double)myusage.ru_utime.tv_sec+
356 (double)myusage.ru_utime.tv_usec/1000000.0,
357 (double)myusage.ru_stime.tv_sec+
358 (double)myusage.ru_stime.tv_usec/1000000.0,
359 (double)(currenttime.tv_sec-starttime.tv_sec)
360 +(double)(currenttime.tv_usec-starttime.tv_usec)
365 fflush(stdout); /* this is important for pipes to work */
373 else if (argc == 3 && !strcmp(argv[1],"help"))
379 HandleInputLine(argc, argv, stderr);
383 /* HandleInputLine is NOT thread safe - due to readdir issues,
384 resolving them portably is not really simple. */
385 int HandleInputLine(int argc, char **argv, FILE* out)
387 #if defined(HAVE_OPENDIR) && defined (HAVE_READDIR)
388 DIR *curdir; /* to read current dir with ls */
391 #if defined(HAVE_SYS_STAT_H)
394 optind=0; /* reset gnu getopt */
395 opterr=0; /* no error messages */
398 if (argc>1 && strcmp("quit", argv[1]) == 0){
400 printf("ERROR: invalid parameter count for quit\n");
405 #if defined(HAVE_OPENDIR) && defined(HAVE_READDIR) && defined(HAVE_CHDIR)
406 if (argc>1 && strcmp("cd", argv[1]) == 0){
408 printf("ERROR: invalid parameter count for cd\n");
411 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
412 if (getuid()==0 && ! ChangeRoot){
413 printf("ERROR: chdir security problem - rrdtool is runnig as "
414 "root an no chroot!\n");
420 printf("ERROR: %s\n",strerror(errno));
424 if (argc>1 && strcmp("mkdir", argv[1]) == 0){
426 printf("ERROR: invalid parameter count for mkdir\n");
429 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
430 if (getuid()==0 && ! ChangeRoot){
431 printf("ERROR: mkdir security problem - rrdtool is runnig as "
432 "root an no chroot!\n");
438 printf("ERROR: %s\n",strerror(errno));
442 if (argc>1 && strcmp("ls", argv[1]) == 0){
444 printf("ERROR: invalid parameter count for ls\n");
447 if ((curdir=opendir("."))!=NULL){
448 while((dent=readdir(curdir))!=NULL){
449 if (!stat(dent->d_name,&st)){
450 if (S_ISDIR(st.st_mode)){
451 printf("d %s\n",dent->d_name);
453 if (strlen(dent->d_name)>4 && S_ISREG(st.st_mode)){
454 if (!strcmp(dent->d_name+NAMLEN(dent)-4,".rrd") ||
455 !strcmp(dent->d_name+NAMLEN(dent)-4,".RRD")){
456 printf("- %s\n",dent->d_name);
463 printf("ERROR: %s\n",strerror(errno));
468 #endif /* opendir and readdir */
472 || strcmp("help", argv[1]) == 0
473 || strcmp("--help", argv[1]) == 0
474 || strcmp("-help", argv[1]) == 0
475 || strcmp("-?", argv[1]) == 0
476 || strcmp("-h", argv[1]) == 0 ) {
481 if (strcmp("create", argv[1]) == 0)
482 rrd_create(argc-1, &argv[1]);
483 else if (strcmp("dump", argv[1]) == 0)
484 rrd_dump(argc-1, &argv[1]);
485 else if (strcmp("info", argv[1]) == 0
486 || strcmp("updatev", argv[1]) == 0){
488 if (strcmp("info",argv[1]) == 0)
489 data=rrd_info(argc-1, &argv[1]);
491 data=rrd_update_v(argc-1, &argv[1]);
494 printf ("%s = ", data->key);
497 switch (data->type) {
499 if (isnan (data->value.u_val))
502 printf ("%0.10e", data->value.u_val);
505 printf ("%lu", data->value.u_cnt);
508 printf ("%d", data->value.u_int);
511 printf ("\"%s\"", data->value.u_str);
512 free(data->value.u_str);
522 else if (strcmp("--version", argv[1]) == 0 ||
523 strcmp("version", argv[1]) == 0 ||
524 strcmp("v", argv[1]) == 0 ||
525 strcmp("-v", argv[1]) == 0 ||
526 strcmp("-version", argv[1]) == 0 )
527 printf("RRDtool 1.1.x Copyright (C) 1997-2003 by Tobias Oetiker <tobi@oetiker.ch>\n");
528 else if (strcmp("restore", argv[1]) == 0)
529 rrd_restore(argc-1, &argv[1]);
530 else if (strcmp("resize", argv[1]) == 0)
531 rrd_resize(argc-1, &argv[1]);
532 else if (strcmp("last", argv[1]) == 0)
533 printf("%ld\n",rrd_last(argc-1, &argv[1]));
534 else if (strcmp("update", argv[1]) == 0)
535 rrd_update(argc-1, &argv[1]);
536 else if (strcmp("fetch", argv[1]) == 0) {
537 time_t start,end, ti;
538 unsigned long step, ds_cnt,i,ii;
539 rrd_value_t *data,*datai;
541 if (rrd_fetch(argc-1, &argv[1],&start,&end,&step,&ds_cnt,&ds_namv,&data) != -1) {
544 for (i = 0; i<ds_cnt;i++)
545 printf("%20s",ds_namv[i]);
547 for (ti = start+step; ti <= end; ti += step){
548 printf("%10lu:", ti);
549 for (ii = 0; ii < ds_cnt; ii++)
550 printf(" %0.10e", *(datai++));
553 for (i=0;i<ds_cnt;i++)
558 } else if (strcmp("xport", argv[1]) == 0) {
560 unsigned long int j = 0;
561 time_t start,end, ti;
562 unsigned long step, col_cnt,row_cnt;
563 rrd_value_t *data,*ptr;
565 if(rrd_xport(argc-1, &argv[1], &xxsize,&start,&end,&step,&col_cnt,&legend_v,&data) != -1) {
566 row_cnt = (end-start)/step;
568 printf("<?xml version=\"1.0\" encoding=\"%s\"?>\n\n", XML_ENCODING);
569 printf("<%s>\n", ROOT_TAG);
570 printf(" <%s>\n", META_TAG);
571 printf(" <%s>%lu</%s>\n", META_START_TAG, start+step, META_START_TAG);
572 printf(" <%s>%lu</%s>\n", META_STEP_TAG, step, META_STEP_TAG);
573 printf(" <%s>%lu</%s>\n", META_END_TAG, end, META_END_TAG);
574 printf(" <%s>%lu</%s>\n", META_ROWS_TAG, row_cnt, META_ROWS_TAG);
575 printf(" <%s>%lu</%s>\n", META_COLS_TAG, col_cnt, META_COLS_TAG);
576 printf(" <%s>\n", LEGEND_TAG);
577 for (j = 0; j < col_cnt; j++) {
580 printf(" <%s>%s</%s>\n", LEGEND_ENTRY_TAG, entry, LEGEND_ENTRY_TAG);
584 printf(" </%s>\n", LEGEND_TAG);
585 printf(" </%s>\n", META_TAG);
586 printf(" <%s>\n", DATA_TAG);
587 for (ti = start+step; ti <= end; ti += step) {
588 printf (" <%s>", DATA_ROW_TAG);
589 printf ("<%s>%lu</%s>", COL_TIME_TAG, ti, COL_TIME_TAG);
590 for (j = 0; j < col_cnt; j++) {
591 rrd_value_t newval = DNAN;
594 printf("<%s>NaN</%s>", COL_DATA_TAG, COL_DATA_TAG);
596 printf("<%s>%0.10e</%s>", COL_DATA_TAG, newval, COL_DATA_TAG);
600 printf("</%s>\n", DATA_ROW_TAG);
603 printf(" </%s>\n", DATA_TAG);
604 printf("</%s>\n", ROOT_TAG);
607 else if (strcmp("graph", argv[1]) == 0) {
609 const char *imgfile = argv[2]; /* rrd_graph changes argv pointer */
612 int tostdout = (strcmp(argv[2],"-") == 0);
613 if( rrd_graph(argc-1, &argv[1], &calcpr, &xsize, &ysize, NULL) != -1 ) {
615 printf ("%dx%d\n",xsize,ysize);
617 for(i=0;calcpr[i];i++){
619 printf("%s\n",calcpr[i]);
626 } else if (strcmp("tune", argv[1]) == 0)
627 rrd_tune(argc-1, &argv[1]);
629 rrd_set_error("unknown function '%s'",argv[1]);
631 if (rrd_test_error()) {
632 fprintf(out, "ERROR: %s\n",rrd_get_error());
638 int CountArgs(char *aLine)
643 while (aLine[i] == ' ') i++;
644 while (aLine[i] != 0){
645 if((aLine[i]== ' ') && inarg){
648 if((aLine[i]!= ' ') && ! inarg){
658 * CreateArgs - take a string (aLine) and tokenize
660 int CreateArgs(char *pName, char *aLine, int argc, char **argv)
669 /* remove trailing space and newlines */
670 while (len && aLine[len] <= ' ') {
671 aLine[len] = 0 ; len--;
673 /* sikp leading blanks */
674 while (*aLine && *aLine <= ' ') aLine++;
701 pargv[argc++] = putP;
709 pargv[argc++] = putP;