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-2001 by Tobias Oetiker <tobi@oetiker.ch>\n\n"
26 "Usage: rrdtool [options] command command_options\n\n";
29 "Valid commands: create, update, graph, dump, restore,\n"
30 "\t\tlast, info, fetch, tune, resize, xport\n\n";
32 char help_listremote[] =
33 "Valid remote commands: quit, ls, cd, mkdir\n\n";
37 "* create - create a new RRD\n\n"
38 "\trrdtool create filename [--start|-b start time]\n"
39 "\t\t[--step|-s step]\n"
40 "\t\t[DS:ds-name:DST:dst arguments]\n"
41 "\t\t[RRA:CF:cf arguments]\n\n";
44 "* dump - dump an RRD to XML\n\n"
45 "\trrdtool dump filename.rrd >filename.xml\n\n";
48 "* info - returns the configuration and status of the RRD\n\n"
49 "\trrdtool info filename.rrd\n\n";
52 "* restore - restore an RRD file from its XML form\n\n"
53 "\trrdtool restore [--range-check|-r] filename.xml filename.rrd\n\n";
56 "* last - show last update time for RRD\n\n"
57 "\trrdtool last filename.rrd\n\n";
60 "* update - update an RRD\n\n"
61 "\trrdtool update filename\n"
62 "\t\t--template|-t ds-name:ds-name:...\n"
63 "\t\ttime|N:value[:value...]\n\n"
64 "\t\tat-time@value[:value...]\n\n"
65 "\t\t[ time:value[:value...] ..]\n\n";
68 "* fetch - fetch data out of an RRD\n\n"
69 "\trrdtool fetch filename.rrd CF\n"
70 "\t\t[--resolution|-r resolution]\n"
71 "\t\t[--start|-s start] [--end|-e end]\n\n";
74 "* graph - generate a graph from one or several RRD\n\n"
75 "\trrdtool graph filename [-s|--start seconds] [-e|--end seconds]\n"
76 "\t\t[-x|--x-grid x-axis grid and label]\n"
77 "\t\t[--alt-y-grid]\n"
78 "\t\t[-y|--y-grid y-axis grid and label]\n"
79 "\t\t[-v|--vertical-label string] [-w|--width pixels]\n"
80 "\t\t[-h|--height pixels] [-o|--logarithmic]\n"
81 "\t\t[-u|--upper-limit value] [-z|--lazy]\n"
82 "\t\t[-l|--lower-limit value] [-r|--rigid]\n"
83 "\t\t[-g|--no-legend]\n"
84 "\t\t[--font FONTTAG:size:font]\n"
85 "\t\t[--zoom factor]\n"
86 "\t\t[--alt-autoscale]\n"
87 "\t\t[--alt-autoscale-max]\n"
88 "\t\t[--units-exponent value]\n"
89 "\t\t[--step seconds]\n"
90 "\t\t[-f|--imginfo printfstr]\n"
91 "\t\t[-a|--imgformat PNG]\n"
92 "\t\t[-c|--color COLORTAG#rrggbb[aa]] [-t|--title string]\n"
93 "\t\t[DEF:vname=rrd:ds-name:CF]\n"
94 "\t\t[CDEF:vname=rpn-expression]\n"
95 "\t\t[PRINT:vname:CF:format]\n"
96 "\t\t[GPRINT:vname:CF:format]\n"
97 "\t\t[HRULE:value#rrggbb[aa][:legend]]\n"
98 "\t\t[VRULE:value#rrggbb[aa][:legend]]\n"
99 "\t\t[LINE{1|2|3}:vname[#rrggbb[aa][:legend]]]\n"
100 "\t\t[AREA:vname[#rrggbb[aa][:legend]]]\n"
101 "\t\t[STACK:vname[#rrggbb[aa][:legend]]]\n\n";
104 " * tune - Modify some basic properties of an RRD\n\n"
105 "\trrdtool tune filename\n"
106 "\t\t[--heartbeat|-h ds-name:heartbeat]\n"
107 "\t\t[--data-source-type|-d ds-name:DST]\n"
108 "\t\t[--data-source-rename|-r old-name:new-name]\n"
109 "\t\t[--minimum|-i ds-name:min] [--maximum|-a ds-name:max]\n"
110 "\t\t[--deltapos scale-value] [--deltaneg scale-value]\n"
111 "\t\t[--failure-threshold integer]\n"
112 "\t\t[--window-length integer]\n"
113 "\t\t[--alpha adaptation-parameter]\n"
114 "\t\t[--beta adaptation-parameter]\n"
115 "\t\t[--gamma adaptation-parameter]\n"
116 "\t\t[--gamma-deviation adaptation-parameter]\n"
117 "\t\t[--aberrant-reset ds-name]\n\n";
120 " * resize - alter the lenght of one of the RRAs in an RRD\n\n"
121 "\trrdtool resize filename rranum GROW|SHRINK rows\n\n";
124 "* xport - generate XML dump from one or several RRD\n\n"
125 "\trrdtool xport [-s|--start seconds] [-e|--end seconds]\n"
126 "\t\t[-m|--maxrows rows]\n"
127 "\t\t[--step seconds]\n"
128 "\t\t[DEF:vname=rrd:ds-name:CF]\n"
129 "\t\t[CDEF:vname=rpn-expression]\n"
130 "\t\t[XPORT:vname:legend]\n\n";
133 " * quit - closeing a session in remote mode\n\n"
134 "\trrdtool quit\n\n";
137 " * ls - lists all *.rrd files in current directory\n\n"
141 " * cd - changes the current directory\n\n"
142 "\trrdtool cd new direcotry\n\n";
145 " * mkdir - creates a new direcotry\n\n"
146 "\trrdtool mkdir newdirecotryname\n\n";
149 "RRDtool is distributed under the Terms of the GNU General\n"
150 "Public License Version 2. (www.gnu.org/copyleft/gpl.html)\n\n"
152 "For more information read the RRD manpages\n\n";
154 enum { C_NONE, C_CREATE, C_DUMP, C_INFO, C_RESTORE, C_LAST,
155 C_UPDATE, C_FETCH, C_GRAPH, C_TUNE, C_RESIZE, C_XPORT,
156 C_QUIT, C_LS, C_CD, C_MKDIR };
158 int help_cmd = C_NONE;
162 if (!strcmp(cmd,"create"))
164 else if (!strcmp(cmd,"dump"))
166 else if (!strcmp(cmd,"info"))
168 else if (!strcmp(cmd,"restore"))
169 help_cmd = C_RESTORE;
170 else if (!strcmp(cmd,"last"))
172 else if (!strcmp(cmd,"update"))
174 else if (!strcmp(cmd,"fetch"))
176 else if (!strcmp(cmd,"graph"))
178 else if (!strcmp(cmd,"tune"))
180 else if (!strcmp(cmd,"resize"))
182 else if (!strcmp(cmd,"xport"))
184 else if (!strcmp(cmd,"quit"))
186 else if (!strcmp(cmd,"ls"))
188 else if (!strcmp(cmd,"cd"))
190 else if (!strcmp(cmd,"mkdir"))
193 fputs(help_main, stdout);
197 fputs(help_list, stdout);
199 fputs(help_listremote, stdout);
203 fputs(help_create, stdout);
206 fputs(help_dump, stdout);
209 fputs(help_info, stdout);
212 fputs(help_restore, stdout);
215 fputs(help_last, stdout);
218 fputs(help_update, stdout);
221 fputs(help_fetch, stdout);
224 fputs(help_graph, stdout);
227 fputs(help_tune, stdout);
230 fputs(help_resize, stdout);
233 fputs(help_xport, stdout);
236 fputs(help_quit, stdout);
239 fputs(help_ls, stdout);
242 fputs(help_cd, stdout);
245 fputs(help_mkdir, stdout);
248 fputs(help_lic, stdout);
252 int main(int argc, char *argv[])
255 char aLine[MAX_LENGTH];
257 #ifdef MUST_DISABLE_SIGFPE
258 signal(SIGFPE,SIG_IGN);
260 #ifdef MUST_DISABLE_FPMASK
269 if (((argc == 2)||(argc == 3)) && !strcmp("-",argv[1]))
272 struct rusage myusage;
273 struct timeval starttime;
274 struct timeval currenttime;
277 tz.tz_minuteswest =0;
279 gettimeofday(&starttime,&tz);
283 if ((argc == 3) && strcmp("",argv[2])){
287 fprintf(stderr,"ERROR: can't change root to '%s' errno=%d\n",
298 if (strcmp(firstdir,"")){
301 fprintf(stderr,"ERROR: %s\n",strerror(errno));
306 fprintf(stderr,"ERROR: change root only in unix "
307 "enviroment posible\n");
311 while (fgets(aLine, sizeof(aLine)-1, stdin)){
312 if ((argc = CountArgs(aLine)) == 0) {
313 fprintf(stderr,"ERROR: not enough arguments\n");
315 if ((myargv = (char **) malloc((argc+1) *
316 sizeof(char *))) == NULL) {
320 if ((argc=CreateArgs(argv[0], aLine, argc, myargv)) < 0) {
321 fprintf(stderr, "ERROR: creating arguments\n");
325 if (HandleInputLine(argc, myargv, stdout))
330 getrusage(RUSAGE_SELF,&myusage);
331 gettimeofday(¤ttime,&tz);
332 printf("OK u:%1.2f s:%1.2f r:%1.2f\n",
333 (double)myusage.ru_utime.tv_sec+
334 (double)myusage.ru_utime.tv_usec/1000000.0,
335 (double)myusage.ru_stime.tv_sec+
336 (double)myusage.ru_stime.tv_usec/1000000.0,
337 (double)(currenttime.tv_sec-starttime.tv_sec)
338 +(double)(currenttime.tv_usec-starttime.tv_usec)
343 fflush(stdout); /* this is important for pipes to work */
351 else if (argc == 3 && !strcmp(argv[1],"help"))
357 HandleInputLine(argc, argv, stderr);
361 int HandleInputLine(int argc, char **argv, FILE* out)
363 DIR *curdir; /* to read current dir with ls */
366 optind=0; /* reset gnu getopt */
367 opterr=0; /* no error messages */
370 if (argc>1 && strcmp("quit", argv[1]) == 0){
372 printf("ERROR: invalid parameter count for quit\n");
377 if (argc>1 && strcmp("cd", argv[1]) == 0){
379 printf("ERROR: invalid parameter count for cd\n");
383 if (getuid()==0 && ! ChangeRoot){
384 printf("ERROR: chdir security problem - rrdtool is runnig as "
385 "root an no chroot!\n");
391 printf("ERROR: %s\n",strerror(errno));
395 if (argc>1 && strcmp("mkdir", argv[1]) == 0){
397 printf("ERROR: invalid parameter count for mkdir\n");
401 if (getuid()==0 && ! ChangeRoot){
402 printf("ERROR: mkdir security problem - rrdtool is runnig as "
403 "root an no chroot!\n");
409 printf("ERROR: %s\n",strerror(errno));
413 if (argc>1 && strcmp("ls", argv[1]) == 0){
415 printf("ERROR: invalid parameter count for ls\n");
418 if ((curdir=opendir("."))!=NULL){
419 while((dent=readdir(curdir))!=NULL){
420 if (!stat(dent->d_name,&st)){
421 if (S_ISDIR(st.st_mode)){
422 printf("d %s\n",dent->d_name);
424 if (strlen(dent->d_name)>4 && S_ISREG(st.st_mode)){
425 if (!strcmp(dent->d_name+strlen(dent->d_name)-4,".rrd") ||
426 !strcmp(dent->d_name+strlen(dent->d_name)-4,".RRD")){
427 printf("- %s\n",dent->d_name);
434 printf("ERROR: %s\n",strerror(errno));
441 || strcmp("help", argv[1]) == 0
442 || strcmp("--help", argv[1]) == 0
443 || strcmp("-help", argv[1]) == 0
444 || strcmp("-?", argv[1]) == 0
445 || strcmp("-h", argv[1]) == 0 ) {
450 if (strcmp("create", argv[1]) == 0)
451 rrd_create(argc-1, &argv[1]);
452 else if (strcmp("dump", argv[1]) == 0)
453 rrd_dump(argc-1, &argv[1]);
454 else if (strcmp("info", argv[1]) == 0){
456 data=rrd_info(argc-1, &argv[1]);
459 printf ("%s = ", data->key);
462 switch (data->type) {
464 if (isnan (data->value.u_val))
467 printf ("%0.10e", data->value.u_val);
470 printf ("%lu", data->value.u_cnt);
473 printf ("\"%s\"", data->value.u_str);
474 free(data->value.u_str);
484 else if (strcmp("--version", argv[1]) == 0 ||
485 strcmp("version", argv[1]) == 0 ||
486 strcmp("v", argv[1]) == 0 ||
487 strcmp("-v", argv[1]) == 0 ||
488 strcmp("-version", argv[1]) == 0 )
489 printf("RRDtool 1.1.x Copyright (C) 1997-2001 by Tobias Oetiker <tobi@oetiker.ch>\n");
490 else if (strcmp("restore", argv[1]) == 0)
491 rrd_restore(argc-1, &argv[1]);
492 else if (strcmp("resize", argv[1]) == 0)
493 rrd_resize(argc-1, &argv[1]);
494 else if (strcmp("last", argv[1]) == 0)
495 printf("%ld\n",rrd_last(argc-1, &argv[1]));
496 else if (strcmp("update", argv[1]) == 0)
497 rrd_update(argc-1, &argv[1]);
498 else if (strcmp("fetch", argv[1]) == 0) {
500 unsigned long step, ds_cnt,i,ii;
501 rrd_value_t *data,*datai;
503 if (rrd_fetch(argc-1, &argv[1],&start,&end,&step,&ds_cnt,&ds_namv,&data) != -1) {
506 for (i = 0; i<ds_cnt;i++)
507 printf("%14s",ds_namv[i]);
509 for (i = start+step; i <= end; i += step){
511 for (ii = 0; ii < ds_cnt; ii++)
512 printf(" %0.10e", *(datai++));
515 for (i=0;i<ds_cnt;i++)
520 } else if (strcmp("xport", argv[1]) == 0) {
524 unsigned long step, col_cnt,row_cnt;
525 rrd_value_t *data,*ptr;
527 if(rrd_xport(argc-1, &argv[1], &xxsize,&start,&end,&step,&col_cnt,&legend_v,&data) != -1) {
528 row_cnt = (end-start)/step;
530 printf("<?xml version=\"1.0\" encoding=\"%s\"?>\n\n", XML_ENCODING);
531 printf("<%s>\n", ROOT_TAG);
532 printf(" <%s>\n", META_TAG);
533 printf(" <%s>%lu</%s>\n", META_START_TAG, start+step, META_START_TAG);
534 printf(" <%s>%lu</%s>\n", META_STEP_TAG, step, META_STEP_TAG);
535 printf(" <%s>%lu</%s>\n", META_END_TAG, end, META_END_TAG);
536 printf(" <%s>%lu</%s>\n", META_ROWS_TAG, row_cnt, META_ROWS_TAG);
537 printf(" <%s>%lu</%s>\n", META_COLS_TAG, col_cnt, META_COLS_TAG);
538 printf(" <%s>\n", LEGEND_TAG);
539 for (j = 0; j < col_cnt; j++) {
542 printf(" <%s>%s</%s>\n", LEGEND_ENTRY_TAG, entry, LEGEND_ENTRY_TAG);
546 printf(" </%s>\n", LEGEND_TAG);
547 printf(" </%s>\n", META_TAG);
548 printf(" <%s>\n", DATA_TAG);
549 for (i = start+step; i <= end; i += step) {
550 printf (" <%s>", DATA_ROW_TAG);
551 printf ("<%s>%lu</%s>", COL_TIME_TAG, i, COL_TIME_TAG);
552 for (j = 0; j < col_cnt; j++) {
553 rrd_value_t newval = DNAN;
556 printf("<%s>NaN</%s>", COL_DATA_TAG, COL_DATA_TAG);
558 printf("<%s>%0.10e</%s>", COL_DATA_TAG, newval, COL_DATA_TAG);
562 printf("</%s>\n", DATA_ROW_TAG);
565 printf(" </%s>\n", DATA_TAG);
566 printf("</%s>\n", ROOT_TAG);
569 else if (strcmp("graph", argv[1]) == 0) {
571 const char *imgfile = argv[2]; /* rrd_graph changes argv pointer */
574 if( rrd_graph(argc-1, &argv[1], &calcpr, &xsize, &ysize) != -1 ) {
575 if (strcmp(imgfile,"-") != 0)
576 printf ("%dx%d\n",xsize,ysize);
578 for(i=0;calcpr[i];i++){
579 if (strcmp(imgfile,"-") != 0)
580 printf("%s\n",calcpr[i]);
587 } else if (strcmp("tune", argv[1]) == 0)
588 rrd_tune(argc-1, &argv[1]);
590 rrd_set_error("unknown function '%s'",argv[1]);
592 if (rrd_test_error()) {
593 fprintf(out, "ERROR: %s\n",rrd_get_error());
599 int CountArgs(char *aLine)
604 while (aLine[i] == ' ') i++;
605 while (aLine[i] != 0){
606 if((aLine[i]== ' ') && inarg){
609 if((aLine[i]!= ' ') && ! inarg){
619 * CreateArgs - take a string (aLine) and tokenize
621 int CreateArgs(char *pName, char *aLine, int argc, char **argv)
630 /* remove trailing space and newlines */
631 while (len && aLine[len] <= ' ') {
632 aLine[len] = 0 ; len--;
634 /* sikp leading blanks */
635 while (*aLine && *aLine <= ' ') aLine++;
662 pargv[argc++] = putP;
670 pargv[argc++] = putP;