1 /*****************************************************************************
2 * RRDtool 1.4.3 Copyright by Tobi Oetiker, 1997-2010
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"
15 #include "../rrd_config.h"
20 #include "rrd_xport.h"
43 #define MAX_LENGTH 10000
50 const char *help_main =
52 " Copyright 1997-2009 by Tobias Oetiker <tobi@oetiker.ch>\n"
54 "Usage: rrdtool [options] command command_options\n");
56 const char *help_list =
58 ("Valid commands: create, update, updatev, graph, graphv, dump, restore,\n"
59 "\t\tlast, lastupdate, first, info, fetch, tune,\n"
60 "\t\tresize, xport, flushcached\n");
62 const char *help_listremote =
63 N_("Valid remote commands: quit, ls, cd, mkdir, pwd\n");
66 const char *help_create =
67 N_("* create - create a new RRD\n\n"
68 "\trrdtool create filename [--start|-b start time]\n"
69 "\t\t[--step|-s step]\n"
70 "\t\t[--no-overwrite|-O]\n"
71 "\t\t[DS:ds-name:DST:dst arguments]\n"
72 "\t\t[RRA:CF:cf arguments]\n");
74 const char *help_dump =
75 N_("* dump - dump an RRD to XML\n\n"
76 "\trrdtool dump filename.rrd >filename.xml\n");
78 const char *help_info =
79 N_("* info - returns the configuration and status of the RRD\n\n"
80 "\trrdtool info filename.rrd\n");
82 const char *help_restore =
83 N_("* restore - restore an RRD file from its XML form\n\n"
84 "\trrdtool restore [--range-check|-r] [--force-overwrite|-f] filename.xml filename.rrd\n");
86 const char *help_last =
87 N_("* last - show last update time for RRD\n\n"
88 "\trrdtool last filename.rrd\n");
90 const char *help_lastupdate =
91 N_("* lastupdate - returns the most recent datum stored for\n"
92 " each DS in an RRD\n\n" "\trrdtool lastupdate filename.rrd\n");
94 const char *help_first =
95 N_("* first - show first update time for RRA within an RRD\n\n"
96 "\trrdtool first filename.rrd [--rraindex number]\n");
98 const char *help_update =
99 N_("* update - update an RRD\n\n"
100 "\trrdtool update filename\n"
101 "\t\t[--template|-t ds-name:ds-name:...]\n"
102 "\t\t[--daemon <address>]\n"
103 "\t\ttime|N:value[:value...]\n\n"
104 "\t\tat-time@value[:value...]\n\n"
105 "\t\t[ time:value[:value...] ..]\n");
107 const char *help_updatev =
108 N_("* updatev - a verbose version of update\n"
109 "\treturns information about values, RRAs, and datasources updated\n\n"
110 "\trrdtool updatev filename\n"
111 "\t\t[--template|-t ds-name:ds-name:...]\n"
112 "\t\ttime|N:value[:value...]\n\n"
113 "\t\tat-time@value[:value...]\n\n"
114 "\t\t[ time:value[:value...] ..]\n");
116 const char *help_fetch =
117 N_("* fetch - fetch data out of an RRD\n\n"
118 "\trrdtool fetch filename.rrd CF\n"
119 "\t\t[-r|--resolution resolution]\n"
120 "\t\t[-s|--start start] [-e|--end end]\n"
121 "\t\t[--daemon <address>]\n");
123 const char *help_flushcached =
124 N_("* flushcached - flush cached data out to an RRD file\n\n"
125 "\trrdtool flushcached filename.rrd\n"
126 "\t\t[--daemon <address>]\n");
128 /* break up very large strings (help_graph, help_tune) for ISO C89 compliance*/
130 const char *help_graph0 =
131 N_("* graph - generate a graph from one or several RRD\n\n"
132 "\trrdtool graph filename [-s|--start seconds] [-e|--end seconds]\n");
133 const char *help_graphv0 =
134 N_("* graphv - generate a graph from one or several RRD\n"
135 " with meta data printed before the graph\n\n"
136 "\trrdtool graphv filename [-s|--start seconds] [-e|--end seconds]\n");
137 const char *help_graph1 =
138 N_("\t\t[-x|--x-grid x-axis grid and label]\n"
139 "\t\t[-Y|--alt-y-grid] [--full-size-mode]\n"
140 "\t\t[-y|--y-grid y-axis grid and label]\n"
141 "\t\t[-v|--vertical-label string] [-w|--width pixels]\n"
142 "\t\t[--right-axis scale:shift] [--right-axis-label label]\n"
143 "\t\t[--right-axis-format format]\n"
144 "\t\t[-h|--height pixels] [-o|--logarithmic]\n"
145 "\t\t[-u|--upper-limit value] [-z|--lazy]\n"
146 "\t\t[-l|--lower-limit value] [-r|--rigid]\n"
147 "\t\t[-g|--no-legend] [--daemon <address>]\n"
148 "\t\t[-F|--force-rules-legend]\n" "\t\t[-j|--only-graph]\n");
149 const char *help_graph2 =
150 N_("\t\t[-n|--font FONTTAG:size:font]\n"
151 "\t\t[-m|--zoom factor]\n"
152 "\t\t[-A|--alt-autoscale]\n"
153 "\t\t[-M|--alt-autoscale-max]\n"
154 "\t\t[-G|--graph-render-mode {normal,mono}]\n"
155 "\t\t[-R|--font-render-mode {normal,light,mono}]\n"
156 "\t\t[-B|--font-smoothing-threshold size]\n"
157 "\t\t[-T|--tabwidth width]\n"
158 "\t\t[-E|--slope-mode]\n"
159 "\t\t[-P|--pango-markup]\n"
160 "\t\t[-N|--no-gridfit]\n"
161 "\t\t[-X|--units-exponent value]\n"
162 "\t\t[-L|--units-length value]\n"
163 "\t\t[-S|--step seconds]\n"
164 "\t\t[-f|--imginfo printfstr]\n"
165 "\t\t[-a|--imgformat PNG]\n"
166 "\t\t[-c|--color COLORTAG#rrggbb[aa]]\n"
167 "\t\t[--border width\n"
168 "\t\t[-t|--title string]\n"
169 "\t\t[-W|--watermark string]\n"
170 "\t\t[DEF:vname=rrd:ds-name:CF]\n");
171 const char *help_graph3 =
172 N_("\t\t[CDEF:vname=rpn-expression]\n"
173 "\t\t[VDEF:vdefname=rpn-expression]\n"
174 "\t\t[PRINT:vdefname:format]\n"
175 "\t\t[GPRINT:vdefname:format]\n" "\t\t[COMMENT:text]\n"
176 "\t\t[SHIFT:vname:offset]\n"
177 "\t\t[TEXTALIGN:{left|right|justified|center}]\n"
178 "\t\t[TICK:vname#rrggbb[aa][:[fraction][:legend]]]\n"
179 "\t\t[HRULE:value#rrggbb[aa][:legend]]\n"
180 "\t\t[VRULE:value#rrggbb[aa][:legend]]\n"
181 "\t\t[LINE[width]:vname[#rrggbb[aa][:[legend][:STACK]]]]\n"
182 "\t\t[AREA:vname[#rrggbb[aa][:[legend][:STACK]]]]\n"
183 "\t\t[PRINT:vname:CF:format] (deprecated)\n"
184 "\t\t[GPRINT:vname:CF:format] (deprecated)\n"
185 "\t\t[STACK:vname[#rrggbb[aa][:legend]]] (deprecated)\n");
186 const char *help_tune1 =
187 N_(" * tune - Modify some basic properties of an RRD\n\n"
188 "\trrdtool tune filename\n"
189 "\t\t[--heartbeat|-h ds-name:heartbeat]\n"
190 "\t\t[--data-source-type|-d ds-name:DST]\n"
191 "\t\t[--data-source-rename|-r old-name:new-name]\n"
192 "\t\t[--minimum|-i ds-name:min] [--maximum|-a ds-name:max]\n"
193 "\t\t[--deltapos scale-value] [--deltaneg scale-value]\n"
194 "\t\t[--failure-threshold integer]\n"
195 "\t\t[--window-length integer]\n"
196 "\t\t[--alpha adaptation-parameter]\n");
197 const char *help_tune2 =
198 N_("\t\t[--beta adaptation-parameter]\n"
199 "\t\t[--gamma adaptation-parameter]\n"
200 "\t\t[--gamma-deviation adaptation-parameter]\n"
201 "\t\t[--aberrant-reset ds-name]\n");
202 const char *help_resize =
204 (" * resize - alter the length of one of the RRAs in an RRD\n\n"
205 "\trrdtool resize filename rranum GROW|SHRINK rows\n");
206 const char *help_xport =
207 N_("* xport - generate XML dump from one or several RRD\n\n"
208 "\trrdtool xport [-s|--start seconds] [-e|--end seconds]\n"
209 "\t\t[-m|--maxrows rows]\n" "\t\t[--step seconds]\n"
210 "\t\t[--enumds] [--json]\n" "\t\t[DEF:vname=rrd:ds-name:CF]\n"
211 "\t\t[CDEF:vname=rpn-expression]\n"
212 "\t\t[XPORT:vname:legend]\n");
213 const char *help_quit =
214 N_(" * quit - closing a session in remote mode\n\n"
216 const char *help_ls =
217 N_(" * ls - lists all *.rrd files in current directory\n\n"
219 const char *help_cd =
220 N_(" * cd - changes the current directory\n\n"
221 "\trrdtool cd new directory\n");
222 const char *help_mkdir =
223 N_(" * mkdir - creates a new directory\n\n"
224 "\trrdtool mkdir newdirectoryname\n");
225 const char *help_pwd =
226 N_(" * pwd - returns the current working directory\n\n"
228 const char *help_lic =
229 N_("RRDtool is distributed under the Terms of the GNU General\n"
230 "Public License Version 2. (www.gnu.org/copyleft/gpl.html)\n\n"
231 "For more information read the RRD manpages\n");
232 enum { C_NONE, C_CREATE, C_DUMP, C_INFO, C_RESTORE, C_LAST,
233 C_LASTUPDATE, C_FIRST, C_UPDATE, C_FETCH, C_GRAPH, C_GRAPHV,
235 C_RESIZE, C_XPORT, C_QUIT, C_LS, C_CD, C_MKDIR, C_PWD,
236 C_UPDATEV, C_FLUSHCACHED
238 int help_cmd = C_NONE;
241 if (!strcmp(cmd, "create"))
243 else if (!strcmp(cmd, "dump"))
245 else if (!strcmp(cmd, "info"))
247 else if (!strcmp(cmd, "restore"))
248 help_cmd = C_RESTORE;
249 else if (!strcmp(cmd, "last"))
251 else if (!strcmp(cmd, "lastupdate"))
252 help_cmd = C_LASTUPDATE;
253 else if (!strcmp(cmd, "first"))
255 else if (!strcmp(cmd, "update"))
257 else if (!strcmp(cmd, "updatev"))
258 help_cmd = C_UPDATEV;
259 else if (!strcmp(cmd, "fetch"))
261 else if (!strcmp(cmd, "flushcached"))
262 help_cmd = C_FLUSHCACHED;
263 else if (!strcmp(cmd, "graph"))
265 else if (!strcmp(cmd, "graphv"))
267 else if (!strcmp(cmd, "tune"))
269 else if (!strcmp(cmd, "resize"))
271 else if (!strcmp(cmd, "xport"))
273 else if (!strcmp(cmd, "quit"))
275 else if (!strcmp(cmd, "ls"))
277 else if (!strcmp(cmd, "cd"))
279 else if (!strcmp(cmd, "mkdir"))
281 else if (!strcmp(cmd, "pwd"))
284 fprintf(stdout, _(help_main), PACKAGE_VERSION, __DATE__, __TIME__);
290 puts(_(help_listremote));
294 puts(_(help_create));
303 puts(_(help_restore));
309 puts(_(help_lastupdate));
315 puts(_(help_update));
318 puts(_(help_updatev));
324 puts(_(help_flushcached));
327 puts(_(help_graph0));
328 puts(_(help_graph1));
329 puts(_(help_graph2));
330 puts(_(help_graph3));
333 puts(_(help_graphv0));
334 puts(_(help_graph1));
335 puts(_(help_graph2));
336 puts(_(help_graph3));
343 puts(_(help_resize));
367 static char *fgetslong(
372 size_t bufsize = MAX_LENGTH;
376 return *aLinePtr = 0;
377 if (!(linebuf = malloc(bufsize))) {
378 perror("fgetslong: malloc");
382 while (fgets(linebuf + eolpos, MAX_LENGTH, stream)) {
383 eolpos += strlen(linebuf + eolpos);
384 if (linebuf[eolpos - 1] == '\n')
385 return *aLinePtr = linebuf;
386 bufsize += MAX_LENGTH;
387 if (!(linebuf = realloc(linebuf, bufsize))) {
389 perror("fgetslong: realloc");
394 return *aLinePtr = linebuf;
397 return *aLinePtr = 0;
408 #ifdef MUST_DISABLE_SIGFPE
409 signal(SIGFPE, SIG_IGN);
411 #ifdef MUST_DISABLE_FPMASK
415 /* initialize locale settings
416 according to localeconv(3) */
417 setlocale(LC_ALL, "");
419 #if defined(WIN32) && !defined(__CYGWIN__)
420 setmode(fileno(stdout), O_BINARY);
421 setmode(fileno(stdin), O_BINARY);
425 #if defined(HAVE_LIBINTL_H) && defined(BUILD_LIBINTL)
426 bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
427 textdomain(GETTEXT_PACKAGE);
434 if (((argc == 2) || (argc == 3)) && !strcmp("-", argv[1])) {
436 struct rusage myusage;
437 struct timeval starttime;
438 struct timeval currenttime;
440 gettimeofday(&starttime, NULL);
443 if ((argc == 3) && strcmp("", argv[2])) {
454 if (chroot(argv[2]) != 0){
455 fprintf(stderr, "ERROR: chroot %s: %s\n", argv[2],rrd_strerror(errno));
462 "ERROR: change root is not supported by your OS "
463 "or at least by this copy of rrdtool\n");
470 if (strcmp(firstdir, "")) {
471 if (chdir(firstdir) != 0){
472 fprintf(stderr, "ERROR: chdir %s %s\n", firstdir,rrd_strerror(errno));
477 while (fgetslong(&aLine, stdin)) {
478 char *aLineOrig = aLine;
479 if ((argc = CountArgs(aLine)) == 0) {
481 printf("ERROR: not enough arguments\n");
484 if ((myargv = (char **) malloc((argc + 1) *
485 sizeof(char *))) == NULL) {
489 if ((argc = CreateArgs(argv[0], aLine, myargv)) < 0) {
490 printf("ERROR: creating arguments\n");
492 if ( HandleInputLine(argc, myargv, stdout) == 0 ){
494 getrusage(RUSAGE_SELF, &myusage);
495 gettimeofday(¤ttime, NULL);
496 printf("OK u:%1.2f s:%1.2f r:%1.2f\n",
497 (double) myusage.ru_utime.tv_sec +
498 (double) myusage.ru_utime.tv_usec / 1000000.0,
499 (double) myusage.ru_stime.tv_sec +
500 (double) myusage.ru_stime.tv_usec / 1000000.0,
501 (double) (currenttime.tv_sec - starttime.tv_sec)
502 + (double) (currenttime.tv_usec -
510 fflush(stdout); /* this is important for pipes to work */
514 } else if (argc == 2) {
517 } else if (argc == 3 && !strcmp(argv[1], "help")) {
521 exit(HandleInputLine(argc, argv, stderr));
526 /* HandleInputLine is NOT thread safe - due to readdir issues,
527 resolving them portably is not really simple. */
533 #if defined(HAVE_OPENDIR) && defined (HAVE_READDIR)
534 DIR *curdir; /* to read current dir with ls */
537 #if defined(HAVE_SYS_STAT_H)
541 /* Reset errno to 0 before we start.
544 if (argc > 1 && strcmp("quit", argv[1]) == 0) {
546 printf("ERROR: invalid parameter count for quit\n");
551 #if defined(HAVE_OPENDIR) && defined(HAVE_READDIR) && defined(HAVE_CHDIR)
552 if (argc > 1 && strcmp("cd", argv[1]) == 0) {
554 printf("ERROR: invalid parameter count for cd\n");
557 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
558 if (getuid() == 0 && !ChangeRoot) {
560 ("ERROR: chdir security problem - rrdtool is running as "
561 "root but not chroot!\n");
565 if (chdir(argv[2]) != 0){
566 printf("ERROR: chdir %s %s\n", argv[2], rrd_strerror(errno));
571 if (argc > 1 && strcmp("pwd", argv[1]) == 0) {
572 char *cwd; /* To hold current working dir on call to pwd */
574 printf("ERROR: invalid parameter count for pwd\n");
577 cwd = getcwd(NULL, MAXPATH);
579 printf("ERROR: getcwd %s\n", rrd_strerror(errno));
586 if (argc > 1 && strcmp("mkdir", argv[1]) == 0) {
588 printf("ERROR: invalid parameter count for mkdir\n");
591 #if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
592 if (getuid() == 0 && !ChangeRoot) {
594 ("ERROR: mkdir security problem - rrdtool is running as "
595 "root but not chroot!\n");
599 if(mkdir(argv[2], 0777)!=0){
600 printf("ERROR: mkdir %s: %s\n", argv[2],rrd_strerror(errno));
605 if (argc > 1 && strcmp("ls", argv[1]) == 0) {
607 printf("ERROR: invalid parameter count for ls\n");
610 if ((curdir = opendir(".")) != NULL) {
611 while ((dent = readdir(curdir)) != NULL) {
612 if (!stat(dent->d_name, &st)) {
613 if (S_ISDIR(st.st_mode)) {
614 printf("d %s\n", dent->d_name);
616 if (strlen(dent->d_name) > 4 && S_ISREG(st.st_mode)) {
618 (dent->d_name + NAMLEN(dent) - 4, ".rrd")
619 || !strcmp(dent->d_name + NAMLEN(dent) - 4,
621 printf("- %s\n", dent->d_name);
628 printf("ERROR: opendir .: %s\n", rrd_strerror(errno));
633 #endif /* opendir and readdir */
637 || strcmp("help", argv[1]) == 0
638 || strcmp("--help", argv[1]) == 0
639 || strcmp("-help", argv[1]) == 0
640 || strcmp("-?", argv[1]) == 0 || strcmp("-h", argv[1]) == 0) {
645 if (strcmp("create", argv[1]) == 0)
646 rrd_create(argc - 1, &argv[1]);
647 else if (strcmp("dump", argv[1]) == 0)
648 rrd_dump(argc - 1, &argv[1]);
649 else if (strcmp("info", argv[1]) == 0 || strcmp("updatev", argv[1]) == 0) {
652 if (strcmp("info", argv[1]) == 0)
654 data = rrd_info(argc - 1, &argv[1]);
656 data = rrd_update_v(argc - 1, &argv[1]);
657 rrd_info_print(data);
661 else if (strcmp("--version", argv[1]) == 0 ||
662 strcmp("version", argv[1]) == 0 ||
663 strcmp("v", argv[1]) == 0 ||
664 strcmp("-v", argv[1]) == 0 || strcmp("-version", argv[1]) == 0)
665 printf("RRDtool " PACKAGE_VERSION
666 " Copyright by Tobi Oetiker, 1997-2008 (%f)\n",
668 else if (strcmp("restore", argv[1]) == 0)
669 rrd_restore(argc - 1, &argv[1]);
670 else if (strcmp("resize", argv[1]) == 0)
671 rrd_resize(argc - 1, &argv[1]);
672 else if (strcmp("last", argv[1]) == 0)
673 printf("%ld\n", rrd_last(argc - 1, &argv[1]));
674 else if (strcmp("lastupdate", argv[1]) == 0) {
675 rrd_lastupdate(argc - 1, &argv[1]);
676 } else if (strcmp("first", argv[1]) == 0)
677 printf("%ld\n", rrd_first(argc - 1, &argv[1]));
678 else if (strcmp("update", argv[1]) == 0)
679 rrd_update(argc - 1, &argv[1]);
680 else if (strcmp("fetch", argv[1]) == 0) {
681 time_t start, end, ti;
682 unsigned long step, ds_cnt, i, ii;
683 rrd_value_t *data, *datai;
687 (argc - 1, &argv[1], &start, &end, &step, &ds_cnt, &ds_namv,
691 for (i = 0; i < ds_cnt; i++)
692 printf("%20s", ds_namv[i]);
694 for (ti = start + step; ti <= end; ti += step) {
695 printf("%10lu:", ti);
696 for (ii = 0; ii < ds_cnt; ii++)
697 printf(" %0.10e", *(datai++));
700 for (i = 0; i < ds_cnt; i++)
705 } else if (strcmp("xport", argv[1]) == 0) {
706 #ifdef HAVE_RRD_GRAPH
708 unsigned long step, col_cnt;
712 (argc - 1, &argv[1], NULL, &start, &end, &step, &col_cnt,
715 rrd_set_error("the instance of rrdtool has been compiled without graphics");
717 } else if (strcmp("graph", argv[1]) == 0) {
718 #ifdef HAVE_RRD_GRAPH
721 #ifdef notused /*XXX*/
722 const char *imgfile = argv[2]; /* rrd_graph changes argv pointer */
727 int tostdout = (strcmp(argv[2], "-") == 0);
730 for (i = 2; i < argc; i++) {
731 if (strcmp(argv[i], "--imginfo") == 0
732 || strcmp(argv[i], "-f") == 0) {
738 (argc - 1, &argv[1], &calcpr, &xsize, &ysize, NULL, &ymin,
740 if (!tostdout && !imginfo)
741 printf("%dx%d\n", xsize, ysize);
743 for (i = 0; calcpr[i]; i++) {
745 printf("%s\n", calcpr[i]);
753 rrd_set_error("the instance of rrdtool has been compiled without graphics");
755 } else if (strcmp("graphv", argv[1]) == 0) {
756 #ifdef HAVE_RRD_GRAPH
757 rrd_info_t *grinfo = NULL; /* 1 to distinguish it from the NULL that rrd_graph sends in */
759 grinfo = rrd_graph_v(argc - 1, &argv[1]);
761 rrd_info_print(grinfo);
762 rrd_info_free(grinfo);
765 rrd_set_error("the instance of rrdtool has been compiled without graphics");
767 } else if (strcmp("tune", argv[1]) == 0)
768 rrd_tune(argc - 1, &argv[1]);
770 else if (strcmp("flushcached", argv[1]) == 0)
771 rrd_flushcached(argc - 1, &argv[1]);
774 rrd_set_error("unknown function '%s'", argv[1]);
776 if (rrd_test_error()) {
777 fprintf(out, "ERROR: %s\n", rrd_get_error());
791 while (aLine[i] == ' ')
793 while (aLine[i] != 0) {
794 if ((aLine[i] == ' ') && inarg) {
797 if ((aLine[i] != ' ') && !inarg) {
807 * CreateArgs - take a string (aLine) and tokenize
822 /* remove trailing space and newlines */
823 while (len && aLine[len] <= ' ') {
827 /* sikp leading blanks */
828 while (*aLine && *aLine <= ' ')
854 pargv[argc++] = putP;
862 pargv[argc++] = putP;