1 /*****************************************************************************
2 * RRDtool 1.2.99907080300 Copyright by Tobi Oetiker, 1997-2007
3 *****************************************************************************
4 * rrd_tool.c Startup wrapper
5 *****************************************************************************/
7 #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__) && !defined(HAVE_CONFIG_H)
8 #include "../win32/config.h"
11 #include "../rrd_config.h"
16 #include "rrd_xport.h"
41 #define MAX_LENGTH 10000
50 " Copyright 1997-2007 by Tobias Oetiker <tobi@oetiker.ch>\n"
52 "Usage: rrdtool [options] command command_options\n\n");
55 N_("Valid commands: create, update, updatev, graph, dump, restore,\n"
56 "\t\tlast, lastupdate, first, info, fetch, tune,\n"
57 "\t\tresize, xport\n\n");
59 char help_listremote[] =
60 N_("Valid remote commands: quit, ls, cd, mkdir, pwd\n\n");
64 N_("* create - create a new RRD\n\n"
65 "\trrdtool create filename [--start|-b start time]\n"
66 "\t\t[--step|-s step]\n"
67 "\t\t[DS:ds-name:DST:dst arguments]\n"
68 "\t\t[RRA:CF:cf arguments]\n\n");
71 N_("* dump - dump an RRD to XML\n\n"
72 "\trrdtool dump filename.rrd >filename.xml\n\n");
75 N_("* info - returns the configuration and status of the RRD\n\n"
76 "\trrdtool info filename.rrd\n\n");
79 N_("* restore - restore an RRD file from its XML form\n\n"
80 "\trrdtool restore [--range-check|-r] [--force-overwrite|-f] filename.xml filename.rrd\n\n");
83 N_("* last - show last update time for RRD\n\n"
84 "\trrdtool last filename.rrd\n\n");
86 char help_lastupdate[] =
87 N_("* lastupdate - returns the most recent datum stored for\n"
88 " each DS in an RRD\n\n" "\trrdtool lastupdate filename.rrd\n\n");
91 N_("* first - show first update time for RRA within an RRD\n\n"
92 "\trrdtool first filename.rrd [--rraindex number]\n\n");
95 N_("* update - update an RRD\n\n"
96 "\trrdtool update filename\n"
97 "\t\t--template|-t ds-name:ds-name:...\n"
98 "\t\ttime|N:value[:value...]\n\n"
99 "\t\tat-time@value[:value...]\n\n"
100 "\t\t[ time:value[:value...] ..]\n\n");
102 char help_updatev[] =
103 N_("* updatev - a verbose version of update\n"
104 "\treturns information about values, RRAs, and datasources updated\n\n"
105 "\trrdtool updatev filename\n"
106 "\t\t--template|-t ds-name:ds-name:...\n"
107 "\t\ttime|N:value[:value...]\n\n"
108 "\t\tat-time@value[:value...]\n\n"
109 "\t\t[ time:value[:value...] ..]\n\n");
112 N_("* fetch - fetch data out of an RRD\n\n"
113 "\trrdtool fetch filename.rrd CF\n"
114 "\t\t[-r|--resolution resolution]\n"
115 "\t\t[-s|--start start] [-e|--end end]\n\n");
117 /* break up very large strings (help_graph, help_tune) for ISO C89 compliance*/
120 N_("* graph - generate a graph from one or several RRD\n\n"
121 "\trrdtool graph filename [-s|--start seconds] [-e|--end seconds]\n"
122 "\t\t[-x|--x-grid x-axis grid and label]\n"
123 "\t\t[-Y|--alt-y-grid]\n"
124 "\t\t[-y|--y-grid y-axis grid and label]\n"
125 "\t\t[-v|--vertical-label string] [-w|--width pixels]\n"
126 "\t\t[-h|--height pixels] [-o|--logarithmic]\n"
127 "\t\t[-u|--upper-limit value] [-z|--lazy]\n"
128 "\t\t[-l|--lower-limit value] [-r|--rigid]\n"
129 "\t\t[-g|--no-legend]\n"
130 "\t\t[-F|--force-rules-legend]\n" "\t\t[-j|--only-graph]\n");
132 "\t\t[-n|--font FONTTAG:size:font]\n"
133 "\t\t[-m|--zoom factor]\n"
134 "\t\t[-A|--alt-autoscale]\n"
135 "\t\t[-M|--alt-autoscale-max]\n"
136 "\t\t[-R|--font-render-mode {normal,light,mono}]\n"
137 "\t\t[-B|--font-smoothing-threshold size]\n"
138 "\t\t[-E|--slope-mode]\n"
139 "\t\t[-N|--no-gridfit]\n"
140 "\t\t[-X|--units-exponent value]\n"
141 "\t\t[-L|--units-length value]\n"
142 "\t\t[-S|--step seconds]\n"
143 "\t\t[-f|--imginfo printfstr]\n"
144 "\t\t[-a|--imgformat PNG]\n"
145 "\t\t[-c|--color COLORTAG#rrggbb[aa]] [-t|--title string]\n"
146 "\t\t[-W|--watermark string]\n" "\t\t[DEF:vname=rrd:ds-name:CF]\n";
148 "\t\t[CDEF:vname=rpn-expression]\n"
149 "\t\t[VDEF:vdefname=rpn-expression]\n"
150 "\t\t[PRINT:vdefname:format]\n"
151 "\t\t[GPRINT:vdefname:format]\n"
152 "\t\t[COMMENT:text]\n"
153 "\t\t[SHIFT:vname:offset]\n"
154 "\t\t[TICK:vname#rrggbb[aa][:[fraction][:legend]]]\n"
155 "\t\t[HRULE:value#rrggbb[aa][:legend]]\n"
156 "\t\t[VRULE:value#rrggbb[aa][:legend]]\n"
157 "\t\t[LINE[width]:vname[#rrggbb[aa][:[legend][:STACK]]]]\n"
158 "\t\t[AREA:vname[#rrggbb[aa][:[legend][:STACK]]]]\n"
159 "\t\t[PRINT:vname:CF:format] (deprecated)\n"
160 "\t\t[GPRINT:vname:CF:format] (deprecated)\n"
161 "\t\t[STACK:vname[#rrggbb[aa][:legend]]] (deprecated)\n\n";
164 N_(" * tune - Modify some basic properties of an RRD\n\n"
165 "\trrdtool tune filename\n"
166 "\t\t[--heartbeat|-h ds-name:heartbeat]\n"
167 "\t\t[--data-source-type|-d ds-name:DST]\n"
168 "\t\t[--data-source-rename|-r old-name:new-name]\n"
169 "\t\t[--minimum|-i ds-name:min] [--maximum|-a ds-name:max]\n"
170 "\t\t[--deltapos scale-value] [--deltaneg scale-value]\n"
171 "\t\t[--failure-threshold integer]\n"
172 "\t\t[--window-length integer]\n"
173 "\t\t[--alpha adaptation-parameter]\n");
175 N_(" * tune - Modify some basic properties of an RRD\n\n"
176 "\t\t[--beta adaptation-parameter]\n"
177 "\t\t[--gamma adaptation-parameter]\n"
178 "\t\t[--gamma-deviation adaptation-parameter]\n"
179 "\t\t[--aberrant-reset ds-name]\n\n");
182 N_(" * resize - alter the length of one of the RRAs in an RRD\n\n"
183 "\trrdtool resize filename rranum GROW|SHRINK rows\n\n");
186 N_("* xport - generate XML dump from one or several RRD\n\n"
187 "\trrdtool xport [-s|--start seconds] [-e|--end seconds]\n"
188 "\t\t[-m|--maxrows rows]\n"
189 "\t\t[--step seconds]\n"
191 "\t\t[DEF:vname=rrd:ds-name:CF]\n"
192 "\t\t[CDEF:vname=rpn-expression]\n" "\t\t[XPORT:vname:legend]\n\n");
195 N_(" * quit - closing a session in remote mode\n\n" "\trrdtool quit\n\n");
198 N_(" * ls - lists all *.rrd files in current directory\n\n"
202 N_(" * cd - changes the current directory\n\n"
203 "\trrdtool cd new directory\n\n");
206 N_(" * mkdir - creates a new directory\n\n"
207 "\trrdtool mkdir newdirectoryname\n\n");
210 N_(" * pwd - returns the current working directory\n\n"
211 "\trrdtool pwd\n\n");
214 N_("RRDtool is distributed under the Terms of the GNU General\n"
215 "Public License Version 2. (www.gnu.org/copyleft/gpl.html)\n\n"
216 "For more information read the RRD manpages\n\n");
218 enum { C_NONE, C_CREATE, C_DUMP, C_INFO, C_RESTORE, C_LAST,
219 C_LASTUPDATE, C_FIRST, C_UPDATE, C_FETCH, C_GRAPH, C_TUNE,
220 C_RESIZE, C_XPORT, C_QUIT, C_LS, C_CD, C_MKDIR, C_PWD,
224 int help_cmd = C_NONE;
227 if (!strcmp(cmd, "create"))
229 else if (!strcmp(cmd, "dump"))
231 else if (!strcmp(cmd, "info"))
233 else if (!strcmp(cmd, "restore"))
234 help_cmd = C_RESTORE;
235 else if (!strcmp(cmd, "last"))
237 else if (!strcmp(cmd, "lastupdate"))
238 help_cmd = C_LASTUPDATE;
239 else if (!strcmp(cmd, "first"))
241 else if (!strcmp(cmd, "update"))
243 else if (!strcmp(cmd, "updatev"))
244 help_cmd = C_UPDATEV;
245 else if (!strcmp(cmd, "fetch"))
247 else if (!strcmp(cmd, "graph"))
249 else if (!strcmp(cmd, "tune"))
251 else if (!strcmp(cmd, "resize"))
253 else if (!strcmp(cmd, "xport"))
255 else if (!strcmp(cmd, "quit"))
257 else if (!strcmp(cmd, "ls"))
259 else if (!strcmp(cmd, "cd"))
261 else if (!strcmp(cmd, "mkdir"))
263 else if (!strcmp(cmd, "pwd"))
266 fprintf (stdout, _(help_main), PACKAGE_VERSION, __DATE__, __TIME__);
270 fputs(_(help_list), stdout);
272 fputs(_(help_listremote), stdout);
276 fputs(_(help_create), stdout);
279 fputs(_(help_dump), stdout);
282 fputs(_(help_info), stdout);
285 fputs(_(help_restore), stdout);
288 fputs(_(help_last), stdout);
291 fputs(_(help_lastupdate), stdout);
294 fputs(_(help_first), stdout);
297 fputs(_(help_update), stdout);
300 fputs(_(help_updatev), stdout);
303 fputs(_(help_fetch), stdout);
306 fputs(_(help_graph1), stdout);
307 fputs(help_graph2, stdout);
308 fputs(help_graph3, stdout);
311 fputs(_(help_tune1), stdout);
312 fputs(_(help_tune2), stdout);
315 fputs(_(help_resize), stdout);
318 fputs(_(help_xport), stdout);
321 fputs(_(help_quit), stdout);
324 fputs(_(help_ls), stdout);
327 fputs(_(help_cd), stdout);
330 fputs(_(help_mkdir), stdout);
333 fputs(_(help_pwd), stdout);
336 fputs(_(help_lic), stdout);
339 static char *fgetslong(
344 size_t bufsize = MAX_LENGTH;
348 return *aLinePtr = 0;
349 if (!(linebuf = malloc(bufsize))) {
350 perror("fgetslong: malloc");
354 while (fgets(linebuf + eolpos, MAX_LENGTH, stream)) {
355 eolpos += strlen(linebuf + eolpos);
356 if (linebuf[eolpos - 1] == '\n')
357 return *aLinePtr = linebuf;
358 bufsize += MAX_LENGTH;
359 if (!(linebuf = realloc(linebuf, bufsize))) {
360 perror("fgetslong: realloc");
364 return *aLinePtr = linebuf[0] ? linebuf : 0;
375 #ifdef MUST_DISABLE_SIGFPE
376 signal(SIGFPE, SIG_IGN);
378 #ifdef MUST_DISABLE_FPMASK
382 setlocale (LC_ALL, "");
384 #ifdef HAVE_LIBINTL_H
385 bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
386 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
387 textdomain (GETTEXT_PACKAGE);
394 if (((argc == 2) || (argc == 3)) && !strcmp("-", argv[1])) {
396 struct rusage myusage;
397 struct timeval starttime;
398 struct timeval currenttime;
400 gettimeofday(&starttime, NULL);
403 if ((argc == 3) && strcmp("", argv[2])) {
417 "ERROR: can't change root to '%s' errno=%d\n",
425 "ERROR: change root is not supported by your OS "
426 "or at least by this copy of rrdtool\n");
433 if (strcmp(firstdir, "")) {
436 fprintf(stderr, "ERROR: %s\n", rrd_strerror(errno));
441 while (fgetslong(&aLine, stdin)) {
442 if ((argc = CountArgs(aLine)) == 0) {
443 printf("ERROR: not enough arguments\n");
445 if ((myargv = (char **) malloc((argc + 1) *
446 sizeof(char *))) == NULL) {
450 if ((argc = CreateArgs(argv[0], aLine, argc, myargv)) < 0) {
451 printf("ERROR: creating arguments\n");
453 int ret = HandleInputLine(argc, myargv, stdout);
458 getrusage(RUSAGE_SELF, &myusage);
459 gettimeofday(¤ttime, NULL);
460 printf("OK u:%1.2f s:%1.2f r:%1.2f\n",
461 (double) myusage.ru_utime.tv_sec +
462 (double) myusage.ru_utime.tv_usec / 1000000.0,
463 (double) myusage.ru_stime.tv_sec +
464 (double) myusage.ru_stime.tv_usec / 1000000.0,
465 (double) (currenttime.tv_sec - starttime.tv_sec)
466 + (double) (currenttime.tv_usec -
475 fflush(stdout); /* this is important for pipes to work */
478 } else if (argc == 2) {
481 } else if (argc == 3 && !strcmp(argv[1], "help")) {
485 exit(HandleInputLine(argc, argv, stderr));
490 /* HandleInputLine is NOT thread safe - due to readdir issues,
491 resolving them portably is not really simple. */
497 #if defined(HAVE_OPENDIR) && defined (HAVE_READDIR)
498 DIR *curdir; /* to read current dir with ls */
501 #if defined(HAVE_SYS_STAT_H)
504 char *cwd; /* To hold current working dir on call to pwd */
506 /* Reset errno to 0 before we start.
511 if (argc > 1 && strcmp("quit", argv[1]) == 0) {
513 printf("ERROR: invalid parameter count for quit\n");
518 #if defined(HAVE_OPENDIR) && defined(HAVE_READDIR) && defined(HAVE_CHDIR)
519 if (argc > 1 && strcmp("cd", argv[1]) == 0) {
521 printf("ERROR: invalid parameter count for cd\n");
524 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
525 if (getuid() == 0 && !ChangeRoot) {
527 ("ERROR: chdir security problem - rrdtool is running as "
528 "root but not chroot!\n");
534 printf("ERROR: %s\n", rrd_strerror(errno));
539 if (argc > 1 && strcmp("pwd", argv[1]) == 0) {
541 printf("ERROR: invalid parameter count for pwd\n");
544 cwd = getcwd(NULL, MAXPATH);
546 printf("ERROR: %s\n", rrd_strerror(errno));
553 if (argc > 1 && strcmp("mkdir", argv[1]) == 0) {
555 printf("ERROR: invalid parameter count for mkdir\n");
558 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
559 if (getuid() == 0 && !ChangeRoot) {
561 ("ERROR: mkdir security problem - rrdtool is running as "
562 "root but not chroot!\n");
566 mkdir(argv[2], 0777);
568 printf("ERROR: %s\n", rrd_strerror(errno));
573 if (argc > 1 && strcmp("ls", argv[1]) == 0) {
575 printf("ERROR: invalid parameter count for ls\n");
578 if ((curdir = opendir(".")) != NULL) {
579 while ((dent = readdir(curdir)) != NULL) {
580 if (!stat(dent->d_name, &st)) {
581 if (S_ISDIR(st.st_mode)) {
582 printf("d %s\n", dent->d_name);
584 if (strlen(dent->d_name) > 4 && S_ISREG(st.st_mode)) {
586 (dent->d_name + NAMLEN(dent) - 4, ".rrd")
587 || !strcmp(dent->d_name + NAMLEN(dent) - 4,
589 printf("- %s\n", dent->d_name);
596 printf("ERROR: %s\n", rrd_strerror(errno));
601 #endif /* opendir and readdir */
605 || strcmp("help", argv[1]) == 0
606 || strcmp("--help", argv[1]) == 0
607 || strcmp("-help", argv[1]) == 0
608 || strcmp("-?", argv[1]) == 0 || strcmp("-h", argv[1]) == 0) {
613 if (strcmp("create", argv[1]) == 0)
614 rrd_create(argc - 1, &argv[1]);
615 else if (strcmp("dump", argv[1]) == 0)
616 rrd_dump(argc - 1, &argv[1]);
617 else if (strcmp("info", argv[1]) == 0 || strcmp("updatev", argv[1]) == 0) {
620 if (strcmp("info", argv[1]) == 0)
621 data = rrd_info(argc - 1, &argv[1]);
623 data = rrd_update_v(argc - 1, &argv[1]);
626 printf("%s = ", data->key);
629 switch (data->type) {
631 if (isnan(data->value.u_val))
634 printf("%0.10e", data->value.u_val);
637 printf("%lu", data->value.u_cnt);
640 printf("%d", data->value.u_int);
643 printf("\"%s\"", data->value.u_str);
644 free(data->value.u_str);
654 else if (strcmp("--version", argv[1]) == 0 ||
655 strcmp("version", argv[1]) == 0 ||
656 strcmp("v", argv[1]) == 0 ||
657 strcmp("-v", argv[1]) == 0 || strcmp("-version", argv[1]) == 0)
658 printf("RRDtool " PACKAGE_VERSION
659 " Copyright by Tobi Oetiker, 1997-2005 (%f)\n",
661 else if (strcmp("restore", argv[1]) == 0)
662 rrd_restore(argc - 1, &argv[1]);
663 else if (strcmp("resize", argv[1]) == 0)
664 rrd_resize(argc - 1, &argv[1]);
665 else if (strcmp("last", argv[1]) == 0)
666 printf("%ld\n", rrd_last(argc - 1, &argv[1]));
667 else if (strcmp("lastupdate", argv[1]) == 0) {
671 unsigned long ds_cnt, i;
673 if (rrd_lastupdate(argc - 1, &argv[1], &last_update,
674 &ds_cnt, &ds_namv, &last_ds) == 0) {
675 for (i = 0; i < ds_cnt; i++)
676 printf(" %s", ds_namv[i]);
678 printf("%10lu:", last_update);
679 for (i = 0; i < ds_cnt; i++) {
680 printf(" %s", last_ds[i]);
688 } else if (strcmp("first", argv[1]) == 0)
689 printf("%ld\n", rrd_first(argc - 1, &argv[1]));
690 else if (strcmp("update", argv[1]) == 0)
691 rrd_update(argc - 1, &argv[1]);
692 else if (strcmp("fetch", argv[1]) == 0) {
693 time_t start, end, ti;
694 unsigned long step, ds_cnt, i, ii;
695 rrd_value_t *data, *datai;
699 (argc - 1, &argv[1], &start, &end, &step, &ds_cnt, &ds_namv,
703 for (i = 0; i < ds_cnt; i++)
704 printf("%20s", ds_namv[i]);
706 for (ti = start + step; ti <= end; ti += step) {
707 printf("%10lu:", ti);
708 for (ii = 0; ii < ds_cnt; ii++)
709 printf(" %0.10e", *(datai++));
712 for (i = 0; i < ds_cnt; i++)
717 } else if (strcmp("xport", argv[1]) == 0) {
719 unsigned long int j = 0;
720 time_t start, end, ti;
721 unsigned long step, col_cnt, row_cnt;
722 rrd_value_t *data, *ptr;
726 size_t vtag_s = strlen(COL_DATA_TAG) + 10;
727 char *vtag = malloc(vtag_s);
729 for (i = 2; i < argc; i++) {
730 if (strcmp("--enumds", argv[i]) == 0)
735 (argc - 1, &argv[1], &xxsize, &start, &end, &step, &col_cnt,
736 &legend_v, &data) != -1) {
737 row_cnt = (end - start) / step;
739 printf("<?xml version=\"1.0\" encoding=\"%s\"?>\n\n",
741 printf("<%s>\n", ROOT_TAG);
742 printf(" <%s>\n", META_TAG);
743 printf(" <%s>%lu</%s>\n", META_START_TAG, start + step,
745 printf(" <%s>%lu</%s>\n", META_STEP_TAG, step, META_STEP_TAG);
746 printf(" <%s>%lu</%s>\n", META_END_TAG, end, META_END_TAG);
747 printf(" <%s>%lu</%s>\n", META_ROWS_TAG, row_cnt,
749 printf(" <%s>%lu</%s>\n", META_COLS_TAG, col_cnt,
751 printf(" <%s>\n", LEGEND_TAG);
752 for (j = 0; j < col_cnt; j++) {
756 printf(" <%s>%s</%s>\n", LEGEND_ENTRY_TAG, entry,
761 printf(" </%s>\n", LEGEND_TAG);
762 printf(" </%s>\n", META_TAG);
763 printf(" <%s>\n", DATA_TAG);
764 for (ti = start + step; ti <= end; ti += step) {
765 printf(" <%s>", DATA_ROW_TAG);
766 printf("<%s>%lu</%s>", COL_TIME_TAG, ti, COL_TIME_TAG);
767 for (j = 0; j < col_cnt; j++) {
768 rrd_value_t newval = DNAN;
771 snprintf(vtag, vtag_s, "%s%lu", COL_DATA_TAG, j);
773 snprintf(vtag, vtag_s, "%s", COL_DATA_TAG);
777 printf("<%s>NaN</%s>", vtag, vtag);
779 printf("<%s>%0.10e</%s>", vtag, newval, vtag);
783 printf("</%s>\n", DATA_ROW_TAG);
786 printf(" </%s>\n", DATA_TAG);
787 printf("</%s>\n", ROOT_TAG);
790 } else if (strcmp("graph", argv[1]) == 0) {
793 #ifdef notused /*XXX*/
794 const char *imgfile = argv[2]; /* rrd_graph changes argv pointer */
799 int tostdout = (strcmp(argv[2], "-") == 0);
802 for (i = 2; i < argc; i++) {
803 if (strcmp(argv[i], "--imginfo") == 0
804 || strcmp(argv[i], "-f") == 0) {
810 (argc - 1, &argv[1], &calcpr, &xsize, &ysize, NULL, &ymin,
812 if (!tostdout && !imginfo)
813 printf("%dx%d\n", xsize, ysize);
815 for (i = 0; calcpr[i]; i++) {
817 printf("%s\n", calcpr[i]);
824 } else if (strcmp("tune", argv[1]) == 0)
825 rrd_tune(argc - 1, &argv[1]);
827 rrd_set_error("unknown function '%s'", argv[1]);
829 if (rrd_test_error()) {
830 fprintf(out, "ERROR: %s\n", rrd_get_error());
844 while (aLine[i] == ' ')
846 while (aLine[i] != 0) {
847 if ((aLine[i] == ' ') && inarg) {
850 if ((aLine[i] != ' ') && !inarg) {
860 * CreateArgs - take a string (aLine) and tokenize
875 /* remove trailing space and newlines */
876 while (len && aLine[len] <= ' ') {
880 /* sikp leading blanks */
881 while (*aLine && *aLine <= ' ')
908 pargv[argc++] = putP;
916 pargv[argc++] = putP;