1 /*****************************************************************************
2 * RRDtool 1.2.99907080300 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);
436 getrusage(RUSAGE_SELF, &myusage);
437 gettimeofday(¤ttime, NULL);
438 printf("OK u:%1.2f s:%1.2f r:%1.2f\n",
439 (double) myusage.ru_utime.tv_sec +
440 (double) myusage.ru_utime.tv_usec / 1000000.0,
441 (double) myusage.ru_stime.tv_sec +
442 (double) myusage.ru_stime.tv_usec / 1000000.0,
443 (double) (currenttime.tv_sec - starttime.tv_sec)
444 + (double) (currenttime.tv_usec -
453 fflush(stdout); /* this is important for pipes to work */
456 } else if (argc == 2) {
459 } else if (argc == 3 && !strcmp(argv[1], "help")) {
463 exit(HandleInputLine(argc, argv, stderr));
468 /* HandleInputLine is NOT thread safe - due to readdir issues,
469 resolving them portably is not really simple. */
475 #if defined(HAVE_OPENDIR) && defined (HAVE_READDIR)
476 DIR *curdir; /* to read current dir with ls */
479 #if defined(HAVE_SYS_STAT_H)
482 char *cwd; /* To hold current working dir on call to pwd */
484 /* Reset errno to 0 before we start.
489 if (argc > 1 && strcmp("quit", argv[1]) == 0) {
491 printf("ERROR: invalid parameter count for quit\n");
496 #if defined(HAVE_OPENDIR) && defined(HAVE_READDIR) && defined(HAVE_CHDIR)
497 if (argc > 1 && strcmp("cd", argv[1]) == 0) {
499 printf("ERROR: invalid parameter count for cd\n");
502 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
503 if (getuid() == 0 && !ChangeRoot) {
505 ("ERROR: chdir security problem - rrdtool is running as "
506 "root but not chroot!\n");
512 printf("ERROR: %s\n", rrd_strerror(errno));
517 if (argc > 1 && strcmp("pwd", argv[1]) == 0) {
519 printf("ERROR: invalid parameter count for pwd\n");
522 cwd = getcwd(NULL, MAXPATH);
524 printf("ERROR: %s\n", rrd_strerror(errno));
531 if (argc > 1 && strcmp("mkdir", argv[1]) == 0) {
533 printf("ERROR: invalid parameter count for mkdir\n");
536 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
537 if (getuid() == 0 && !ChangeRoot) {
539 ("ERROR: mkdir security problem - rrdtool is running as "
540 "root but not chroot!\n");
544 mkdir(argv[2], 0777);
546 printf("ERROR: %s\n", rrd_strerror(errno));
551 if (argc > 1 && strcmp("ls", argv[1]) == 0) {
553 printf("ERROR: invalid parameter count for ls\n");
556 if ((curdir = opendir(".")) != NULL) {
557 while ((dent = readdir(curdir)) != NULL) {
558 if (!stat(dent->d_name, &st)) {
559 if (S_ISDIR(st.st_mode)) {
560 printf("d %s\n", dent->d_name);
562 if (strlen(dent->d_name) > 4 && S_ISREG(st.st_mode)) {
564 (dent->d_name + NAMLEN(dent) - 4, ".rrd")
565 || !strcmp(dent->d_name + NAMLEN(dent) - 4,
567 printf("- %s\n", dent->d_name);
574 printf("ERROR: %s\n", rrd_strerror(errno));
579 #endif /* opendir and readdir */
583 || strcmp("help", argv[1]) == 0
584 || strcmp("--help", argv[1]) == 0
585 || strcmp("-help", argv[1]) == 0
586 || strcmp("-?", argv[1]) == 0 || strcmp("-h", argv[1]) == 0) {
591 if (strcmp("create", argv[1]) == 0)
592 rrd_create(argc - 1, &argv[1]);
593 else if (strcmp("dump", argv[1]) == 0)
594 rrd_dump(argc - 1, &argv[1]);
595 else if (strcmp("info", argv[1]) == 0 || strcmp("updatev", argv[1]) == 0) {
598 if (strcmp("info", argv[1]) == 0)
599 data = rrd_info(argc - 1, &argv[1]);
601 data = rrd_update_v(argc - 1, &argv[1]);
604 printf("%s = ", data->key);
607 switch (data->type) {
609 if (isnan(data->value.u_val))
612 printf("%0.10e", data->value.u_val);
615 printf("%lu", data->value.u_cnt);
618 printf("%d", data->value.u_int);
621 printf("\"%s\"", data->value.u_str);
622 free(data->value.u_str);
632 else if (strcmp("--version", argv[1]) == 0 ||
633 strcmp("version", argv[1]) == 0 ||
634 strcmp("v", argv[1]) == 0 ||
635 strcmp("-v", argv[1]) == 0 || strcmp("-version", argv[1]) == 0)
636 printf("RRDtool " PACKAGE_VERSION
637 " Copyright by Tobi Oetiker, 1997-2005 (%f)\n",
639 else if (strcmp("restore", argv[1]) == 0)
640 rrd_restore(argc - 1, &argv[1]);
641 else if (strcmp("resize", argv[1]) == 0)
642 rrd_resize(argc - 1, &argv[1]);
643 else if (strcmp("last", argv[1]) == 0)
644 printf("%ld\n", rrd_last(argc - 1, &argv[1]));
645 else if (strcmp("lastupdate", argv[1]) == 0) {
649 unsigned long ds_cnt, i;
651 if (rrd_lastupdate(argc - 1, &argv[1], &last_update,
652 &ds_cnt, &ds_namv, &last_ds) == 0) {
653 for (i = 0; i < ds_cnt; i++)
654 printf(" %s", ds_namv[i]);
656 printf("%10lu:", last_update);
657 for (i = 0; i < ds_cnt; i++) {
658 printf(" %s", last_ds[i]);
666 } else if (strcmp("first", argv[1]) == 0)
667 printf("%ld\n", rrd_first(argc - 1, &argv[1]));
668 else if (strcmp("update", argv[1]) == 0)
669 rrd_update(argc - 1, &argv[1]);
670 else if (strcmp("fetch", argv[1]) == 0) {
671 time_t start, end, ti;
672 unsigned long step, ds_cnt, i, ii;
673 rrd_value_t *data, *datai;
677 (argc - 1, &argv[1], &start, &end, &step, &ds_cnt, &ds_namv,
681 for (i = 0; i < ds_cnt; i++)
682 printf("%20s", ds_namv[i]);
684 for (ti = start + step; ti <= end; ti += step) {
685 printf("%10lu:", ti);
686 for (ii = 0; ii < ds_cnt; ii++)
687 printf(" %0.10e", *(datai++));
690 for (i = 0; i < ds_cnt; i++)
695 } else if (strcmp("xport", argv[1]) == 0) {
697 unsigned long int j = 0;
698 time_t start, end, ti;
699 unsigned long step, col_cnt, row_cnt;
700 rrd_value_t *data, *ptr;
704 size_t vtag_s = strlen(COL_DATA_TAG) + 10;
705 char *vtag = malloc(vtag_s);
707 for (i = 2; i < argc; i++) {
708 if (strcmp("--enumds", argv[i]) == 0)
713 (argc - 1, &argv[1], &xxsize, &start, &end, &step, &col_cnt,
714 &legend_v, &data) != -1) {
715 row_cnt = (end - start) / step;
717 printf("<?xml version=\"1.0\" encoding=\"%s\"?>\n\n",
719 printf("<%s>\n", ROOT_TAG);
720 printf(" <%s>\n", META_TAG);
721 printf(" <%s>%lu</%s>\n", META_START_TAG, start + step,
723 printf(" <%s>%lu</%s>\n", META_STEP_TAG, step, META_STEP_TAG);
724 printf(" <%s>%lu</%s>\n", META_END_TAG, end, META_END_TAG);
725 printf(" <%s>%lu</%s>\n", META_ROWS_TAG, row_cnt,
727 printf(" <%s>%lu</%s>\n", META_COLS_TAG, col_cnt,
729 printf(" <%s>\n", LEGEND_TAG);
730 for (j = 0; j < col_cnt; j++) {
734 printf(" <%s>%s</%s>\n", LEGEND_ENTRY_TAG, entry,
739 printf(" </%s>\n", LEGEND_TAG);
740 printf(" </%s>\n", META_TAG);
741 printf(" <%s>\n", DATA_TAG);
742 for (ti = start + step; ti <= end; ti += step) {
743 printf(" <%s>", DATA_ROW_TAG);
744 printf("<%s>%lu</%s>", COL_TIME_TAG, ti, COL_TIME_TAG);
745 for (j = 0; j < col_cnt; j++) {
746 rrd_value_t newval = DNAN;
749 snprintf(vtag, vtag_s, "%s%lu", COL_DATA_TAG, j);
751 snprintf(vtag, vtag_s, "%s", COL_DATA_TAG);
755 printf("<%s>NaN</%s>", vtag, vtag);
757 printf("<%s>%0.10e</%s>", vtag, newval, vtag);
761 printf("</%s>\n", DATA_ROW_TAG);
764 printf(" </%s>\n", DATA_TAG);
765 printf("</%s>\n", ROOT_TAG);
768 } else if (strcmp("graph", argv[1]) == 0) {
771 #ifdef notused /*XXX*/
772 const char *imgfile = argv[2]; /* rrd_graph changes argv pointer */
777 int tostdout = (strcmp(argv[2], "-") == 0);
780 for (i = 2; i < argc; i++) {
781 if (strcmp(argv[i], "--imginfo") == 0
782 || strcmp(argv[i], "-f") == 0) {
788 (argc - 1, &argv[1], &calcpr, &xsize, &ysize, NULL, &ymin,
790 if (!tostdout && !imginfo)
791 printf("%dx%d\n", xsize, ysize);
793 for (i = 0; calcpr[i]; i++) {
795 printf("%s\n", calcpr[i]);
802 } else if (strcmp("tune", argv[1]) == 0)
803 rrd_tune(argc - 1, &argv[1]);
805 rrd_set_error("unknown function '%s'", argv[1]);
807 if (rrd_test_error()) {
808 fprintf(out, "ERROR: %s\n", rrd_get_error());
822 while (aLine[i] == ' ')
824 while (aLine[i] != 0) {
825 if ((aLine[i] == ' ') && inarg) {
828 if ((aLine[i] != ' ') && !inarg) {
838 * CreateArgs - take a string (aLine) and tokenize
853 /* remove trailing space and newlines */
854 while (len && aLine[len] <= ' ') {
858 /* sikp leading blanks */
859 while (*aLine && *aLine <= ' ')
886 pargv[argc++] = putP;
894 pargv[argc++] = putP;