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
48 const char *help_main =
50 " Copyright 1997-2007 by Tobias Oetiker <tobi@oetiker.ch>\n"
52 "Usage: rrdtool [options] command command_options\n\n");
54 const char *help_list =
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 const char *help_listremote =
60 N_("Valid remote commands: quit, ls, cd, mkdir, pwd\n\n");
63 const char *help_create =
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");
70 const char *help_dump =
71 N_("* dump - dump an RRD to XML\n\n"
72 "\trrdtool dump filename.rrd >filename.xml\n\n");
74 const char *help_info =
75 N_("* info - returns the configuration and status of the RRD\n\n"
76 "\trrdtool info filename.rrd\n\n");
78 const char *help_restore =
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");
82 const char *help_last =
83 N_("* last - show last update time for RRD\n\n"
84 "\trrdtool last filename.rrd\n\n");
86 const 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");
90 const char *help_first =
91 N_("* first - show first update time for RRA within an RRD\n\n"
92 "\trrdtool first filename.rrd [--rraindex number]\n\n");
94 const char *help_update =
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 const 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");
111 const char *help_fetch =
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*/
119 const char *help_graph1 =
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");
131 const char *help_graph2 =
132 N_("\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"
147 "\t\t[DEF:vname=rrd:ds-name:CF]\n");
148 const char *help_graph3 =
149 N_("\t\t[CDEF:vname=rpn-expression]\n"
150 "\t\t[VDEF:vdefname=rpn-expression]\n"
151 "\t\t[PRINT:vdefname:format]\n" "\t\t[GPRINT:vdefname:format]\n"
152 "\t\t[COMMENT:text]\n" "\t\t[SHIFT:vname:offset]\n"
153 "\t\t[TICK:vname#rrggbb[aa][:[fraction][:legend]]]\n"
154 "\t\t[HRULE:value#rrggbb[aa][:legend]]\n"
155 "\t\t[VRULE:value#rrggbb[aa][:legend]]\n"
156 "\t\t[LINE[width]:vname[#rrggbb[aa][:[legend][:STACK]]]]\n"
157 "\t\t[AREA:vname[#rrggbb[aa][:[legend][:STACK]]]]\n"
158 "\t\t[PRINT:vname:CF:format] (deprecated)\n"
159 "\t\t[GPRINT:vname:CF:format] (deprecated)\n"
160 "\t\t[STACK:vname[#rrggbb[aa][:legend]]] (deprecated)\n\n");
162 const char *help_tune1 =
163 N_(" * tune - Modify some basic properties of an RRD\n\n"
164 "\trrdtool tune filename\n"
165 "\t\t[--heartbeat|-h ds-name:heartbeat]\n"
166 "\t\t[--data-source-type|-d ds-name:DST]\n"
167 "\t\t[--data-source-rename|-r old-name:new-name]\n"
168 "\t\t[--minimum|-i ds-name:min] [--maximum|-a ds-name:max]\n"
169 "\t\t[--deltapos scale-value] [--deltaneg scale-value]\n"
170 "\t\t[--failure-threshold integer]\n"
171 "\t\t[--window-length integer]\n"
172 "\t\t[--alpha adaptation-parameter]\n");
173 const char *help_tune2 =
174 N_(" * tune - Modify some basic properties of an RRD\n\n"
175 "\t\t[--beta adaptation-parameter]\n"
176 "\t\t[--gamma adaptation-parameter]\n"
177 "\t\t[--gamma-deviation adaptation-parameter]\n"
178 "\t\t[--aberrant-reset ds-name]\n\n");
180 const char *help_resize =
181 N_(" * resize - alter the length of one of the RRAs in an RRD\n\n"
182 "\trrdtool resize filename rranum GROW|SHRINK rows\n\n");
184 const char *help_xport =
185 N_("* xport - generate XML dump from one or several RRD\n\n"
186 "\trrdtool xport [-s|--start seconds] [-e|--end seconds]\n"
187 "\t\t[-m|--maxrows rows]\n"
188 "\t\t[--step seconds]\n"
190 "\t\t[DEF:vname=rrd:ds-name:CF]\n"
191 "\t\t[CDEF:vname=rpn-expression]\n"
192 "\t\t[XPORT:vname:legend]\n\n");
194 const char *help_quit =
195 N_(" * quit - closing a session in remote mode\n\n"
196 "\trrdtool quit\n\n");
198 const char *help_ls =
199 N_(" * ls - lists all *.rrd files in current directory\n\n"
202 const char *help_cd =
203 N_(" * cd - changes the current directory\n\n"
204 "\trrdtool cd new directory\n\n");
206 const char *help_mkdir =
207 N_(" * mkdir - creates a new directory\n\n"
208 "\trrdtool mkdir newdirectoryname\n\n");
210 const char *help_pwd =
211 N_(" * pwd - returns the current working directory\n\n"
212 "\trrdtool pwd\n\n");
214 const char *help_lic =
215 N_("RRDtool is distributed under the Terms of the GNU General\n"
216 "Public License Version 2. (www.gnu.org/copyleft/gpl.html)\n\n"
217 "For more information read the RRD manpages\n\n");
219 enum { C_NONE, C_CREATE, C_DUMP, C_INFO, C_RESTORE, C_LAST,
220 C_LASTUPDATE, C_FIRST, C_UPDATE, C_FETCH, C_GRAPH, C_TUNE,
221 C_RESIZE, C_XPORT, C_QUIT, C_LS, C_CD, C_MKDIR, C_PWD,
225 int help_cmd = C_NONE;
228 if (!strcmp(cmd, "create"))
230 else if (!strcmp(cmd, "dump"))
232 else if (!strcmp(cmd, "info"))
234 else if (!strcmp(cmd, "restore"))
235 help_cmd = C_RESTORE;
236 else if (!strcmp(cmd, "last"))
238 else if (!strcmp(cmd, "lastupdate"))
239 help_cmd = C_LASTUPDATE;
240 else if (!strcmp(cmd, "first"))
242 else if (!strcmp(cmd, "update"))
244 else if (!strcmp(cmd, "updatev"))
245 help_cmd = C_UPDATEV;
246 else if (!strcmp(cmd, "fetch"))
248 else if (!strcmp(cmd, "graph"))
250 else if (!strcmp(cmd, "tune"))
252 else if (!strcmp(cmd, "resize"))
254 else if (!strcmp(cmd, "xport"))
256 else if (!strcmp(cmd, "quit"))
258 else if (!strcmp(cmd, "ls"))
260 else if (!strcmp(cmd, "cd"))
262 else if (!strcmp(cmd, "mkdir"))
264 else if (!strcmp(cmd, "pwd"))
267 fprintf(stdout, _(help_main), PACKAGE_VERSION, __DATE__, __TIME__);
271 fputs(_(help_list), stdout);
273 fputs(_(help_listremote), stdout);
277 fputs(_(help_create), stdout);
280 fputs(_(help_dump), stdout);
283 fputs(_(help_info), stdout);
286 fputs(_(help_restore), stdout);
289 fputs(_(help_last), stdout);
292 fputs(_(help_lastupdate), stdout);
295 fputs(_(help_first), stdout);
298 fputs(_(help_update), stdout);
301 fputs(_(help_updatev), stdout);
304 fputs(_(help_fetch), stdout);
307 fputs(_(help_graph1), stdout);
308 fputs(help_graph2, stdout);
309 fputs(help_graph3, stdout);
312 fputs(_(help_tune1), stdout);
313 fputs(_(help_tune2), stdout);
316 fputs(_(help_resize), stdout);
319 fputs(_(help_xport), stdout);
322 fputs(_(help_quit), stdout);
325 fputs(_(help_ls), stdout);
328 fputs(_(help_cd), stdout);
331 fputs(_(help_mkdir), stdout);
334 fputs(_(help_pwd), stdout);
337 fputs(_(help_lic), stdout);
340 static char *fgetslong(
345 size_t bufsize = MAX_LENGTH;
349 return *aLinePtr = 0;
350 if (!(linebuf = malloc(bufsize))) {
351 perror("fgetslong: malloc");
355 while (fgets(linebuf + eolpos, MAX_LENGTH, stream)) {
356 eolpos += strlen(linebuf + eolpos);
357 if (linebuf[eolpos - 1] == '\n')
358 return *aLinePtr = linebuf;
359 bufsize += MAX_LENGTH;
360 if (!(linebuf = realloc(linebuf, bufsize))) {
361 perror("fgetslong: realloc");
365 return *aLinePtr = linebuf[0] ? linebuf : 0;
376 #ifdef MUST_DISABLE_SIGFPE
377 signal(SIGFPE, SIG_IGN);
379 #ifdef MUST_DISABLE_FPMASK
383 setlocale(LC_ALL, "");
385 #ifdef HAVE_LIBINTL_H
386 bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
387 bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
388 textdomain(GETTEXT_PACKAGE);
395 if (((argc == 2) || (argc == 3)) && !strcmp("-", argv[1])) {
397 struct rusage myusage;
398 struct timeval starttime;
399 struct timeval currenttime;
401 gettimeofday(&starttime, NULL);
404 if ((argc == 3) && strcmp("", argv[2])) {
418 "ERROR: can't change root to '%s' errno=%d\n",
426 "ERROR: change root is not supported by your OS "
427 "or at least by this copy of rrdtool\n");
434 if (strcmp(firstdir, "")) {
437 fprintf(stderr, "ERROR: %s\n", rrd_strerror(errno));
442 while (fgetslong(&aLine, stdin)) {
443 if ((argc = CountArgs(aLine)) == 0) {
444 printf("ERROR: not enough arguments\n");
446 if ((myargv = (char **) malloc((argc + 1) *
447 sizeof(char *))) == NULL) {
451 if ((argc = CreateArgs(argv[0], aLine, argc, myargv)) < 0) {
452 printf("ERROR: creating arguments\n");
454 int ret = HandleInputLine(argc, myargv, stdout);
459 getrusage(RUSAGE_SELF, &myusage);
460 gettimeofday(¤ttime, NULL);
461 printf("OK u:%1.2f s:%1.2f r:%1.2f\n",
462 (double) myusage.ru_utime.tv_sec +
463 (double) myusage.ru_utime.tv_usec / 1000000.0,
464 (double) myusage.ru_stime.tv_sec +
465 (double) myusage.ru_stime.tv_usec / 1000000.0,
466 (double) (currenttime.tv_sec - starttime.tv_sec)
467 + (double) (currenttime.tv_usec -
476 fflush(stdout); /* this is important for pipes to work */
479 } else if (argc == 2) {
482 } else if (argc == 3 && !strcmp(argv[1], "help")) {
486 exit(HandleInputLine(argc, argv, stderr));
491 /* HandleInputLine is NOT thread safe - due to readdir issues,
492 resolving them portably is not really simple. */
498 #if defined(HAVE_OPENDIR) && defined (HAVE_READDIR)
499 DIR *curdir; /* to read current dir with ls */
502 #if defined(HAVE_SYS_STAT_H)
505 char *cwd; /* To hold current working dir on call to pwd */
507 /* Reset errno to 0 before we start.
512 if (argc > 1 && strcmp("quit", argv[1]) == 0) {
514 printf("ERROR: invalid parameter count for quit\n");
519 #if defined(HAVE_OPENDIR) && defined(HAVE_READDIR) && defined(HAVE_CHDIR)
520 if (argc > 1 && strcmp("cd", argv[1]) == 0) {
522 printf("ERROR: invalid parameter count for cd\n");
525 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
526 if (getuid() == 0 && !ChangeRoot) {
528 ("ERROR: chdir security problem - rrdtool is running as "
529 "root but not chroot!\n");
535 printf("ERROR: %s\n", rrd_strerror(errno));
540 if (argc > 1 && strcmp("pwd", argv[1]) == 0) {
542 printf("ERROR: invalid parameter count for pwd\n");
545 cwd = getcwd(NULL, MAXPATH);
547 printf("ERROR: %s\n", rrd_strerror(errno));
554 if (argc > 1 && strcmp("mkdir", argv[1]) == 0) {
556 printf("ERROR: invalid parameter count for mkdir\n");
559 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
560 if (getuid() == 0 && !ChangeRoot) {
562 ("ERROR: mkdir security problem - rrdtool is running as "
563 "root but not chroot!\n");
567 mkdir(argv[2], 0777);
569 printf("ERROR: %s\n", rrd_strerror(errno));
574 if (argc > 1 && strcmp("ls", argv[1]) == 0) {
576 printf("ERROR: invalid parameter count for ls\n");
579 if ((curdir = opendir(".")) != NULL) {
580 while ((dent = readdir(curdir)) != NULL) {
581 if (!stat(dent->d_name, &st)) {
582 if (S_ISDIR(st.st_mode)) {
583 printf("d %s\n", dent->d_name);
585 if (strlen(dent->d_name) > 4 && S_ISREG(st.st_mode)) {
587 (dent->d_name + NAMLEN(dent) - 4, ".rrd")
588 || !strcmp(dent->d_name + NAMLEN(dent) - 4,
590 printf("- %s\n", dent->d_name);
597 printf("ERROR: %s\n", rrd_strerror(errno));
602 #endif /* opendir and readdir */
606 || strcmp("help", argv[1]) == 0
607 || strcmp("--help", argv[1]) == 0
608 || strcmp("-help", argv[1]) == 0
609 || strcmp("-?", argv[1]) == 0 || strcmp("-h", argv[1]) == 0) {
614 if (strcmp("create", argv[1]) == 0)
615 rrd_create(argc - 1, &argv[1]);
616 else if (strcmp("dump", argv[1]) == 0)
617 rrd_dump(argc - 1, &argv[1]);
618 else if (strcmp("info", argv[1]) == 0 || strcmp("updatev", argv[1]) == 0) {
621 if (strcmp("info", argv[1]) == 0)
622 data = rrd_info(argc - 1, &argv[1]);
624 data = rrd_update_v(argc - 1, &argv[1]);
627 printf("%s = ", data->key);
630 switch (data->type) {
632 if (isnan(data->value.u_val))
635 printf("%0.10e", data->value.u_val);
638 printf("%lu", data->value.u_cnt);
641 printf("%d", data->value.u_int);
644 printf("\"%s\"", data->value.u_str);
645 free(data->value.u_str);
655 else if (strcmp("--version", argv[1]) == 0 ||
656 strcmp("version", argv[1]) == 0 ||
657 strcmp("v", argv[1]) == 0 ||
658 strcmp("-v", argv[1]) == 0 || strcmp("-version", argv[1]) == 0)
659 printf("RRDtool " PACKAGE_VERSION
660 " Copyright by Tobi Oetiker, 1997-2005 (%f)\n",
662 else if (strcmp("restore", argv[1]) == 0)
663 rrd_restore(argc - 1, &argv[1]);
664 else if (strcmp("resize", argv[1]) == 0)
665 rrd_resize(argc - 1, &argv[1]);
666 else if (strcmp("last", argv[1]) == 0)
667 printf("%ld\n", rrd_last(argc - 1, &argv[1]));
668 else if (strcmp("lastupdate", argv[1]) == 0) {
672 unsigned long ds_cnt, i;
674 if (rrd_lastupdate(argc - 1, &argv[1], &last_update,
675 &ds_cnt, &ds_namv, &last_ds) == 0) {
676 for (i = 0; i < ds_cnt; i++)
677 printf(" %s", ds_namv[i]);
679 printf("%10lu:", last_update);
680 for (i = 0; i < ds_cnt; i++) {
681 printf(" %s", last_ds[i]);
689 } else if (strcmp("first", argv[1]) == 0)
690 printf("%ld\n", rrd_first(argc - 1, &argv[1]));
691 else if (strcmp("update", argv[1]) == 0)
692 rrd_update(argc - 1, &argv[1]);
693 else if (strcmp("fetch", argv[1]) == 0) {
694 time_t start, end, ti;
695 unsigned long step, ds_cnt, i, ii;
696 rrd_value_t *data, *datai;
700 (argc - 1, &argv[1], &start, &end, &step, &ds_cnt, &ds_namv,
704 for (i = 0; i < ds_cnt; i++)
705 printf("%20s", ds_namv[i]);
707 for (ti = start + step; ti <= end; ti += step) {
708 printf("%10lu:", ti);
709 for (ii = 0; ii < ds_cnt; ii++)
710 printf(" %0.10e", *(datai++));
713 for (i = 0; i < ds_cnt; i++)
718 } else if (strcmp("xport", argv[1]) == 0) {
720 unsigned long int j = 0;
721 time_t start, end, ti;
722 unsigned long step, col_cnt, row_cnt;
723 rrd_value_t *data, *ptr;
727 size_t vtag_s = strlen(COL_DATA_TAG) + 10;
728 char *vtag = malloc(vtag_s);
730 for (i = 2; i < argc; i++) {
731 if (strcmp("--enumds", argv[i]) == 0)
736 (argc - 1, &argv[1], &xxsize, &start, &end, &step, &col_cnt,
737 &legend_v, &data) != -1) {
738 row_cnt = (end - start) / step;
740 printf("<?xml version=\"1.0\" encoding=\"%s\"?>\n\n",
742 printf("<%s>\n", ROOT_TAG);
743 printf(" <%s>\n", META_TAG);
744 printf(" <%s>%lu</%s>\n", META_START_TAG,
745 (unsigned long) start + step, META_START_TAG);
746 printf(" <%s>%lu</%s>\n", META_STEP_TAG, step, META_STEP_TAG);
747 printf(" <%s>%lu</%s>\n", META_END_TAG, (unsigned long) end,
749 printf(" <%s>%lu</%s>\n", META_ROWS_TAG, row_cnt,
751 printf(" <%s>%lu</%s>\n", META_COLS_TAG, col_cnt,
753 printf(" <%s>\n", LEGEND_TAG);
754 for (j = 0; j < col_cnt; j++) {
758 printf(" <%s>%s</%s>\n", LEGEND_ENTRY_TAG, entry,
763 printf(" </%s>\n", LEGEND_TAG);
764 printf(" </%s>\n", META_TAG);
765 printf(" <%s>\n", DATA_TAG);
766 for (ti = start + step; ti <= end; ti += step) {
767 printf(" <%s>", DATA_ROW_TAG);
768 printf("<%s>%lu</%s>", COL_TIME_TAG, ti, COL_TIME_TAG);
769 for (j = 0; j < col_cnt; j++) {
770 rrd_value_t newval = DNAN;
773 snprintf(vtag, vtag_s, "%s%lu", COL_DATA_TAG, j);
775 snprintf(vtag, vtag_s, "%s", COL_DATA_TAG);
779 printf("<%s>NaN</%s>", vtag, vtag);
781 printf("<%s>%0.10e</%s>", vtag, newval, vtag);
785 printf("</%s>\n", DATA_ROW_TAG);
788 printf(" </%s>\n", DATA_TAG);
789 printf("</%s>\n", ROOT_TAG);
792 } else if (strcmp("graph", argv[1]) == 0) {
795 #ifdef notused /*XXX*/
796 const char *imgfile = argv[2]; /* rrd_graph changes argv pointer */
801 int tostdout = (strcmp(argv[2], "-") == 0);
804 for (i = 2; i < argc; i++) {
805 if (strcmp(argv[i], "--imginfo") == 0
806 || strcmp(argv[i], "-f") == 0) {
812 (argc - 1, &argv[1], &calcpr, &xsize, &ysize, NULL, &ymin,
814 if (!tostdout && !imginfo)
815 printf("%dx%d\n", xsize, ysize);
817 for (i = 0; calcpr[i]; i++) {
819 printf("%s\n", calcpr[i]);
826 } else if (strcmp("tune", argv[1]) == 0)
827 rrd_tune(argc - 1, &argv[1]);
829 rrd_set_error("unknown function '%s'", argv[1]);
831 if (rrd_test_error()) {
832 fprintf(out, "ERROR: %s\n", rrd_get_error());
846 while (aLine[i] == ' ')
848 while (aLine[i] != 0) {
849 if ((aLine[i] == ' ') && inarg) {
852 if ((aLine[i] != ' ') && !inarg) {
862 * CreateArgs - take a string (aLine) and tokenize
877 /* remove trailing space and newlines */
878 while (len && aLine[len] <= ' ') {
882 /* sikp leading blanks */
883 while (*aLine && *aLine <= ' ')
910 pargv[argc++] = putP;
918 pargv[argc++] = putP;