1 /*****************************************************************************
2 * RRDtool 1.2.23 Copyright by Tobi Oetiker, 1997-2007
3 *****************************************************************************
4 * rrd_tool.c Startup wrapper
5 *****************************************************************************/
28 #define MAX_LENGTH 10000
36 "RRDtool " PACKAGE_VERSION
37 " Copyright 1997-2007 by Tobias Oetiker <tobi@oetiker.ch>\n"
38 " Compiled " __DATE__ " " __TIME__ "\n\n"
39 "Usage: rrdtool [options] command command_options\n\n";
42 "Valid commands: create, update, updatev, graph, dump, restore,\n"
43 "\t\tlast, lastupdate, first, info, fetch, tune,\n"
44 "\t\tresize, xport\n\n";
46 char help_listremote[] =
47 "Valid remote commands: quit, ls, cd, mkdir, pwd\n\n";
51 "* create - create a new RRD\n\n"
52 "\trrdtool create filename [--start|-b start time]\n"
53 "\t\t[--step|-s step]\n"
54 "\t\t[DS:ds-name:DST:dst arguments]\n"
55 "\t\t[RRA:CF:cf arguments]\n\n";
58 "* dump - dump an RRD to XML\n\n"
59 "\trrdtool dump filename.rrd >filename.xml\n\n";
62 "* info - returns the configuration and status of the RRD\n\n"
63 "\trrdtool info filename.rrd\n\n";
66 "* restore - restore an RRD file from its XML form\n\n"
67 "\trrdtool restore [--range-check|-r] [--force-overwrite|-f] filename.xml filename.rrd\n\n";
70 "* last - show last update time for RRD\n\n"
71 "\trrdtool last filename.rrd\n\n";
73 char help_lastupdate[] =
74 "* lastupdate - returns the most recent datum stored for\n"
75 " each DS in an RRD\n\n" "\trrdtool lastupdate filename.rrd\n\n";
78 "* first - show first update time for RRA within an RRD\n\n"
79 "\trrdtool first filename.rrd [--rraindex number]\n\n";
82 "* update - update an RRD\n\n"
83 "\trrdtool update filename\n"
84 "\t\t--template|-t ds-name:ds-name:...\n"
85 "\t\ttime|N:value[:value...]\n\n"
86 "\t\tat-time@value[:value...]\n\n"
87 "\t\t[ time:value[:value...] ..]\n\n";
90 "* updatev - a verbose version of update\n"
91 "\treturns information about values, RRAs, and datasources updated\n\n"
92 "\trrdtool updatev filename\n"
93 "\t\t--template|-t ds-name:ds-name:...\n"
94 "\t\ttime|N:value[:value...]\n\n"
95 "\t\tat-time@value[:value...]\n\n"
96 "\t\t[ time:value[:value...] ..]\n\n";
99 "* fetch - fetch data out of an RRD\n\n"
100 "\trrdtool fetch filename.rrd CF\n"
101 "\t\t[-r|--resolution resolution]\n"
102 "\t\t[-s|--start start] [-e|--end end]\n\n";
104 /* break up very large strings (help_graph, help_tune) for ISO C89 compliance*/
107 "* graph - generate a graph from one or several RRD\n\n"
108 "\trrdtool graph filename [-s|--start seconds] [-e|--end seconds]\n"
109 "\t\t[-x|--x-grid x-axis grid and label]\n"
110 "\t\t[-Y|--alt-y-grid]\n"
111 "\t\t[-y|--y-grid y-axis grid and label]\n"
112 "\t\t[-v|--vertical-label string] [-w|--width pixels]\n"
113 "\t\t[-h|--height pixels] [-o|--logarithmic]\n"
114 "\t\t[-u|--upper-limit value] [-z|--lazy]\n"
115 "\t\t[-l|--lower-limit value] [-r|--rigid]\n"
116 "\t\t[-g|--no-legend]\n"
117 "\t\t[-F|--force-rules-legend]\n" "\t\t[-j|--only-graph]\n";
119 "\t\t[-n|--font FONTTAG:size:font]\n"
120 "\t\t[-m|--zoom factor]\n"
121 "\t\t[-A|--alt-autoscale]\n"
122 "\t\t[-M|--alt-autoscale-max]\n"
123 "\t\t[-R|--font-render-mode {normal,light,mono}]\n"
124 "\t\t[-B|--font-smoothing-threshold size]\n"
125 "\t\t[-E|--slope-mode]\n"
126 "\t\t[-N|--no-gridfit]\n"
127 "\t\t[-X|--units-exponent value]\n"
128 "\t\t[-L|--units-length value]\n"
129 "\t\t[-S|--step seconds]\n"
130 "\t\t[-f|--imginfo printfstr]\n"
131 "\t\t[-a|--imgformat PNG]\n"
132 "\t\t[-c|--color COLORTAG#rrggbb[aa]] [-t|--title string]\n"
133 "\t\t[-W|--watermark string]\n" "\t\t[DEF:vname=rrd:ds-name:CF]\n";
135 "\t\t[CDEF:vname=rpn-expression]\n"
136 "\t\t[VDEF:vdefname=rpn-expression]\n"
137 "\t\t[PRINT:vdefname:format]\n"
138 "\t\t[GPRINT:vdefname:format]\n"
139 "\t\t[COMMENT:text]\n"
140 "\t\t[SHIFT:vname:offset]\n"
141 "\t\t[TICK:vname#rrggbb[aa][:[fraction][:legend]]]\n"
142 "\t\t[HRULE:value#rrggbb[aa][:legend]]\n"
143 "\t\t[VRULE:value#rrggbb[aa][:legend]]\n"
144 "\t\t[LINE[width]:vname[#rrggbb[aa][:[legend][:STACK]]]]\n"
145 "\t\t[AREA:vname[#rrggbb[aa][:[legend][:STACK]]]]\n"
146 "\t\t[PRINT:vname:CF:format] (deprecated)\n"
147 "\t\t[GPRINT:vname:CF:format] (deprecated)\n"
148 "\t\t[STACK:vname[#rrggbb[aa][:legend]]] (deprecated)\n\n";
151 " * tune - Modify some basic properties of an RRD\n\n"
152 "\trrdtool tune filename\n"
153 "\t\t[--heartbeat|-h ds-name:heartbeat]\n"
154 "\t\t[--data-source-type|-d ds-name:DST]\n"
155 "\t\t[--data-source-rename|-r old-name:new-name]\n"
156 "\t\t[--minimum|-i ds-name:min] [--maximum|-a ds-name:max]\n"
157 "\t\t[--deltapos scale-value] [--deltaneg scale-value]\n"
158 "\t\t[--failure-threshold integer]\n"
159 "\t\t[--window-length integer]\n"
160 "\t\t[--alpha adaptation-parameter]\n";
162 " * tune - Modify some basic properties of an RRD\n\n"
163 "\t\t[--beta adaptation-parameter]\n"
164 "\t\t[--gamma adaptation-parameter]\n"
165 "\t\t[--gamma-deviation adaptation-parameter]\n"
166 "\t\t[--aberrant-reset ds-name]\n\n";
169 " * resize - alter the length of one of the RRAs in an RRD\n\n"
170 "\trrdtool resize filename rranum GROW|SHRINK rows\n\n";
173 "* xport - generate XML dump from one or several RRD\n\n"
174 "\trrdtool xport [-s|--start seconds] [-e|--end seconds]\n"
175 "\t\t[-m|--maxrows rows]\n"
176 "\t\t[--step seconds]\n"
178 "\t\t[DEF:vname=rrd:ds-name:CF]\n"
179 "\t\t[CDEF:vname=rpn-expression]\n" "\t\t[XPORT:vname:legend]\n\n";
182 " * quit - closing a session in remote mode\n\n" "\trrdtool quit\n\n";
185 " * ls - lists all *.rrd files in current directory\n\n"
189 " * cd - changes the current directory\n\n"
190 "\trrdtool cd new directory\n\n";
193 " * mkdir - creates a new directory\n\n"
194 "\trrdtool mkdir newdirectoryname\n\n";
197 " * pwd - returns the current working directory\n\n"
201 "RRDtool is distributed under the Terms of the GNU General\n"
202 "Public License Version 2. (www.gnu.org/copyleft/gpl.html)\n\n"
203 "For more information read the RRD manpages\n\n";
205 enum { C_NONE, C_CREATE, C_DUMP, C_INFO, C_RESTORE, C_LAST,
206 C_LASTUPDATE, C_FIRST, C_UPDATE, C_FETCH, C_GRAPH, C_TUNE,
207 C_RESIZE, C_XPORT, C_QUIT, C_LS, C_CD, C_MKDIR, C_PWD,
211 int help_cmd = C_NONE;
214 if (!strcmp(cmd, "create"))
216 else if (!strcmp(cmd, "dump"))
218 else if (!strcmp(cmd, "info"))
220 else if (!strcmp(cmd, "restore"))
221 help_cmd = C_RESTORE;
222 else if (!strcmp(cmd, "last"))
224 else if (!strcmp(cmd, "lastupdate"))
225 help_cmd = C_LASTUPDATE;
226 else if (!strcmp(cmd, "first"))
228 else if (!strcmp(cmd, "update"))
230 else if (!strcmp(cmd, "updatev"))
231 help_cmd = C_UPDATEV;
232 else if (!strcmp(cmd, "fetch"))
234 else if (!strcmp(cmd, "graph"))
236 else if (!strcmp(cmd, "tune"))
238 else if (!strcmp(cmd, "resize"))
240 else if (!strcmp(cmd, "xport"))
242 else if (!strcmp(cmd, "quit"))
244 else if (!strcmp(cmd, "ls"))
246 else if (!strcmp(cmd, "cd"))
248 else if (!strcmp(cmd, "mkdir"))
250 else if (!strcmp(cmd, "pwd"))
253 fputs(help_main, stdout);
256 fputs(help_list, stdout);
258 fputs(help_listremote, stdout);
262 fputs(help_create, stdout);
265 fputs(help_dump, stdout);
268 fputs(help_info, stdout);
271 fputs(help_restore, stdout);
274 fputs(help_last, stdout);
277 fputs(help_lastupdate, stdout);
280 fputs(help_first, stdout);
283 fputs(help_update, stdout);
286 fputs(help_updatev, stdout);
289 fputs(help_fetch, stdout);
292 fputs(help_graph1, stdout);
293 fputs(help_graph2, stdout);
294 fputs(help_graph3, stdout);
297 fputs(help_tune1, stdout);
298 fputs(help_tune2, stdout);
301 fputs(help_resize, stdout);
304 fputs(help_xport, stdout);
307 fputs(help_quit, stdout);
310 fputs(help_ls, stdout);
313 fputs(help_cd, stdout);
316 fputs(help_mkdir, stdout);
319 fputs(help_pwd, stdout);
322 fputs(help_lic, stdout);
325 static char *fgetslong(
330 size_t bufsize = MAX_LENGTH;
334 return *aLinePtr = 0;
335 if (!(linebuf = malloc(bufsize))) {
336 perror("fgetslong: malloc");
340 while (fgets(linebuf + eolpos, MAX_LENGTH, stream)) {
341 eolpos += strlen(linebuf + eolpos);
342 if (linebuf[eolpos - 1] == '\n')
343 return *aLinePtr = linebuf;
344 bufsize += MAX_LENGTH;
345 if (!(linebuf = realloc(linebuf, bufsize))) {
346 perror("fgetslong: realloc");
350 return *aLinePtr = linebuf[0] ? linebuf : 0;
361 #ifdef MUST_DISABLE_SIGFPE
362 signal(SIGFPE, SIG_IGN);
364 #ifdef MUST_DISABLE_FPMASK
372 if (((argc == 2) || (argc == 3)) && !strcmp("-", argv[1])) {
374 struct rusage myusage;
375 struct timeval starttime;
376 struct timeval currenttime;
378 gettimeofday(&starttime, NULL);
381 if ((argc == 3) && strcmp("", argv[2])) {
395 "ERROR: can't change root to '%s' errno=%d\n",
403 "ERROR: change root is not supported by your OS "
404 "or at least by this copy of rrdtool\n");
411 if (strcmp(firstdir, "")) {
414 fprintf(stderr, "ERROR: %s\n", rrd_strerror(errno));
419 while (fgetslong(&aLine, stdin)) {
420 if ((argc = CountArgs(aLine)) == 0) {
421 printf("ERROR: not enough arguments\n");
423 if ((myargv = (char **) malloc((argc + 1) *
424 sizeof(char *))) == NULL) {
428 if ((argc = CreateArgs(argv[0], aLine, argc, myargv)) < 0) {
429 printf("ERROR: creating arguments\n");
431 int ret = HandleInputLine(argc, myargv, stdout);
438 getrusage(RUSAGE_SELF, &myusage);
439 gettimeofday(¤ttime, NULL);
440 printf("OK u:%1.2f s:%1.2f r:%1.2f\n",
441 (double) myusage.ru_utime.tv_sec +
442 (double) myusage.ru_utime.tv_usec / 1000000.0,
443 (double) myusage.ru_stime.tv_sec +
444 (double) myusage.ru_stime.tv_usec / 1000000.0,
445 (double) (currenttime.tv_sec - starttime.tv_sec)
446 + (double) (currenttime.tv_usec -
455 fflush(stdout); /* this is important for pipes to work */
458 } else if (argc == 2) {
461 } else if (argc == 3 && !strcmp(argv[1], "help")) {
465 exit(HandleInputLine(argc, argv, stderr));
470 /* HandleInputLine is NOT thread safe - due to readdir issues,
471 resolving them portably is not really simple. */
477 #if defined(HAVE_OPENDIR) && defined (HAVE_READDIR)
478 DIR *curdir; /* to read current dir with ls */
481 #if defined(HAVE_SYS_STAT_H)
484 char *cwd; /* To hold current working dir on call to pwd */
486 /* Reset errno to 0 before we start.
491 if (argc > 1 && strcmp("quit", argv[1]) == 0) {
493 printf("ERROR: invalid parameter count for quit\n");
498 #if defined(HAVE_OPENDIR) && defined(HAVE_READDIR) && defined(HAVE_CHDIR)
499 if (argc > 1 && strcmp("cd", argv[1]) == 0) {
501 printf("ERROR: invalid parameter count for cd\n");
504 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
505 if (getuid() == 0 && !ChangeRoot) {
507 ("ERROR: chdir security problem - rrdtool is running as "
508 "root but not chroot!\n");
514 printf("ERROR: %s\n", rrd_strerror(errno));
519 if (argc > 1 && strcmp("pwd", argv[1]) == 0) {
521 printf("ERROR: invalid parameter count for pwd\n");
524 cwd = getcwd(NULL, MAXPATH);
526 printf("ERROR: %s\n", rrd_strerror(errno));
533 if (argc > 1 && strcmp("mkdir", argv[1]) == 0) {
535 printf("ERROR: invalid parameter count for mkdir\n");
538 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
539 if (getuid() == 0 && !ChangeRoot) {
541 ("ERROR: mkdir security problem - rrdtool is running as "
542 "root but not chroot!\n");
546 mkdir(argv[2], 0777);
548 printf("ERROR: %s\n", rrd_strerror(errno));
553 if (argc > 1 && strcmp("ls", argv[1]) == 0) {
555 printf("ERROR: invalid parameter count for ls\n");
558 if ((curdir = opendir(".")) != NULL) {
559 while ((dent = readdir(curdir)) != NULL) {
560 if (!stat(dent->d_name, &st)) {
561 if (S_ISDIR(st.st_mode)) {
562 printf("d %s\n", dent->d_name);
564 if (strlen(dent->d_name) > 4 && S_ISREG(st.st_mode)) {
566 (dent->d_name + NAMLEN(dent) - 4, ".rrd")
567 || !strcmp(dent->d_name + NAMLEN(dent) - 4,
569 printf("- %s\n", dent->d_name);
576 printf("ERROR: %s\n", rrd_strerror(errno));
581 #endif /* opendir and readdir */
585 || strcmp("help", argv[1]) == 0
586 || strcmp("--help", argv[1]) == 0
587 || strcmp("-help", argv[1]) == 0
588 || strcmp("-?", argv[1]) == 0 || strcmp("-h", argv[1]) == 0) {
593 if (strcmp("create", argv[1]) == 0)
594 rrd_create(argc - 1, &argv[1]);
595 else if (strcmp("dump", argv[1]) == 0)
596 rrd_dump(argc - 1, &argv[1]);
597 else if (strcmp("info", argv[1]) == 0 || strcmp("updatev", argv[1]) == 0) {
600 if (strcmp("info", argv[1]) == 0)
601 data = rrd_info(argc - 1, &argv[1]);
603 data = rrd_update_v(argc - 1, &argv[1]);
606 printf("%s = ", data->key);
609 switch (data->type) {
611 if (isnan(data->value.u_val))
614 printf("%0.10e", data->value.u_val);
617 printf("%lu", data->value.u_cnt);
620 printf("%d", data->value.u_int);
623 printf("\"%s\"", data->value.u_str);
624 free(data->value.u_str);
634 else if (strcmp("--version", argv[1]) == 0 ||
635 strcmp("version", argv[1]) == 0 ||
636 strcmp("v", argv[1]) == 0 ||
637 strcmp("-v", argv[1]) == 0 || strcmp("-version", argv[1]) == 0)
638 printf("RRDtool " PACKAGE_VERSION
639 " Copyright by Tobi Oetiker, 1997-2005 (%f)\n",
641 else if (strcmp("restore", argv[1]) == 0)
642 rrd_restore(argc - 1, &argv[1]);
643 else if (strcmp("resize", argv[1]) == 0)
644 rrd_resize(argc - 1, &argv[1]);
645 else if (strcmp("last", argv[1]) == 0)
646 printf("%ld\n", rrd_last(argc - 1, &argv[1]));
647 else if (strcmp("lastupdate", argv[1]) == 0) {
651 unsigned long ds_cnt, i;
653 if (rrd_lastupdate(argc - 1, &argv[1], &last_update,
654 &ds_cnt, &ds_namv, &last_ds) == 0) {
655 for (i = 0; i < ds_cnt; i++)
656 printf(" %s", ds_namv[i]);
658 printf("%10lu:", last_update);
659 for (i = 0; i < ds_cnt; i++) {
660 printf(" %s", last_ds[i]);
668 } else if (strcmp("first", argv[1]) == 0)
669 printf("%ld\n", rrd_first(argc - 1, &argv[1]));
670 else if (strcmp("update", argv[1]) == 0)
671 rrd_update(argc - 1, &argv[1]);
672 else if (strcmp("fetch", argv[1]) == 0) {
673 time_t start, end, ti;
674 unsigned long step, ds_cnt, i, ii;
675 rrd_value_t *data, *datai;
679 (argc - 1, &argv[1], &start, &end, &step, &ds_cnt, &ds_namv,
683 for (i = 0; i < ds_cnt; i++)
684 printf("%20s", ds_namv[i]);
686 for (ti = start + step; ti <= end; ti += step) {
687 printf("%10lu:", ti);
688 for (ii = 0; ii < ds_cnt; ii++)
689 printf(" %0.10e", *(datai++));
692 for (i = 0; i < ds_cnt; i++)
697 } else if (strcmp("xport", argv[1]) == 0) {
699 unsigned long int j = 0;
700 time_t start, end, ti;
701 unsigned long step, col_cnt, row_cnt;
702 rrd_value_t *data, *ptr;
706 size_t vtag_s = strlen(COL_DATA_TAG) + 10;
707 char *vtag = malloc(vtag_s);
709 for (i = 2; i < argc; i++) {
710 if (strcmp("--enumds", argv[i]) == 0)
715 (argc - 1, &argv[1], &xxsize, &start, &end, &step, &col_cnt,
716 &legend_v, &data) != -1) {
717 row_cnt = (end - start) / step;
719 printf("<?xml version=\"1.0\" encoding=\"%s\"?>\n\n",
721 printf("<%s>\n", ROOT_TAG);
722 printf(" <%s>\n", META_TAG);
723 printf(" <%s>%lu</%s>\n", META_START_TAG, start + step,
725 printf(" <%s>%lu</%s>\n", META_STEP_TAG, step, META_STEP_TAG);
726 printf(" <%s>%lu</%s>\n", META_END_TAG, end, META_END_TAG);
727 printf(" <%s>%lu</%s>\n", META_ROWS_TAG, row_cnt,
729 printf(" <%s>%lu</%s>\n", META_COLS_TAG, col_cnt,
731 printf(" <%s>\n", LEGEND_TAG);
732 for (j = 0; j < col_cnt; j++) {
736 printf(" <%s>%s</%s>\n", LEGEND_ENTRY_TAG, entry,
741 printf(" </%s>\n", LEGEND_TAG);
742 printf(" </%s>\n", META_TAG);
743 printf(" <%s>\n", DATA_TAG);
744 for (ti = start + step; ti <= end; ti += step) {
745 printf(" <%s>", DATA_ROW_TAG);
746 printf("<%s>%lu</%s>", COL_TIME_TAG, ti, COL_TIME_TAG);
747 for (j = 0; j < col_cnt; j++) {
748 rrd_value_t newval = DNAN;
751 snprintf(vtag, vtag_s, "%s%lu", COL_DATA_TAG, j);
753 snprintf(vtag, vtag_s, "%s", COL_DATA_TAG);
757 printf("<%s>NaN</%s>", vtag, vtag);
759 printf("<%s>%0.10e</%s>", vtag, newval, vtag);
763 printf("</%s>\n", DATA_ROW_TAG);
766 printf(" </%s>\n", DATA_TAG);
767 printf("</%s>\n", ROOT_TAG);
770 } else if (strcmp("graph", argv[1]) == 0) {
773 #ifdef notused /*XXX*/
774 const char *imgfile = argv[2]; /* rrd_graph changes argv pointer */
779 int tostdout = (strcmp(argv[2], "-") == 0);
782 for (i = 2; i < argc; i++) {
783 if (strcmp(argv[i], "--imginfo") == 0
784 || strcmp(argv[i], "-f") == 0) {
790 (argc - 1, &argv[1], &calcpr, &xsize, &ysize, NULL, &ymin,
792 if (!tostdout && !imginfo)
793 printf("%dx%d\n", xsize, ysize);
795 for (i = 0; calcpr[i]; i++) {
797 printf("%s\n", calcpr[i]);
804 } else if (strcmp("tune", argv[1]) == 0)
805 rrd_tune(argc - 1, &argv[1]);
807 rrd_set_error("unknown function '%s'", argv[1]);
809 if (rrd_test_error()) {
810 fprintf(out, "ERROR: %s\n", rrd_get_error());
824 while (aLine[i] == ' ')
826 while (aLine[i] != 0) {
827 if ((aLine[i] == ' ') && inarg) {
830 if ((aLine[i] != ' ') && !inarg) {
840 * CreateArgs - take a string (aLine) and tokenize
855 /* remove trailing space and newlines */
856 while (len && aLine[len] <= ' ') {
860 /* sikp leading blanks */
861 while (*aLine && *aLine <= ' ')
888 pargv[argc++] = putP;
896 pargv[argc++] = putP;