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, 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] 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 "* fetch - fetch data out of an RRD\n\n"
74 "\trrdtool fetch filename.rrd CF\n"
75 "\t\t[--resolution|-r resolution]\n"
76 "\t\t[--start|-s start] [--end|-e end]\n\n";
79 "* graph - generate a graph from one or several RRD\n\n"
80 "\trrdtool graph filename [-s|--start seconds] [-e|--end seconds]\n"
81 "\t\t[-x|--x-grid x-axis grid and label]\n"
82 "\t\t[--alt-y-grid]\n"
83 "\t\t[-y|--y-grid y-axis grid and label]\n"
84 "\t\t[-v|--vertical-label string] [-w|--width pixels]\n"
85 "\t\t[-h|--height pixels] [-o|--logarithmic]\n"
86 "\t\t[-u|--upper-limit value] [-z|--lazy]\n"
87 "\t\t[-l|--lower-limit value] [-r|--rigid]\n"
88 "\t\t[-g|--no-legend]\n"
89 "\t\t[--font FONTTAG:size:font]\n"
90 "\t\t[--zoom factor]\n"
91 "\t\t[--alt-autoscale]\n"
92 "\t\t[--alt-autoscale-max]\n"
93 "\t\t[--units-exponent value]\n"
94 "\t\t[--step seconds]\n"
95 "\t\t[-f|--imginfo printfstr]\n"
96 "\t\t[-a|--imgformat PNG]\n"
97 "\t\t[-c|--color COLORTAG#rrggbb[aa]] [-t|--title string]\n"
98 "\t\t[DEF:vname=rrd:ds-name:CF]\n"
99 "\t\t[CDEF:vname=rpn-expression]\n"
100 "\t\t[PRINT:vname:CF:format]\n"
101 "\t\t[GPRINT:vname:CF:format]\n"
102 "\t\t[HRULE:value#rrggbb[aa][:legend]]\n"
103 "\t\t[VRULE:value#rrggbb[aa][:legend]]\n"
104 "\t\t[LINE{1|2|3}:vname[#rrggbb[aa][:legend]]]\n"
105 "\t\t[AREA:vname[#rrggbb[aa][:legend]]]\n"
106 "\t\t[STACK:vname[#rrggbb[aa][:legend]]]\n\n";
109 " * tune - Modify some basic properties of an RRD\n\n"
110 "\trrdtool tune filename\n"
111 "\t\t[--heartbeat|-h ds-name:heartbeat]\n"
112 "\t\t[--data-source-type|-d ds-name:DST]\n"
113 "\t\t[--data-source-rename|-r old-name:new-name]\n"
114 "\t\t[--minimum|-i ds-name:min] [--maximum|-a ds-name:max]\n"
115 "\t\t[--deltapos scale-value] [--deltaneg scale-value]\n"
116 "\t\t[--failure-threshold integer]\n"
117 "\t\t[--window-length integer]\n"
118 "\t\t[--alpha adaptation-parameter]\n"
119 "\t\t[--beta adaptation-parameter]\n"
120 "\t\t[--gamma adaptation-parameter]\n"
121 "\t\t[--gamma-deviation adaptation-parameter]\n"
122 "\t\t[--aberrant-reset ds-name]\n\n";
125 " * resize - alter the lenght of one of the RRAs in an RRD\n\n"
126 "\trrdtool resize filename rranum GROW|SHRINK rows\n\n";
129 "* xport - generate XML dump from one or several RRD\n\n"
130 "\trrdtool xport [-s|--start seconds] [-e|--end seconds]\n"
131 "\t\t[-m|--maxrows rows]\n"
132 "\t\t[--step seconds]\n"
133 "\t\t[DEF:vname=rrd:ds-name:CF]\n"
134 "\t\t[CDEF:vname=rpn-expression]\n"
135 "\t\t[XPORT:vname:legend]\n\n";
138 " * quit - closeing a session in remote mode\n\n"
139 "\trrdtool quit\n\n";
142 " * ls - lists all *.rrd files in current directory\n\n"
146 " * cd - changes the current directory\n\n"
147 "\trrdtool cd new direcotry\n\n";
150 " * mkdir - creates a new direcotry\n\n"
151 "\trrdtool mkdir newdirecotryname\n\n";
154 "RRDtool is distributed under the Terms of the GNU General\n"
155 "Public License Version 2. (www.gnu.org/copyleft/gpl.html)\n\n"
157 "For more information read the RRD manpages\n\n";
159 enum { C_NONE, C_CREATE, C_DUMP, C_INFO, C_RESTORE, C_LAST,
160 C_UPDATE, C_FETCH, C_GRAPH, C_TUNE, C_RESIZE, C_XPORT,
161 C_QUIT, C_LS, C_CD, C_MKDIR };
163 int help_cmd = C_NONE;
167 if (!strcmp(cmd,"create"))
169 else if (!strcmp(cmd,"dump"))
171 else if (!strcmp(cmd,"info"))
173 else if (!strcmp(cmd,"restore"))
174 help_cmd = C_RESTORE;
175 else if (!strcmp(cmd,"last"))
177 else if (!strcmp(cmd,"update"))
179 else if (!strcmp(cmd,"fetch"))
181 else if (!strcmp(cmd,"graph"))
183 else if (!strcmp(cmd,"tune"))
185 else if (!strcmp(cmd,"resize"))
187 else if (!strcmp(cmd,"xport"))
189 else if (!strcmp(cmd,"quit"))
191 else if (!strcmp(cmd,"ls"))
193 else if (!strcmp(cmd,"cd"))
195 else if (!strcmp(cmd,"mkdir"))
198 fputs(help_main, stdout);
202 fputs(help_list, stdout);
204 fputs(help_listremote, stdout);
208 fputs(help_create, stdout);
211 fputs(help_dump, stdout);
214 fputs(help_info, stdout);
217 fputs(help_restore, stdout);
220 fputs(help_last, stdout);
223 fputs(help_update, stdout);
226 fputs(help_fetch, stdout);
229 fputs(help_graph, stdout);
232 fputs(help_tune, stdout);
235 fputs(help_resize, stdout);
238 fputs(help_xport, stdout);
241 fputs(help_quit, stdout);
244 fputs(help_ls, stdout);
247 fputs(help_cd, stdout);
250 fputs(help_mkdir, stdout);
253 fputs(help_lic, stdout);
257 int main(int argc, char *argv[])
260 char aLine[MAX_LENGTH];
264 #ifdef MUST_DISABLE_SIGFPE
265 signal(SIGFPE,SIG_IGN);
267 #ifdef MUST_DISABLE_FPMASK
276 if (((argc == 2)||(argc == 3)) && !strcmp("-",argv[1]))
279 struct rusage myusage;
280 struct timeval starttime;
281 struct timeval currenttime;
284 tz.tz_minuteswest =0;
286 gettimeofday(&starttime,&tz);
290 if ((argc == 3) && strcmp("",argv[2])){
294 fprintf(stderr,"ERROR: can't change root to '%s' errno=%d\n",
305 if (strcmp(firstdir,"")){
308 fprintf(stderr,"ERROR: %s\n",strerror(errno));
313 fprintf(stderr,"ERROR: change root is not supported by your OS "
314 "or at least by this copy of rrdtool\n");
318 while (fgets(aLine, sizeof(aLine)-1, stdin)){
319 if ((argc = CountArgs(aLine)) == 0) {
320 fprintf(stderr,"ERROR: not enough arguments\n");
322 if ((myargv = (char **) malloc((argc+1) *
323 sizeof(char *))) == NULL) {
327 if ((argc=CreateArgs(argv[0], aLine, argc, myargv)) < 0) {
328 fprintf(stderr, "ERROR: creating arguments\n");
332 if (HandleInputLine(argc, myargv, stdout))
337 getrusage(RUSAGE_SELF,&myusage);
338 gettimeofday(¤ttime,&tz);
339 printf("OK u:%1.2f s:%1.2f r:%1.2f\n",
340 (double)myusage.ru_utime.tv_sec+
341 (double)myusage.ru_utime.tv_usec/1000000.0,
342 (double)myusage.ru_stime.tv_sec+
343 (double)myusage.ru_stime.tv_usec/1000000.0,
344 (double)(currenttime.tv_sec-starttime.tv_sec)
345 +(double)(currenttime.tv_usec-starttime.tv_usec)
350 fflush(stdout); /* this is important for pipes to work */
358 else if (argc == 3 && !strcmp(argv[1],"help"))
364 HandleInputLine(argc, argv, stderr);
368 /* HandleInputLine is NOT thread safe - due to readdir issues,
369 resolving them portably is not really simple. */
370 int HandleInputLine(int argc, char **argv, FILE* out)
372 #if defined(HAVE_OPENDIR) && defined (HAVE_READDIR)
373 DIR *curdir; /* to read current dir with ls */
376 #if defined(HAVE_SYS_STAT_H)
379 optind=0; /* reset gnu getopt */
380 opterr=0; /* no error messages */
383 if (argc>1 && strcmp("quit", argv[1]) == 0){
385 printf("ERROR: invalid parameter count for quit\n");
390 #if defined(HAVE_OPENDIR) && defined(HAVE_READDIR) && defined(HAVE_CHDIR)
391 if (argc>1 && strcmp("cd", argv[1]) == 0){
393 printf("ERROR: invalid parameter count for cd\n");
396 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
397 if (getuid()==0 && ! ChangeRoot){
398 printf("ERROR: chdir security problem - rrdtool is runnig as "
399 "root an no chroot!\n");
405 printf("ERROR: %s\n",strerror(errno));
409 if (argc>1 && strcmp("mkdir", argv[1]) == 0){
411 printf("ERROR: invalid parameter count for mkdir\n");
414 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
415 if (getuid()==0 && ! ChangeRoot){
416 printf("ERROR: mkdir security problem - rrdtool is runnig as "
417 "root an no chroot!\n");
423 printf("ERROR: %s\n",strerror(errno));
427 if (argc>1 && strcmp("ls", argv[1]) == 0){
429 printf("ERROR: invalid parameter count for ls\n");
432 if ((curdir=opendir("."))!=NULL){
433 while((dent=readdir(curdir))!=NULL){
434 if (!stat(dent->d_name,&st)){
435 if (S_ISDIR(st.st_mode)){
436 printf("d %s\n",dent->d_name);
438 if (strlen(dent->d_name)>4 && S_ISREG(st.st_mode)){
439 if (!strcmp(dent->d_name+NAMLEN(dent)-4,".rrd") ||
440 !strcmp(dent->d_name+NAMLEN(dent)-4,".RRD")){
441 printf("- %s\n",dent->d_name);
448 printf("ERROR: %s\n",strerror(errno));
453 #endif /* opendir and readdir */
457 || strcmp("help", argv[1]) == 0
458 || strcmp("--help", argv[1]) == 0
459 || strcmp("-help", argv[1]) == 0
460 || strcmp("-?", argv[1]) == 0
461 || strcmp("-h", argv[1]) == 0 ) {
466 if (strcmp("create", argv[1]) == 0)
467 rrd_create(argc-1, &argv[1]);
468 else if (strcmp("dump", argv[1]) == 0)
469 rrd_dump(argc-1, &argv[1]);
470 else if (strcmp("info", argv[1]) == 0){
472 data=rrd_info(argc-1, &argv[1]);
475 printf ("%s = ", data->key);
478 switch (data->type) {
480 if (isnan (data->value.u_val))
483 printf ("%0.10e", data->value.u_val);
486 printf ("%lu", data->value.u_cnt);
489 printf ("\"%s\"", data->value.u_str);
490 free(data->value.u_str);
500 else if (strcmp("--version", argv[1]) == 0 ||
501 strcmp("version", argv[1]) == 0 ||
502 strcmp("v", argv[1]) == 0 ||
503 strcmp("-v", argv[1]) == 0 ||
504 strcmp("-version", argv[1]) == 0 )
505 printf("RRDtool 1.1.x Copyright (C) 1997-2003 by Tobias Oetiker <tobi@oetiker.ch>\n");
506 else if (strcmp("restore", argv[1]) == 0)
507 rrd_restore(argc-1, &argv[1]);
508 else if (strcmp("resize", argv[1]) == 0)
509 rrd_resize(argc-1, &argv[1]);
510 else if (strcmp("last", argv[1]) == 0)
511 printf("%ld\n",rrd_last(argc-1, &argv[1]));
512 else if (strcmp("update", argv[1]) == 0)
513 rrd_update(argc-1, &argv[1]);
514 else if (strcmp("fetch", argv[1]) == 0) {
515 time_t start,end, ti;
516 unsigned long step, ds_cnt,i,ii;
517 rrd_value_t *data,*datai;
519 if (rrd_fetch(argc-1, &argv[1],&start,&end,&step,&ds_cnt,&ds_namv,&data) != -1) {
522 for (i = 0; i<ds_cnt;i++)
523 printf("%14s",ds_namv[i]);
525 for (ti = start+step; ti <= end; ti += step){
526 printf("%10lu:", ti);
527 for (ii = 0; ii < ds_cnt; ii++)
528 printf(" %0.10e", *(datai++));
531 for (i=0;i<ds_cnt;i++)
536 } else if (strcmp("xport", argv[1]) == 0) {
538 unsigned long int j = 0;
539 time_t start,end, ti;
540 unsigned long step, col_cnt,row_cnt;
541 rrd_value_t *data,*ptr;
543 if(rrd_xport(argc-1, &argv[1], &xxsize,&start,&end,&step,&col_cnt,&legend_v,&data) != -1) {
544 row_cnt = (end-start)/step;
546 printf("<?xml version=\"1.0\" encoding=\"%s\"?>\n\n", XML_ENCODING);
547 printf("<%s>\n", ROOT_TAG);
548 printf(" <%s>\n", META_TAG);
549 printf(" <%s>%lu</%s>\n", META_START_TAG, start+step, META_START_TAG);
550 printf(" <%s>%lu</%s>\n", META_STEP_TAG, step, META_STEP_TAG);
551 printf(" <%s>%lu</%s>\n", META_END_TAG, end, META_END_TAG);
552 printf(" <%s>%lu</%s>\n", META_ROWS_TAG, row_cnt, META_ROWS_TAG);
553 printf(" <%s>%lu</%s>\n", META_COLS_TAG, col_cnt, META_COLS_TAG);
554 printf(" <%s>\n", LEGEND_TAG);
555 for (j = 0; j < col_cnt; j++) {
558 printf(" <%s>%s</%s>\n", LEGEND_ENTRY_TAG, entry, LEGEND_ENTRY_TAG);
562 printf(" </%s>\n", LEGEND_TAG);
563 printf(" </%s>\n", META_TAG);
564 printf(" <%s>\n", DATA_TAG);
565 for (ti = start+step; ti <= end; ti += step) {
566 printf (" <%s>", DATA_ROW_TAG);
567 printf ("<%s>%lu</%s>", COL_TIME_TAG, ti, COL_TIME_TAG);
568 for (j = 0; j < col_cnt; j++) {
569 rrd_value_t newval = DNAN;
572 printf("<%s>NaN</%s>", COL_DATA_TAG, COL_DATA_TAG);
574 printf("<%s>%0.10e</%s>", COL_DATA_TAG, newval, COL_DATA_TAG);
578 printf("</%s>\n", DATA_ROW_TAG);
581 printf(" </%s>\n", DATA_TAG);
582 printf("</%s>\n", ROOT_TAG);
585 else if (strcmp("graph", argv[1]) == 0) {
587 const char *imgfile = argv[2]; /* rrd_graph changes argv pointer */
590 int tostdout = (strcmp(argv[2],"-") == 0);
591 if( rrd_graph(argc-1, &argv[1], &calcpr, &xsize, &ysize) != -1 ) {
593 printf ("%dx%d\n",xsize,ysize);
595 for(i=0;calcpr[i];i++){
597 printf("%s\n",calcpr[i]);
604 } else if (strcmp("tune", argv[1]) == 0)
605 rrd_tune(argc-1, &argv[1]);
607 rrd_set_error("unknown function '%s'",argv[1]);
609 if (rrd_test_error()) {
610 fprintf(out, "ERROR: %s\n",rrd_get_error());
616 int CountArgs(char *aLine)
621 while (aLine[i] == ' ') i++;
622 while (aLine[i] != 0){
623 if((aLine[i]== ' ') && inarg){
626 if((aLine[i]!= ' ') && ! inarg){
636 * CreateArgs - take a string (aLine) and tokenize
638 int CreateArgs(char *pName, char *aLine, int argc, char **argv)
647 /* remove trailing space and newlines */
648 while (len && aLine[len] <= ' ') {
649 aLine[len] = 0 ; len--;
651 /* sikp leading blanks */
652 while (*aLine && *aLine <= ' ') aLine++;
679 pargv[argc++] = putP;
687 pargv[argc++] = putP;