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];
259 #ifdef MUST_DISABLE_SIGFPE
260 signal(SIGFPE,SIG_IGN);
262 #ifdef MUST_DISABLE_FPMASK
271 if (((argc == 2)||(argc == 3)) && !strcmp("-",argv[1]))
274 struct rusage myusage;
275 struct timeval starttime;
276 struct timeval currenttime;
279 tz.tz_minuteswest =0;
281 gettimeofday(&starttime,&tz);
285 if ((argc == 3) && strcmp("",argv[2])){
289 fprintf(stderr,"ERROR: can't change root to '%s' errno=%d\n",
300 if (strcmp(firstdir,"")){
303 fprintf(stderr,"ERROR: %s\n",strerror(errno));
308 fprintf(stderr,"ERROR: change root is not supported by your OS "
309 "or at least by this copy of rrdtool\n");
313 while (fgets(aLine, sizeof(aLine)-1, stdin)){
314 if ((argc = CountArgs(aLine)) == 0) {
315 fprintf(stderr,"ERROR: not enough arguments\n");
317 if ((myargv = (char **) malloc((argc+1) *
318 sizeof(char *))) == NULL) {
322 if ((argc=CreateArgs(argv[0], aLine, argc, myargv)) < 0) {
323 fprintf(stderr, "ERROR: creating arguments\n");
327 if (HandleInputLine(argc, myargv, stdout))
332 getrusage(RUSAGE_SELF,&myusage);
333 gettimeofday(¤ttime,&tz);
334 printf("OK u:%1.2f s:%1.2f r:%1.2f\n",
335 (double)myusage.ru_utime.tv_sec+
336 (double)myusage.ru_utime.tv_usec/1000000.0,
337 (double)myusage.ru_stime.tv_sec+
338 (double)myusage.ru_stime.tv_usec/1000000.0,
339 (double)(currenttime.tv_sec-starttime.tv_sec)
340 +(double)(currenttime.tv_usec-starttime.tv_usec)
345 fflush(stdout); /* this is important for pipes to work */
353 else if (argc == 3 && !strcmp(argv[1],"help"))
359 HandleInputLine(argc, argv, stderr);
363 /* HandleInputLine is NOT thread safe - due to readdir issues,
364 resolving them portably is not really simple. */
365 int HandleInputLine(int argc, char **argv, FILE* out)
367 #if defined(HAVE_OPENDIR) && defined (HAVE_READDIR)
368 DIR *curdir; /* to read current dir with ls */
371 #if defined(HAVE_SYS_STAT_H)
374 optind=0; /* reset gnu getopt */
375 opterr=0; /* no error messages */
378 if (argc>1 && strcmp("quit", argv[1]) == 0){
380 printf("ERROR: invalid parameter count for quit\n");
385 #if defined(HAVE_OPENDIR) && defined(HAVE_READDIR) && defined(HAVE_CHDIR)
386 if (argc>1 && strcmp("cd", argv[1]) == 0){
388 printf("ERROR: invalid parameter count for cd\n");
391 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
392 if (getuid()==0 && ! ChangeRoot){
393 printf("ERROR: chdir security problem - rrdtool is runnig as "
394 "root an no chroot!\n");
400 printf("ERROR: %s\n",strerror(errno));
404 if (argc>1 && strcmp("mkdir", argv[1]) == 0){
406 printf("ERROR: invalid parameter count for mkdir\n");
409 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
410 if (getuid()==0 && ! ChangeRoot){
411 printf("ERROR: mkdir security problem - rrdtool is runnig as "
412 "root an no chroot!\n");
418 printf("ERROR: %s\n",strerror(errno));
422 if (argc>1 && strcmp("ls", argv[1]) == 0){
424 printf("ERROR: invalid parameter count for ls\n");
427 if ((curdir=opendir("."))!=NULL){
428 while((dent=readdir(curdir))!=NULL){
429 if (!stat(dent->d_name,&st)){
430 if (S_ISDIR(st.st_mode)){
431 printf("d %s\n",dent->d_name);
433 if (strlen(dent->d_name)>4 && S_ISREG(st.st_mode)){
434 if (!strcmp(dent->d_name+NAMLEN(dent)-4,".rrd") ||
435 !strcmp(dent->d_name+NAMLEN(dent)-4,".RRD")){
436 printf("- %s\n",dent->d_name);
443 printf("ERROR: %s\n",strerror(errno));
448 #endif /* opendir and readdir */
452 || strcmp("help", argv[1]) == 0
453 || strcmp("--help", argv[1]) == 0
454 || strcmp("-help", argv[1]) == 0
455 || strcmp("-?", argv[1]) == 0
456 || strcmp("-h", argv[1]) == 0 ) {
461 if (strcmp("create", argv[1]) == 0)
462 rrd_create(argc-1, &argv[1]);
463 else if (strcmp("dump", argv[1]) == 0)
464 rrd_dump(argc-1, &argv[1]);
465 else if (strcmp("info", argv[1]) == 0){
467 data=rrd_info(argc-1, &argv[1]);
470 printf ("%s = ", data->key);
473 switch (data->type) {
475 if (isnan (data->value.u_val))
478 printf ("%0.10e", data->value.u_val);
481 printf ("%lu", data->value.u_cnt);
484 printf ("\"%s\"", data->value.u_str);
485 free(data->value.u_str);
495 else if (strcmp("--version", argv[1]) == 0 ||
496 strcmp("version", argv[1]) == 0 ||
497 strcmp("v", argv[1]) == 0 ||
498 strcmp("-v", argv[1]) == 0 ||
499 strcmp("-version", argv[1]) == 0 )
500 printf("RRDtool 1.1.x Copyright (C) 1997-2001 by Tobias Oetiker <tobi@oetiker.ch>\n");
501 else if (strcmp("restore", argv[1]) == 0)
502 rrd_restore(argc-1, &argv[1]);
503 else if (strcmp("resize", argv[1]) == 0)
504 rrd_resize(argc-1, &argv[1]);
505 else if (strcmp("last", argv[1]) == 0)
506 printf("%ld\n",rrd_last(argc-1, &argv[1]));
507 else if (strcmp("update", argv[1]) == 0)
508 rrd_update(argc-1, &argv[1]);
509 else if (strcmp("fetch", argv[1]) == 0) {
510 time_t start,end, ti;
511 unsigned long step, ds_cnt,i,ii;
512 rrd_value_t *data,*datai;
514 if (rrd_fetch(argc-1, &argv[1],&start,&end,&step,&ds_cnt,&ds_namv,&data) != -1) {
517 for (i = 0; i<ds_cnt;i++)
518 printf("%14s",ds_namv[i]);
520 for (ti = start+step; ti <= end; ti += step){
521 printf("%10lu:", ti);
522 for (ii = 0; ii < ds_cnt; ii++)
523 printf(" %0.10e", *(datai++));
526 for (i=0;i<ds_cnt;i++)
531 } else if (strcmp("xport", argv[1]) == 0) {
533 unsigned long int j = 0;
534 time_t start,end, ti;
535 unsigned long step, col_cnt,row_cnt;
536 rrd_value_t *data,*ptr;
538 if(rrd_xport(argc-1, &argv[1], &xxsize,&start,&end,&step,&col_cnt,&legend_v,&data) != -1) {
539 row_cnt = (end-start)/step;
541 printf("<?xml version=\"1.0\" encoding=\"%s\"?>\n\n", XML_ENCODING);
542 printf("<%s>\n", ROOT_TAG);
543 printf(" <%s>\n", META_TAG);
544 printf(" <%s>%lu</%s>\n", META_START_TAG, start+step, META_START_TAG);
545 printf(" <%s>%lu</%s>\n", META_STEP_TAG, step, META_STEP_TAG);
546 printf(" <%s>%lu</%s>\n", META_END_TAG, end, META_END_TAG);
547 printf(" <%s>%lu</%s>\n", META_ROWS_TAG, row_cnt, META_ROWS_TAG);
548 printf(" <%s>%lu</%s>\n", META_COLS_TAG, col_cnt, META_COLS_TAG);
549 printf(" <%s>\n", LEGEND_TAG);
550 for (j = 0; j < col_cnt; j++) {
553 printf(" <%s>%s</%s>\n", LEGEND_ENTRY_TAG, entry, LEGEND_ENTRY_TAG);
557 printf(" </%s>\n", LEGEND_TAG);
558 printf(" </%s>\n", META_TAG);
559 printf(" <%s>\n", DATA_TAG);
560 for (ti = start+step; ti <= end; ti += step) {
561 printf (" <%s>", DATA_ROW_TAG);
562 printf ("<%s>%lu</%s>", COL_TIME_TAG, ti, COL_TIME_TAG);
563 for (j = 0; j < col_cnt; j++) {
564 rrd_value_t newval = DNAN;
567 printf("<%s>NaN</%s>", COL_DATA_TAG, COL_DATA_TAG);
569 printf("<%s>%0.10e</%s>", COL_DATA_TAG, newval, COL_DATA_TAG);
573 printf("</%s>\n", DATA_ROW_TAG);
576 printf(" </%s>\n", DATA_TAG);
577 printf("</%s>\n", ROOT_TAG);
580 else if (strcmp("graph", argv[1]) == 0) {
582 const char *imgfile = argv[2]; /* rrd_graph changes argv pointer */
585 if( rrd_graph(argc-1, &argv[1], &calcpr, &xsize, &ysize) != -1 ) {
586 if (strcmp(imgfile,"-") != 0)
587 printf ("%dx%d\n",xsize,ysize);
589 for(i=0;calcpr[i];i++){
590 if (strcmp(imgfile,"-") != 0)
591 printf("%s\n",calcpr[i]);
598 } else if (strcmp("tune", argv[1]) == 0)
599 rrd_tune(argc-1, &argv[1]);
601 rrd_set_error("unknown function '%s'",argv[1]);
603 if (rrd_test_error()) {
604 fprintf(out, "ERROR: %s\n",rrd_get_error());
610 int CountArgs(char *aLine)
615 while (aLine[i] == ' ') i++;
616 while (aLine[i] != 0){
617 if((aLine[i]== ' ') && inarg){
620 if((aLine[i]!= ' ') && ! inarg){
630 * CreateArgs - take a string (aLine) and tokenize
632 int CreateArgs(char *pName, char *aLine, int argc, char **argv)
641 /* remove trailing space and newlines */
642 while (len && aLine[len] <= ' ') {
643 aLine[len] = 0 ; len--;
645 /* sikp leading blanks */
646 while (*aLine && *aLine <= ' ') aLine++;
673 pargv[argc++] = putP;
681 pargv[argc++] = putP;