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"
26 " Compiled " MAKE_TIMESTAMP "\n\n"
27 "Usage: rrdtool [options] command command_options\n\n";
30 "Valid commands: create, update, graph, dump, restore,\n"
31 "\t\tlast, info, fetch, tune, resize, xport\n\n";
33 char help_listremote[] =
34 "Valid remote commands: quit, ls, cd, mkdir\n\n";
38 "* create - create a new RRD\n\n"
39 "\trrdtool create filename [--start|-b start time]\n"
40 "\t\t[--step|-s step]\n"
41 "\t\t[DS:ds-name:DST:dst arguments]\n"
42 "\t\t[RRA:CF:cf arguments]\n\n";
45 "* dump - dump an RRD to XML\n\n"
46 "\trrdtool dump filename.rrd >filename.xml\n\n";
49 "* info - returns the configuration and status of the RRD\n\n"
50 "\trrdtool info filename.rrd\n\n";
53 "* restore - restore an RRD file from its XML form\n\n"
54 "\trrdtool restore [--range-check|-r] filename.xml filename.rrd\n\n";
57 "* last - show last update time for RRD\n\n"
58 "\trrdtool last filename.rrd\n\n";
61 "* update - update an RRD\n\n"
62 "\trrdtool update filename\n"
63 "\t\t--template|-t ds-name:ds-name:...\n"
64 "\t\ttime|N:value[:value...]\n\n"
65 "\t\tat-time@value[:value...]\n\n"
66 "\t\t[ time:value[:value...] ..]\n\n";
69 "* fetch - fetch data out of an RRD\n\n"
70 "\trrdtool fetch filename.rrd CF\n"
71 "\t\t[--resolution|-r resolution]\n"
72 "\t\t[--start|-s start] [--end|-e end]\n\n";
75 "* graph - generate a graph from one or several RRD\n\n"
76 "\trrdtool graph filename [-s|--start seconds] [-e|--end seconds]\n"
77 "\t\t[-x|--x-grid x-axis grid and label]\n"
78 "\t\t[--alt-y-grid]\n"
79 "\t\t[-y|--y-grid y-axis grid and label]\n"
80 "\t\t[-v|--vertical-label string] [-w|--width pixels]\n"
81 "\t\t[-h|--height pixels] [-o|--logarithmic]\n"
82 "\t\t[-u|--upper-limit value] [-z|--lazy]\n"
83 "\t\t[-l|--lower-limit value] [-r|--rigid]\n"
84 "\t\t[-g|--no-legend]\n"
85 "\t\t[--font FONTTAG:size:font]\n"
86 "\t\t[--zoom factor]\n"
87 "\t\t[--alt-autoscale]\n"
88 "\t\t[--alt-autoscale-max]\n"
89 "\t\t[--units-exponent value]\n"
90 "\t\t[--step seconds]\n"
91 "\t\t[-f|--imginfo printfstr]\n"
92 "\t\t[-a|--imgformat PNG]\n"
93 "\t\t[-c|--color COLORTAG#rrggbb[aa]] [-t|--title string]\n"
94 "\t\t[DEF:vname=rrd:ds-name:CF]\n"
95 "\t\t[CDEF:vname=rpn-expression]\n"
96 "\t\t[PRINT:vname:CF:format]\n"
97 "\t\t[GPRINT:vname:CF:format]\n"
98 "\t\t[HRULE:value#rrggbb[aa][:legend]]\n"
99 "\t\t[VRULE:value#rrggbb[aa][:legend]]\n"
100 "\t\t[LINE{1|2|3}:vname[#rrggbb[aa][:legend]]]\n"
101 "\t\t[AREA:vname[#rrggbb[aa][:legend]]]\n"
102 "\t\t[STACK:vname[#rrggbb[aa][:legend]]]\n\n";
105 " * tune - Modify some basic properties of an RRD\n\n"
106 "\trrdtool tune filename\n"
107 "\t\t[--heartbeat|-h ds-name:heartbeat]\n"
108 "\t\t[--data-source-type|-d ds-name:DST]\n"
109 "\t\t[--data-source-rename|-r old-name:new-name]\n"
110 "\t\t[--minimum|-i ds-name:min] [--maximum|-a ds-name:max]\n"
111 "\t\t[--deltapos scale-value] [--deltaneg scale-value]\n"
112 "\t\t[--failure-threshold integer]\n"
113 "\t\t[--window-length integer]\n"
114 "\t\t[--alpha adaptation-parameter]\n"
115 "\t\t[--beta adaptation-parameter]\n"
116 "\t\t[--gamma adaptation-parameter]\n"
117 "\t\t[--gamma-deviation adaptation-parameter]\n"
118 "\t\t[--aberrant-reset ds-name]\n\n";
121 " * resize - alter the lenght of one of the RRAs in an RRD\n\n"
122 "\trrdtool resize filename rranum GROW|SHRINK rows\n\n";
125 "* xport - generate XML dump from one or several RRD\n\n"
126 "\trrdtool xport [-s|--start seconds] [-e|--end seconds]\n"
127 "\t\t[-m|--maxrows rows]\n"
128 "\t\t[--step seconds]\n"
129 "\t\t[DEF:vname=rrd:ds-name:CF]\n"
130 "\t\t[CDEF:vname=rpn-expression]\n"
131 "\t\t[XPORT:vname:legend]\n\n";
134 " * quit - closeing a session in remote mode\n\n"
135 "\trrdtool quit\n\n";
138 " * ls - lists all *.rrd files in current directory\n\n"
142 " * cd - changes the current directory\n\n"
143 "\trrdtool cd new direcotry\n\n";
146 " * mkdir - creates a new direcotry\n\n"
147 "\trrdtool mkdir newdirecotryname\n\n";
150 "RRDtool is distributed under the Terms of the GNU General\n"
151 "Public License Version 2. (www.gnu.org/copyleft/gpl.html)\n\n"
153 "For more information read the RRD manpages\n\n";
155 enum { C_NONE, C_CREATE, C_DUMP, C_INFO, C_RESTORE, C_LAST,
156 C_UPDATE, C_FETCH, C_GRAPH, C_TUNE, C_RESIZE, C_XPORT,
157 C_QUIT, C_LS, C_CD, C_MKDIR };
159 int help_cmd = C_NONE;
163 if (!strcmp(cmd,"create"))
165 else if (!strcmp(cmd,"dump"))
167 else if (!strcmp(cmd,"info"))
169 else if (!strcmp(cmd,"restore"))
170 help_cmd = C_RESTORE;
171 else if (!strcmp(cmd,"last"))
173 else if (!strcmp(cmd,"update"))
175 else if (!strcmp(cmd,"fetch"))
177 else if (!strcmp(cmd,"graph"))
179 else if (!strcmp(cmd,"tune"))
181 else if (!strcmp(cmd,"resize"))
183 else if (!strcmp(cmd,"xport"))
185 else if (!strcmp(cmd,"quit"))
187 else if (!strcmp(cmd,"ls"))
189 else if (!strcmp(cmd,"cd"))
191 else if (!strcmp(cmd,"mkdir"))
194 fputs(help_main, stdout);
198 fputs(help_list, stdout);
200 fputs(help_listremote, stdout);
204 fputs(help_create, stdout);
207 fputs(help_dump, stdout);
210 fputs(help_info, stdout);
213 fputs(help_restore, stdout);
216 fputs(help_last, stdout);
219 fputs(help_update, stdout);
222 fputs(help_fetch, stdout);
225 fputs(help_graph, stdout);
228 fputs(help_tune, stdout);
231 fputs(help_resize, stdout);
234 fputs(help_xport, stdout);
237 fputs(help_quit, stdout);
240 fputs(help_ls, stdout);
243 fputs(help_cd, stdout);
246 fputs(help_mkdir, stdout);
249 fputs(help_lic, stdout);
253 int main(int argc, char *argv[])
256 char aLine[MAX_LENGTH];
260 #ifdef MUST_DISABLE_SIGFPE
261 signal(SIGFPE,SIG_IGN);
263 #ifdef MUST_DISABLE_FPMASK
272 if (((argc == 2)||(argc == 3)) && !strcmp("-",argv[1]))
275 struct rusage myusage;
276 struct timeval starttime;
277 struct timeval currenttime;
280 tz.tz_minuteswest =0;
282 gettimeofday(&starttime,&tz);
286 if ((argc == 3) && strcmp("",argv[2])){
290 fprintf(stderr,"ERROR: can't change root to '%s' errno=%d\n",
301 if (strcmp(firstdir,"")){
304 fprintf(stderr,"ERROR: %s\n",strerror(errno));
309 fprintf(stderr,"ERROR: change root is not supported by your OS "
310 "or at least by this copy of rrdtool\n");
314 while (fgets(aLine, sizeof(aLine)-1, stdin)){
315 if ((argc = CountArgs(aLine)) == 0) {
316 fprintf(stderr,"ERROR: not enough arguments\n");
318 if ((myargv = (char **) malloc((argc+1) *
319 sizeof(char *))) == NULL) {
323 if ((argc=CreateArgs(argv[0], aLine, argc, myargv)) < 0) {
324 fprintf(stderr, "ERROR: creating arguments\n");
328 if (HandleInputLine(argc, myargv, stdout))
333 getrusage(RUSAGE_SELF,&myusage);
334 gettimeofday(¤ttime,&tz);
335 printf("OK u:%1.2f s:%1.2f r:%1.2f\n",
336 (double)myusage.ru_utime.tv_sec+
337 (double)myusage.ru_utime.tv_usec/1000000.0,
338 (double)myusage.ru_stime.tv_sec+
339 (double)myusage.ru_stime.tv_usec/1000000.0,
340 (double)(currenttime.tv_sec-starttime.tv_sec)
341 +(double)(currenttime.tv_usec-starttime.tv_usec)
346 fflush(stdout); /* this is important for pipes to work */
354 else if (argc == 3 && !strcmp(argv[1],"help"))
360 HandleInputLine(argc, argv, stderr);
364 /* HandleInputLine is NOT thread safe - due to readdir issues,
365 resolving them portably is not really simple. */
366 int HandleInputLine(int argc, char **argv, FILE* out)
368 #if defined(HAVE_OPENDIR) && defined (HAVE_READDIR)
369 DIR *curdir; /* to read current dir with ls */
372 #if defined(HAVE_SYS_STAT_H)
375 optind=0; /* reset gnu getopt */
376 opterr=0; /* no error messages */
379 if (argc>1 && strcmp("quit", argv[1]) == 0){
381 printf("ERROR: invalid parameter count for quit\n");
386 #if defined(HAVE_OPENDIR) && defined(HAVE_READDIR) && defined(HAVE_CHDIR)
387 if (argc>1 && strcmp("cd", argv[1]) == 0){
389 printf("ERROR: invalid parameter count for cd\n");
392 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
393 if (getuid()==0 && ! ChangeRoot){
394 printf("ERROR: chdir security problem - rrdtool is runnig as "
395 "root an no chroot!\n");
401 printf("ERROR: %s\n",strerror(errno));
405 if (argc>1 && strcmp("mkdir", argv[1]) == 0){
407 printf("ERROR: invalid parameter count for mkdir\n");
410 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
411 if (getuid()==0 && ! ChangeRoot){
412 printf("ERROR: mkdir security problem - rrdtool is runnig as "
413 "root an no chroot!\n");
419 printf("ERROR: %s\n",strerror(errno));
423 if (argc>1 && strcmp("ls", argv[1]) == 0){
425 printf("ERROR: invalid parameter count for ls\n");
428 if ((curdir=opendir("."))!=NULL){
429 while((dent=readdir(curdir))!=NULL){
430 if (!stat(dent->d_name,&st)){
431 if (S_ISDIR(st.st_mode)){
432 printf("d %s\n",dent->d_name);
434 if (strlen(dent->d_name)>4 && S_ISREG(st.st_mode)){
435 if (!strcmp(dent->d_name+NAMLEN(dent)-4,".rrd") ||
436 !strcmp(dent->d_name+NAMLEN(dent)-4,".RRD")){
437 printf("- %s\n",dent->d_name);
444 printf("ERROR: %s\n",strerror(errno));
449 #endif /* opendir and readdir */
453 || strcmp("help", argv[1]) == 0
454 || strcmp("--help", argv[1]) == 0
455 || strcmp("-help", argv[1]) == 0
456 || strcmp("-?", argv[1]) == 0
457 || strcmp("-h", argv[1]) == 0 ) {
462 if (strcmp("create", argv[1]) == 0)
463 rrd_create(argc-1, &argv[1]);
464 else if (strcmp("dump", argv[1]) == 0)
465 rrd_dump(argc-1, &argv[1]);
466 else if (strcmp("info", argv[1]) == 0){
468 data=rrd_info(argc-1, &argv[1]);
471 printf ("%s = ", data->key);
474 switch (data->type) {
476 if (isnan (data->value.u_val))
479 printf ("%0.10e", data->value.u_val);
482 printf ("%lu", data->value.u_cnt);
485 printf ("\"%s\"", data->value.u_str);
486 free(data->value.u_str);
496 else if (strcmp("--version", argv[1]) == 0 ||
497 strcmp("version", argv[1]) == 0 ||
498 strcmp("v", argv[1]) == 0 ||
499 strcmp("-v", argv[1]) == 0 ||
500 strcmp("-version", argv[1]) == 0 )
501 printf("RRDtool 1.1.x Copyright (C) 1997-2003 by Tobias Oetiker <tobi@oetiker.ch>\n");
502 else if (strcmp("restore", argv[1]) == 0)
503 rrd_restore(argc-1, &argv[1]);
504 else if (strcmp("resize", argv[1]) == 0)
505 rrd_resize(argc-1, &argv[1]);
506 else if (strcmp("last", argv[1]) == 0)
507 printf("%ld\n",rrd_last(argc-1, &argv[1]));
508 else if (strcmp("update", argv[1]) == 0)
509 rrd_update(argc-1, &argv[1]);
510 else if (strcmp("fetch", argv[1]) == 0) {
511 time_t start,end, ti;
512 unsigned long step, ds_cnt,i,ii;
513 rrd_value_t *data,*datai;
515 if (rrd_fetch(argc-1, &argv[1],&start,&end,&step,&ds_cnt,&ds_namv,&data) != -1) {
518 for (i = 0; i<ds_cnt;i++)
519 printf("%14s",ds_namv[i]);
521 for (ti = start+step; ti <= end; ti += step){
522 printf("%10lu:", ti);
523 for (ii = 0; ii < ds_cnt; ii++)
524 printf(" %0.10e", *(datai++));
527 for (i=0;i<ds_cnt;i++)
532 } else if (strcmp("xport", argv[1]) == 0) {
534 unsigned long int j = 0;
535 time_t start,end, ti;
536 unsigned long step, col_cnt,row_cnt;
537 rrd_value_t *data,*ptr;
539 if(rrd_xport(argc-1, &argv[1], &xxsize,&start,&end,&step,&col_cnt,&legend_v,&data) != -1) {
540 row_cnt = (end-start)/step;
542 printf("<?xml version=\"1.0\" encoding=\"%s\"?>\n\n", XML_ENCODING);
543 printf("<%s>\n", ROOT_TAG);
544 printf(" <%s>\n", META_TAG);
545 printf(" <%s>%lu</%s>\n", META_START_TAG, start+step, META_START_TAG);
546 printf(" <%s>%lu</%s>\n", META_STEP_TAG, step, META_STEP_TAG);
547 printf(" <%s>%lu</%s>\n", META_END_TAG, end, META_END_TAG);
548 printf(" <%s>%lu</%s>\n", META_ROWS_TAG, row_cnt, META_ROWS_TAG);
549 printf(" <%s>%lu</%s>\n", META_COLS_TAG, col_cnt, META_COLS_TAG);
550 printf(" <%s>\n", LEGEND_TAG);
551 for (j = 0; j < col_cnt; j++) {
554 printf(" <%s>%s</%s>\n", LEGEND_ENTRY_TAG, entry, LEGEND_ENTRY_TAG);
558 printf(" </%s>\n", LEGEND_TAG);
559 printf(" </%s>\n", META_TAG);
560 printf(" <%s>\n", DATA_TAG);
561 for (ti = start+step; ti <= end; ti += step) {
562 printf (" <%s>", DATA_ROW_TAG);
563 printf ("<%s>%lu</%s>", COL_TIME_TAG, ti, COL_TIME_TAG);
564 for (j = 0; j < col_cnt; j++) {
565 rrd_value_t newval = DNAN;
568 printf("<%s>NaN</%s>", COL_DATA_TAG, COL_DATA_TAG);
570 printf("<%s>%0.10e</%s>", COL_DATA_TAG, newval, COL_DATA_TAG);
574 printf("</%s>\n", DATA_ROW_TAG);
577 printf(" </%s>\n", DATA_TAG);
578 printf("</%s>\n", ROOT_TAG);
581 else if (strcmp("graph", argv[1]) == 0) {
583 const char *imgfile = argv[2]; /* rrd_graph changes argv pointer */
586 if( rrd_graph(argc-1, &argv[1], &calcpr, &xsize, &ysize) != -1 ) {
587 if (strcmp(imgfile,"-") != 0)
588 printf ("%dx%d\n",xsize,ysize);
590 for(i=0;calcpr[i];i++){
591 if (strcmp(imgfile,"-") != 0)
592 printf("%s\n",calcpr[i]);
599 } else if (strcmp("tune", argv[1]) == 0)
600 rrd_tune(argc-1, &argv[1]);
602 rrd_set_error("unknown function '%s'",argv[1]);
604 if (rrd_test_error()) {
605 fprintf(out, "ERROR: %s\n",rrd_get_error());
611 int CountArgs(char *aLine)
616 while (aLine[i] == ' ') i++;
617 while (aLine[i] != 0){
618 if((aLine[i]== ' ') && inarg){
621 if((aLine[i]!= ' ') && ! inarg){
631 * CreateArgs - take a string (aLine) and tokenize
633 int CreateArgs(char *pName, char *aLine, int argc, char **argv)
642 /* remove trailing space and newlines */
643 while (len && aLine[len] <= ' ') {
644 aLine[len] = 0 ; len--;
646 /* sikp leading blanks */
647 while (*aLine && *aLine <= ' ') aLine++;
674 pargv[argc++] = putP;
682 pargv[argc++] = putP;