Merge branch 'master' into ff/rrdd
authorFlorian Forster <octo@verplant.org>
Tue, 2 Sep 2008 09:36:35 +0000 (11:36 +0200)
committerFlorian Forster <octo@verplant.org>
Tue, 2 Sep 2008 09:36:35 +0000 (11:36 +0200)
Conflicts:

src/rrd_lastupdate.c
src/rrd_update.c

14 files changed:
1  2 
configure.ac
doc/rrdgraph.pod
src/rrd.h
src/rrd_dump.c
src/rrd_fetch.c
src/rrd_graph.c
src/rrd_graph.h
src/rrd_info.c
src/rrd_last.c
src/rrd_lastupdate.c
src/rrd_tool.c
src/rrd_tool.h
src/rrd_update.c
src/rrd_xport.c

diff --combined configure.ac
@@@ -9,14 -9,14 +9,14 @@@ dnl tell automake the this script is fo
  
  dnl the official version number is
  dnl a.b.c
- AC_INIT([rrdtool],[1.3.0])
+ AC_INIT([rrdtool],[1.3.1])
  
  dnl for testing a numberical version number comes handy
  dnl the released version are
  dnl a.bccc
  dnl the devel versions will be something like
  dnl a.b999yymmddhh 
- NUMVERS=1.3000
+ NUMVERS=1.3001
  AC_SUBST(NUMVERS)
  
  dnl for the linker to understand which version the library is compatible with
@@@ -355,9 -355,8 +355,9 @@@ CONFIGURE_PART(Audit Compilation Enviro
  
  
  dnl Check for the compiler and static/shared library creation.
 -AC_PROG_CC
  AC_PROG_CPP
 +AC_PROG_CC
 +AM_PROG_CC_C_O
  AC_PROG_LIBTOOL
  
  dnl Try to detect/use GNU features
@@@ -550,6 -549,7 +550,7 @@@ return 0
  have_broken_isfinite=no],have_broken_isfinite=yes,[
  case "${target}" in
    hppa*-*-hpux*) have_broken_isfinite=yes ;;
+   sparc-sun-solaris2.8) have_broken_isfinite=yes ;;
    *) have_broken_isfinite=no ;;
  esac])
  ])
@@@ -675,7 -675,7 +676,7 @@@ EX_CHECK_ALL(cairo,      cairo_font_opt
  EX_CHECK_ALL(cairo,      cairo_svg_surface_create,      cairo-svg.h,            cairo-svg,   1.4.6,  http://cairographics.org/releases/, "")
  EX_CHECK_ALL(cairo,      cairo_pdf_surface_create,      cairo-pdf.h,            cairo-pdf,   1.4.6,  http://cairographics.org/releases/, "")
  EX_CHECK_ALL(cairo,      cairo_ps_surface_create,       cairo-ps.h,             cairo-ps,    1.4.6,  http://cairographics.org/releases/, "")
 -dnl EX_CHECK_ALL(glib-2.0,   glib_check_version,        glib.h,                 glib-2.0,    2.12.12, ftp://ftp.gtk.org/pub/glib/2.12/, "")
 +EX_CHECK_ALL(glib-2.0,   glib_check_version,            glib.h,                 glib-2.0,    2.12.12, ftp://ftp.gtk.org/pub/glib/2.12/, "")
  EX_CHECK_ALL(pango-1.0,  pango_cairo_context_set_font_options,  pango/pango.h,  pangocairo,  1.17,    http://ftp.gnome.org/pub/GNOME/sources/pango/1.17, "")
  EX_CHECK_ALL(xml2,       xmlParseFile,                  libxml/parser.h,        libxml-2.0,        2.6.31,  http://xmlsoft.org/downloads.html, /usr/include/libxml2)
  
diff --combined doc/rrdgraph.pod
@@@ -248,7 -248,7 +248,7 @@@ to the more robust B<--alt-y-grid> mode
  
  How many digits should rrdtool assume the y-axis labels to be? You
  may have to use this option to make enough space once you start
 -fideling with the y-axis labeling.
 +fiddling with the y-axis labeling.
  
  [B<--units=si>]
  
@@@ -264,20 -264,9 +264,20 @@@ Note that for linear graphs, SI notatio
  
  Only generate the graph if the current graph is out of date or not existent.
  Note, that only the image size will be returned, if you run with lazy even
- when using graphv.
+ when using graphv and even when using PRINT.
  
  
 +[B<--daemon> I<address>]
 +
 +Address of the L<rrdcached(1)> daemon. If specified, a C<flush> command is sent
 +to the server before reading the RRD files. This allows the graph to contain
 +fresh data even if the daemon is configured to cache values for a long time. To
 +specify a UNIX domain socket use the prefix C<unix:>, see example below. Other
 +addresses are interpreted as normal network addresses, i.E<nbsp>e. IPv4 or IPv6
 +addresses in most cases.
 +
 + rrdtool graph [...] --daemon unix:/var/run/rrdcached.sock [...]
 +
  [B<-f>|B<--imginfo> I<printfstr>]
  
  After the image has been created, the graph function uses printf
@@@ -452,6 -441,8 +452,6 @@@ at least one print statement to generat
  See L<rrdgraph_graph> for the exact format.
  
  
 -=back
 -
  =head2 graphv
  
  Calling rrdtool with the graphv option will return information in the
@@@ -480,21 -471,6 +480,21 @@@ There is more information returned tha
  Especially the 'graph_*' keys are new. They help applications that want to
  know what is where on the graph.
  
 +=head1 ENVIRONMENT VARIABLES
 +
 +The following environment variables may be used to change the behavior of
 +C<rrdtoolE<nbsp>graph>:
 +
 +=over 4
 +
 +=item B<RRDCACHED_ADDRESS>
 +
 +If this environment variable is set it will have the same effect as specifying
 +the C<--daemon> option on the command line. If both are present, the command
 +line argument takes precedence.
 +
 +=back
 +
  =head1 SEE ALSO
  
  L<rrdgraph> gives an overview of how B<rrdtool graph> works.
diff --combined src/rrd.h
+++ b/src/rrd.h
@@@ -1,5 -1,5 +1,5 @@@
  /*****************************************************************************
-  * RRDtool 1.3.0  Copyright by Tobi Oetiker, 1997-2008
+  * RRDtool 1.3.1  Copyright by Tobi Oetiker, 1997-2008
   *****************************************************************************
   * rrdlib.h   Public header file for librrd
   *****************************************************************************
@@@ -171,7 -171,13 +171,7 @@@ extern    "C" 
      time_t    rrd_last(
      int,
      char **);
 -    int       rrd_lastupdate(
 -    int argc,
 -    char **argv,
 -    time_t *last_update,
 -    unsigned long *ds_cnt,
 -    char ***ds_namv,
 -    char ***last_ds);
 +    int rrd_lastupdate(int argc, char **argv);
      time_t    rrd_first(
      int,
      char **);
      unsigned long *,
      char ***,
      rrd_value_t **);
 +    int       rrd_cmd_flush (int argc, char **argv);
  
      void      rrd_freemem(
      void *mem);
      const char *_template,
      int argc,
      const char **argv);
 -    int       rrd_fetch_r(
 -    const char *filename,
 -    const char *cf,
 -    time_t *start,
 -    time_t *end,
 -    unsigned long *step,
 -    unsigned long *ds_cnt,
 -    char ***ds_namv,
 -    rrd_value_t **data);
 +    int rrd_fetch_r (
 +            const char *filename,
 +            const char *cf,
 +            time_t *start,
 +            time_t *end,
 +            unsigned long *step,
 +            unsigned long *ds_cnt,
 +            char ***ds_namv,
 +            rrd_value_t **data);
      int       rrd_dump_r(
      const char *filename,
      char *outname);
 -    time_t    rrd_last_r(
 -    const char *filename);
 +    time_t    rrd_last_r (const char *filename);
 +    int rrd_lastupdate_r (const char *filename,
 +            time_t *ret_last_update,
 +            unsigned long *ret_ds_count,
 +            char ***ret_ds_names,
 +            char ***ret_last_ds);
      time_t    rrd_first_r(
      const char *filename,
      int rraindex);
  #if defined(__GNUC__) && defined (RRD_EXPORT_DEPRECATED)
  # define RRD_DEPRECATED __attribute__((deprecated))
  #else
- # define RRD_DEPRECATED /**/
+ # define RRD_DEPRECATED          /**/
  #endif
-     void        rrd_free     (rrd_t *rrd)
-       RRD_DEPRECATED;
-     void        rrd_init     (rrd_t *rrd)
-       RRD_DEPRECATED;
-     rrd_file_t *rrd_open   (const char *const file_name, rrd_t *rrd,
-         unsigned rdwr)
-       RRD_DEPRECATED;
-     void        rrd_dontneed (rrd_file_t *rrd_file, rrd_t *rrd)
-       RRD_DEPRECATED;
-     int         rrd_close    (rrd_file_t *rrd_file)
-       RRD_DEPRECATED;
-     ssize_t     rrd_read     (rrd_file_t *rrd_file, void *buf, size_t count)
-       RRD_DEPRECATED;
-     ssize_t     rrd_write    (rrd_file_t *rrd_file,
-         const void *buf, size_t count)
-       RRD_DEPRECATED;
-     void        rrd_flush    (rrd_file_t *rrd_file)
-       RRD_DEPRECATED;
-     off_t       rrd_seek     (rrd_file_t *rrd_file, off_t off, int whence)
-       RRD_DEPRECATED;
-     off_t       rrd_tell     (rrd_file_t *rrd_file)
-       RRD_DEPRECATED;
-     int         rrd_lock     (rrd_file_t *file)
-       RRD_DEPRECATED;
- #endif /* defined(_RRD_TOOL_H) || defined(RRD_EXPORT_DEPRECATED) */
+      void     rrd_free(
+     rrd_t *rrd)
+               RRD_DEPRECATED;
+     void      rrd_init(
+     rrd_t *rrd)
+               RRD_DEPRECATED;
+     rrd_file_t *rrd_open(
+     const char *const file_name,
+     rrd_t *rrd,
+     unsigned rdwr)
+               RRD_DEPRECATED;
+     void      rrd_dontneed(
+     rrd_file_t *rrd_file,
+     rrd_t *rrd)
+               RRD_DEPRECATED;
+     int       rrd_close(
+     rrd_file_t *rrd_file)
+               RRD_DEPRECATED;
+     ssize_t   rrd_read(
+     rrd_file_t *rrd_file,
+     void *buf,
+     size_t count)
+               RRD_DEPRECATED;
+     ssize_t   rrd_write(
+     rrd_file_t *rrd_file,
+     const void *buf,
+     size_t count)
+               RRD_DEPRECATED;
+     void      rrd_flush(
+     rrd_file_t *rrd_file)
+               RRD_DEPRECATED;
+     off_t     rrd_seek(
+     rrd_file_t *rrd_file,
+     off_t off,
+     int whence)
+               RRD_DEPRECATED;
+     off_t     rrd_tell(
+     rrd_file_t *rrd_file)
+               RRD_DEPRECATED;
+     int       rrd_lock(
+     rrd_file_t *file)
+               RRD_DEPRECATED;
+ #endif                  /* defined(_RRD_TOOL_H) || defined(RRD_EXPORT_DEPRECATED) */
  
  #endif                  /* _RRDLIB_H */
  
diff --combined src/rrd_dump.c
@@@ -1,5 -1,5 +1,5 @@@
  /*****************************************************************************
-  * RRDtool 1.3.0  Copyright by Tobi Oetiker, 1997-2008
+  * RRDtool 1.3.1  Copyright by Tobi Oetiker, 1997-2008
   *****************************************************************************
   * rrd_dump  Display a RRD
   *****************************************************************************
@@@ -43,7 -43,6 +43,7 @@@
   *****************************************************************************/
  #include "rrd_tool.h"
  #include "rrd_rpncalc.h"
 +#include "rrd_client.h"
  
  #if !(defined(NETWARE) || defined(WIN32))
  extern char *tzname[2];
@@@ -442,7 -441,6 +442,7 @@@ int rrd_dump
  {
      int       rc;
      int       opt_noheader = 0;
 +    char     *opt_daemon = NULL;
  
      /* init rrd clean */
  
          int       opt;
          int       option_index = 0;
          static struct option long_options[] = {
 +            {"daemon", required_argument, 0, 'd'},
              {"no-header", no_argument, 0, 'n'},
              {0, 0, 0, 0}
          };
  
 -        opt = getopt_long(argc, argv, "n", long_options, &option_index);
 +        opt = getopt_long(argc, argv, "d:n", long_options, &option_index);
  
          if (opt == EOF)
              break;
  
          switch (opt) {
 +        case 'd':
 +            if (opt_daemon != NULL)
 +                    free (opt_daemon);
 +            opt_daemon = strdup (optarg);
 +            if (opt_daemon == NULL)
 +            {
 +                rrd_set_error ("strdup failed.");
 +                return (-1);
 +            }
 +            break;
 +
          case 'n':
              opt_noheader = 1;
              break;
          return (-1);
      }
  
 +    if (opt_daemon == NULL)
 +    {
 +        char *temp;
 +
 +        temp = getenv (ENV_RRDCACHED_ADDRESS);
 +        if (temp != NULL)
 +        {
 +            opt_daemon = strdup (temp);
 +            if (opt_daemon == NULL)
 +            {
 +                rrd_set_error("strdup failed.");
 +                return (-1);
 +            }
 +        }
 +    }
 +
 +    if (opt_daemon != NULL)
 +    {
 +        int status;
 +
 +        status = rrdc_connect (opt_daemon);
 +        if (status != 0)
 +        {
 +            rrd_set_error ("rrdc_connect failed with status %i.", status);
 +            return (-1);
 +        }
 +
 +        status = rrdc_flush (argv[optind]);
 +        if (status != 0)
 +        {
 +            rrd_set_error ("rrdc_flush (%s) failed with status %i.",
 +                    argv[optind], status);
 +            return (-1);
 +        }
 +
 +        rrdc_disconnect ();
 +    } /* if (opt_daemon) */
 +
      if ((argc - optind) == 2) {
          rc = rrd_dump_opt_r(argv[optind], argv[optind + 1], opt_noheader);
      } else {
diff --combined src/rrd_fetch.c
@@@ -1,5 -1,5 +1,5 @@@
  /*****************************************************************************
-  * RRDtool 1.3.0  Copyright by Tobi Oetiker, 1997-2008
+  * RRDtool 1.3.1  Copyright by Tobi Oetiker, 1997-2008
   *****************************************************************************
   * rrd_fetch.c  read date from an rrd to use for further processing
   *****************************************************************************
@@@ -53,7 -53,6 +53,7 @@@
   *****************************************************************************/
  
  #include "rrd_tool.h"
 +#include "rrd_client.h"
  
  #include "rrd_is_thread_safe.h"
  /*#define DEBUG*/
@@@ -73,8 -72,6 +73,8 @@@ int rrd_fetch
      long      step_tmp = 1;
      time_t    start_tmp = 0, end_tmp = 0;
      const char *cf;
 +    char *opt_daemon = NULL;
 +    int status;
  
      rrd_time_value_t start_tv, end_tv;
      char     *parsetime_error = NULL;
@@@ -82,7 -79,6 +82,7 @@@
          {"resolution", required_argument, 0, 'r'},
          {"start", required_argument, 0, 's'},
          {"end", required_argument, 0, 'e'},
 +        {"daemon", required_argument, 0, 'd'},
          {0, 0, 0, 0}
      };
  
@@@ -97,7 -93,7 +97,7 @@@
          int       option_index = 0;
          int       opt;
  
 -        opt = getopt_long(argc, argv, "r:s:e:", long_options, &option_index);
 +        opt = getopt_long(argc, argv, "r:s:e:d:", long_options, &option_index);
  
          if (opt == EOF)
              break;
          case 'r':
              step_tmp = atol(optarg);
              break;
 +
 +        case 'd':
 +            if (opt_daemon != NULL)
 +                    free (opt_daemon);
 +            opt_daemon = strdup (optarg);
 +            if (opt_daemon == NULL)
 +            {
 +                rrd_set_error ("strdup failed.");
 +                return (-1);
 +            }
 +            break;
 +
          case '?':
              rrd_set_error("unknown option '-%c'", optopt);
              return (-1);
          return -1;
      }
  
 +    if (opt_daemon == NULL)
 +    {
 +        char *temp;
 +
 +        temp = getenv (ENV_RRDCACHED_ADDRESS);
 +        if (temp != NULL)
 +        {
 +            opt_daemon = strdup (temp);
 +            if (opt_daemon == NULL)
 +            {
 +                rrd_set_error("strdup failed.");
 +                return (-1);
 +            }
 +        }
 +    }
 +
 +    if (opt_daemon != NULL)
 +    {
 +        status = rrdc_connect (opt_daemon);
 +        if (status != 0)
 +        {
 +            rrd_set_error ("rrdc_connect failed with status %i.", status);
 +            return (-1);
 +        }
 +
 +        status = rrdc_flush (argv[optind]);
 +        if (status != 0)
 +        {
 +            rrd_set_error ("rrdc_flush (%s) failed with status %i.",
 +                    argv[optind], status);
 +            return (-1);
 +        }
 +
 +        rrdc_disconnect ();
 +    } /* if (opt_daemon) */
 +
      cf = argv[optind + 1];
  
 -    if (rrd_fetch_r(argv[optind], cf, start, end, step, ds_cnt, ds_namv, data)
 -        != 0)
 +    status = rrd_fetch_r(argv[optind], cf, start, end, step,
 +            ds_cnt, ds_namv, data);
 +    if (status != 0)
          return (-1);
      return (0);
  }
@@@ -232,7 -179,7 +232,7 @@@ int rrd_fetch_r
  
      return (rrd_fetch_fn
              (filename, cf_idx, start, end, step, ds_cnt, ds_namv, data));
 -}
 +} /* int rrd_fetch_r */
  
  int rrd_fetch_fn(
      const char *filename,   /* name of the rrd */
diff --combined src/rrd_graph.c
@@@ -1,5 -1,5 +1,5 @@@
  /****************************************************************************
-  * RRDtool 1.3.0  Copyright by Tobi Oetiker, 1997-2008
+  * RRDtool 1.3.1  Copyright by Tobi Oetiker, 1997-2008
   ****************************************************************************
   * rrd__graph.c  produce graphs from data in rrdfiles
   ****************************************************************************/
@@@ -26,7 -26,6 +26,7 @@@
  #endif
  
  #include "rrd_graph.h"
 +#include "rrd_client.h"
  
  /* some constant definitions */
  
  #endif
  
  text_prop_t text_prop[] = {
-     {8.0, RRD_DEFAULT_FONT}
+     {8.0, RRD_DEFAULT_FONT,NULL}
      ,                   /* default */
-     {9.0, RRD_DEFAULT_FONT}
+     {9.0, RRD_DEFAULT_FONT,NULL}
      ,                   /* title */
-     {7.0, RRD_DEFAULT_FONT}
+     {7.0, RRD_DEFAULT_FONT,NULL}
      ,                   /* axis */
-     {8.0, RRD_DEFAULT_FONT}
+     {8.0, RRD_DEFAULT_FONT,NULL}
      ,                   /* unit */
-     {8.0, RRD_DEFAULT_FONT} /* legend */
+     {8.0, RRD_DEFAULT_FONT,NULL} /* legend */
+     ,
+     {5.5, RRD_DEFAULT_FONT,NULL} /* watermark */    
  };
  
  xlab_t    xlab[] = {
@@@ -289,6 -290,7 +291,7 @@@ enum text_prop_en text_prop_conv
      conv_if(AXIS, TEXT_PROP_AXIS);
      conv_if(UNIT, TEXT_PROP_UNIT);
      conv_if(LEGEND, TEXT_PROP_LEGEND);
+     conv_if(WATERMARK, TEXT_PROP_WATERMARK);
      return -1;
  }
  
@@@ -303,13 -305,6 +306,13 @@@ int im_free
  
      if (im == NULL)
          return 0;
 +
 +    if (im->use_rrdcached)
 +    {
 +        rrdc_disconnect ();
 +        im->use_rrdcached = 0;
 +    }
 +
      for (i = 0; i < (unsigned) im->gdes_c; i++) {
          if (im->gdes[i].data_first) {
              /* careful here, because a single pointer can occur several times */
      if (im->rendered_image) {
          free(im->rendered_image);
      }
+     if (im->layout) {
+         g_object_unref (im->layout);
+     }
      if (im->surface)
          cairo_surface_destroy(im->surface);
      if (status)
          fprintf(stderr, "OOPS: Cairo has issues it can't even die: %s\n",
                  cairo_status_to_string(status));
+         
      return 0;
  }
  
@@@ -832,36 -833,6 +841,36 @@@ int data_fetch
          if (!skip) {
              unsigned long ft_step = im->gdes[i].step;   /* ft_step will record what we got from fetch */
  
 +            /* Flush the file if
 +             * - a connection to the daemon has been established
 +             * - this is the first occurrence of that RRD file
 +             */
 +            if (im->use_rrdcached)
 +            {
 +                int status;
 +
 +                status = 0;
 +                for (ii = 0; ii < i; ii++)
 +                {
 +                    if (strcmp (im->gdes[i].rrd, im->gdes[ii].rrd) == 0)
 +                    {
 +                        status = 1;
 +                        break;
 +                    }
 +                }
 +
 +                if (status == 0)
 +                {
 +                    status = rrdc_flush (im->gdes[i].rrd);
 +                    if (status != 0)
 +                    {
 +                        rrd_set_error ("rrdc_flush (%s) failed with status %i.",
 +                                im->gdes[i].rrd, status);
 +                        return (-1);
 +                    }
 +                }
 +            } /* if (im->use_rrdcached) */
 +
              if ((rrd_fetch_fn(im->gdes[i].rrd,
                                im->gdes[i].cf,
                                &im->gdes[i].start,
@@@ -1739,11 -1710,7 +1748,7 @@@ int leg_place
                                         im->
                                         text_prop
                                         [TEXT_PROP_LEGEND].
-                                        font,
-                                        im->
-                                        text_prop
-                                        [TEXT_PROP_LEGEND].
-                                        size,
+                                        font_desc,
                                         im->tabwidth, im->gdes[i].legend);
                  leg_c++;
              } else {
                                             im->
                                             text_prop
                                             [TEXT_PROP_LEGEND].
-                                            font,
-                                            im->
-                                            text_prop
-                                            [TEXT_PROP_LEGEND].
-                                            size,
+                                            font_desc,
                                             im->tabwidth, im->gdes[ii].legend)
                          + legspace[ii]
                          + glue;
@@@ -2028,10 -1991,8 +2029,8 @@@ int draw_horizontal_grid
                           im->graph_col[GRC_FONT],
                           im->
                           text_prop[TEXT_PROP_AXIS].
-                          font,
-                          im->
-                          text_prop[TEXT_PROP_AXIS].
-                          size, im->tabwidth, 0.0,
+                          font_desc,
+                          im->tabwidth, 0.0,
                           GFX_H_RIGHT, GFX_V_CENTER, graph_label);
                  gfx_line(im, X0 - 2, Y0, X0, Y0,
                           MGRIDWIDTH, im->graph_col[GRC_MGRID]);
@@@ -2209,10 -2170,8 +2208,8 @@@ int horizontal_log_grid
                   im->graph_col[GRC_FONT],
                   im->
                   text_prop[TEXT_PROP_AXIS].
-                  font,
-                  im->
-                  text_prop[TEXT_PROP_AXIS].
-                  size, im->tabwidth, 0.0,
+                  font_desc,
+                  im->tabwidth, 0.0,
                   GFX_H_RIGHT, GFX_V_CENTER, graph_label);
          /* minor grid */
          if (mid < 4 && exfrac == 1) {
@@@ -2480,10 -2439,8 +2477,8 @@@ void vertical_grid
                   im->graph_col[GRC_FONT],
                   im->
                   text_prop[TEXT_PROP_AXIS].
-                  font,
-                  im->
-                  text_prop[TEXT_PROP_AXIS].
-                  size, im->tabwidth, 0.0,
+                  font_desc,
+                  im->tabwidth, 0.0,
                   GFX_H_CENTER, GFX_V_TOP, graph_label);
      }
  
@@@ -2561,10 -2518,8 +2556,8 @@@ void grid_paint
                       im->graph_col[GRC_FONT],
                       im->
                       text_prop[TEXT_PROP_AXIS].
-                      font,
-                      im->
-                      text_prop[TEXT_PROP_AXIS].
-                      size, im->tabwidth, 0.0,
+                      font_desc,
+                      im->tabwidth, 0.0,
                       GFX_H_CENTER, GFX_V_CENTER, nodata);
          }
      }
               im->graph_col[GRC_FONT],
               im->
               text_prop[TEXT_PROP_UNIT].
-              font,
-              im->
-              text_prop[TEXT_PROP_UNIT].
-              size, im->tabwidth,
+              font_desc,
+              im->tabwidth,
               RRDGRAPH_YLEGEND_ANGLE, GFX_H_CENTER, GFX_V_CENTER, im->ylegend);
      /* graph title */
      gfx_text(im,
               im->graph_col[GRC_FONT],
               im->
               text_prop[TEXT_PROP_TITLE].
-              font,
-              im->
-              text_prop[TEXT_PROP_TITLE].
-              size, im->tabwidth, 0.0, GFX_H_CENTER, GFX_V_TOP, im->title);
+              font_desc,
+              im->tabwidth, 0.0, GFX_H_CENTER, GFX_V_TOP, im->title);
      /* rrdtool 'logo' */
      water_color = im->graph_col[GRC_FONT];
      water_color.alpha = 0.3;
      gfx_text(im, im->ximg - 4, 5,
               water_color,
               im->
-              text_prop[TEXT_PROP_AXIS].
-              font, 5.5, im->tabwidth,
+              text_prop[TEXT_PROP_WATERMARK].
+              font_desc, im->tabwidth,
               -90, GFX_H_LEFT, GFX_V_TOP, "RRDTOOL / TOBI OETIKER");
      /* graph watermark */
      if (im->watermark[0] != '\0') {
                   im->ximg / 2, im->yimg - 6,
                   water_color,
                   im->
-                  text_prop[TEXT_PROP_AXIS].
-                  font, 5.5, im->tabwidth, 0,
+                  text_prop[TEXT_PROP_WATERMARK].
+                  font_desc, im->tabwidth, 0,
                   GFX_H_CENTER, GFX_V_BOTTOM, im->watermark);
      }
  
                       im->graph_col[GRC_FONT],
                       im->
                       text_prop
-                      [TEXT_PROP_LEGEND].font,
-                      im->
-                      text_prop
-                      [TEXT_PROP_LEGEND].size,
+                      [TEXT_PROP_LEGEND].font_desc,
                       im->tabwidth, 0.0,
                       GFX_H_LEFT, GFX_V_BOTTOM, im->gdes[i].legend);
              /* The legend for GRAPH items starts with "M " to have
                                            im->
                                            text_prop
                                            [TEXT_PROP_LEGEND].
-                                           font,
-                                           im->
-                                           text_prop
-                                           [TEXT_PROP_LEGEND].
-                                           size, im->tabwidth, "o") * 1.2;
+                                           font_desc,
+                                           im->tabwidth, "o") * 1.2;
                  boxV = boxH;
                  /* shift the box up a bit */
                  Y0 -= boxV * 0.4;
@@@ -2801,11 -2746,8 +2784,8 @@@ int graph_size_location
                                     im->
                                     text_prop
                                     [TEXT_PROP_AXIS].
-                                    font,
-                                    im->
-                                    text_prop
-                                    [TEXT_PROP_AXIS].
-                                    size, im->tabwidth, "0") * im->unitslength;
+                                    font_desc,
+                                    im->tabwidth, "0") * im->unitslength;
          }
      }
  
@@@ -2986,10 -2928,11 +2966,11 @@@ int graph_paint
      double    areazero = 0.0;
      graph_desc_t *lastgdes = NULL;
      rrd_infoval_t info;
-     PangoFontMap *font_map = pango_cairo_font_map_get_default();
  
-     /* if we are lazy and there is nothing to PRINT ... quit now */
-     if (lazy && im->prt_c == 0) {
+ //    PangoFontMap *font_map = pango_cairo_font_map_get_default();
+     /* if we want and can be lazy ... quit now */
+     if (lazy) {
          info.u_cnt = im->ximg;
          grinfo_push(im, sprintf_alloc("image_width"), RD_I_CNT, info);
          info.u_cnt = im->yimg;
       * if there are no graph elements (i==0) we stop here ... 
       * if we are lazy, try to quit ... 
       */
-     i = print_calc(im); 
+     i = print_calc(im);
      if (i < 0)
          return -1;
  
              (im->surface, CAIRO_SVG_VERSION_1_1);
          break;
      };
+     cairo_destroy(im->cr);
      im->cr = cairo_create(im->surface);
      cairo_set_antialias(im->cr, im->graph_antialias);
      cairo_scale(im->cr, im->zoom, im->zoom);
-     pango_cairo_font_map_set_resolution(PANGO_CAIRO_FONT_MAP(font_map), 100);
//    pango_cairo_font_map_set_resolution(PANGO_CAIRO_FONT_MAP(font_map), 100);
      gfx_new_area(im, 0, 0, 0, im->yimg,
                   im->ximg, im->yimg, im->graph_col[GRC_BACK]);
      gfx_add_point(im, im->ximg, 0);
@@@ -3605,7 -3549,7 +3587,7 @@@ int rrd_graph
      *ysize = 0;
      *ymin = 0;
      *ymax = 0;
-     while (walker) {        
+     while (walker) {
          if (strcmp(walker->key, "image_width") == 0) {
              *xsize = walker->value.u_int;
          } else if (strcmp(walker->key, "image_height") == 0) {
@@@ -3650,11 -3594,9 +3632,9 @@@ rrd_info_t *rrd_graph_v
  {
      image_desc_t im;
      rrd_info_t *grinfo;
      rrd_graph_init(&im);
      /* a dummy surface so that we can measure text sizes for placements */
-     im.surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 10, 10);
-     im.cr = cairo_create(im.surface);
+     
      rrd_graph_options(argc, argv, &im);
      if (rrd_test_error()) {
          rrd_info_free(im.grinfo);
  
      if (im.imginfo) {
          rrd_infoval_t info;
+         char     *filename;
  
+         filename = im.graphfile + strlen(im.graphfile);
+         while (filename > im.graphfile) {
+             if (*(filename - 1) == '/' || *(filename - 1) == '\\')
+                 break;
+             filename--;
+         }
          info.u_str =
              sprintf_alloc(im.imginfo,
-                           im.graphfile,
+                           filename,
                            (long) (im.zoom *
                                    im.ximg), (long) (im.zoom * im.yimg));
          grinfo_push(&im, sprintf_alloc("image_info"), RD_I_STR, info);
      return grinfo;
  }
  
+ static void 
+ rrd_set_font_desc (
+     image_desc_t *im,int prop,char *font, double size ){
+     static text_prop_t tp_cache[] = { {-1,"",NULL}, {-1,"",NULL}, {-1,"",NULL}, {-1,"",NULL}, {-1,"",NULL}, {-1,"",NULL}};
+     
+     if (tp_cache[prop].font_desc == NULL){        
+         if (prop > 0 && tp_cache[0].font_desc != NULL){
+             tp_cache[prop].font_desc = pango_font_description_copy (tp_cache[0].font_desc);
+             strcpy(tp_cache[prop].font,tp_cache[0].font);
+             tp_cache[prop].size = tp_cache[0].size;
+         }
+         else {
+             tp_cache[prop].font_desc = pango_font_description_new();        
+         }
+         im->text_prop[prop].font_desc =  pango_font_description_copy (tp_cache[prop].font_desc);
+     }
+     
+     if (font != NULL && strcmp(tp_cache[prop].font,font) != 0){
+         pango_font_description_free(tp_cache[prop].font_desc);
+         pango_font_description_free(im->text_prop[prop].font_desc);
+         tp_cache[prop].font_desc = pango_font_description_from_string( font );
+         im->text_prop[prop].font_desc = pango_font_description_copy( tp_cache[prop].font_desc );
+         strncpy(tp_cache[prop].font, font, sizeof(text_prop[prop].font) - 1);        
+         tp_cache[prop].font[sizeof(text_prop[prop].font) - 1] = '\0';   
+         strcpy(im->text_prop[prop].font,tp_cache[prop].font);          
+     }
+     if (size != 0 && size != (tp_cache[prop].size)){
+         pango_font_description_set_size(tp_cache[prop].font_desc, size * PANGO_SCALE);
+         pango_font_description_set_size(im->text_prop[prop].font_desc, size * PANGO_SCALE);
+         im->text_prop[prop].size = size;
+         tp_cache[prop].size = size;
+     }
+     if (im->text_prop[prop].size < 0){
+         im->text_prop[prop].size = tp_cache[prop].size;
+         im->text_prop[prop].font_desc = pango_font_description_copy( tp_cache[prop].font_desc );
+         strcpy(im->text_prop[prop].font,tp_cache[prop].font);
+     }
+     // fprintf(stderr,"%d %s\n",prop,pango_font_description_to_string(im->text_prop[prop].font_desc)); 
+ }
  void rrd_graph_init(
      image_desc_t
      *im)
  {
      unsigned int i;
+     char     *deffont = getenv("RRD_DEFAULT_FONT");
  
  #ifdef HAVE_TZSET
      tzset();
  #endif
  #endif
      im->base = 1000;
-     im->cr = NULL;
      im->draw_x_grid = 1;
      im->draw_y_grid = 1;
      im->extra_flags = 0;
      im->grinfo_current = (rrd_info_t *) NULL;
      im->imgformat = IF_PNG;
      im->imginfo = NULL;
 +    im->use_rrdcached = 0;
      im->lazy = 0;
      im->logarithmic = 0;
      im->maxval = DNAN;
      im->rendered_image = NULL;
      im->slopemode = 0;
      im->step = 0;
-     im->surface = NULL;
      im->symbol = ' ';
      im->tabwidth = 40.0;
      im->title[0] = '\0';
      im->yorigin = 0;
      im->ysize = 100;
      im->zoom = 1;
+     im->surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 10, 10);     
+     im->cr = cairo_create(im->surface);
+     for (i = 0; i < DIM(text_prop); i++) {
+         im->text_prop[i].size = -1;
+         rrd_set_font_desc(im,i, deffont ? deffont : text_prop[i].font,text_prop[i].size);
+     }
+     im->layout = pango_cairo_create_layout(im->cr);    
+     pango_cairo_context_set_resolution(pango_layout_get_context(im->layout), 100);
      cairo_font_options_set_hint_style
          (im->font_options, CAIRO_HINT_STYLE_FULL);
      cairo_font_options_set_hint_metrics
          (im->font_options, CAIRO_HINT_METRICS_ON);
      cairo_font_options_set_antialias(im->font_options, CAIRO_ANTIALIAS_GRAY);
      for (i = 0; i < DIM(graph_col); i++)
          im->graph_col[i] = graph_col[i];
-     {
-         char     *deffont;
-         deffont = getenv("RRD_DEFAULT_FONT");
-         if (deffont != NULL) {
-             for (i = 0; i < DIM(text_prop); i++) {
-                 strncpy(text_prop[i].font, deffont,
-                         sizeof(text_prop[i].font) - 1);
-                 text_prop[i].font[sizeof(text_prop[i].font) - 1] = '\0';
-             }
-         }
-     }
-     for (i = 0; i < DIM(text_prop); i++) {
-         im->text_prop[i].size = text_prop[i].size;
-         strcpy(im->text_prop[i].font, text_prop[i].font);
-     }
  }
  
  void rrd_graph_options(
      int argc,
      char *argv[],
          { "watermark",          required_argument, 0, 'W'},
          { "alt-y-mrtg",         no_argument,       0, 1000},    /* this has no effect it is just here to save old apps from crashing when they use it */
          { "pango-markup",       no_argument,       0, 'P'},
 +        { "daemon",             required_argument, 0, 'd'},
          {  0, 0, 0, 0}
  };
  /* *INDENT-ON* */
          int       col_start, col_end;
  
          opt = getopt_long(argc, argv,
 -                          "s:e:x:y:v:w:h:D:iu:l:rb:oc:n:m:t:f:a:I:zgjFYAMEX:L:S:T:NR:B:W:kP",
 +                          "s:e:x:y:v:w:h:D:iu:l:rb:oc:n:m:t:f:a:I:zgjFYAMEX:L:S:T:NR:B:W:kPd:",
                            long_options, &option_index);
          if (opt == EOF)
              break;
                      for (propidx = sindex;
                           propidx < TEXT_PROP_LAST; propidx++) {
                          if (size > 0) {
-                             im->text_prop[propidx].size = size;
+                             rrd_set_font_desc(im,propidx,NULL,size);   
                          }
                          if ((int) strlen(optarg) > end) {
                              if (optarg[end] == ':') {
-                                 strncpy(im->text_prop[propidx].font,
-                                         optarg + end + 1, 255);
-                                 im->text_prop[propidx].font[255] = '\0';
+                                 rrd_set_font_desc(im,propidx,optarg + end + 1,0);   
                              } else {
                                  rrd_set_error
                                      ("expected : after font size in '%s'",
              strncpy(im->watermark, optarg, 100);
              im->watermark[99] = '\0';
              break;
 +        case 'd':
 +        {
 +            int status;
 +            if (im->use_rrdcached)
 +            {
 +                rrd_set_error ("You cannot specify --daemon "
 +                        "more than once.");
 +                return;
 +            }
 +            status = rrdc_connect (optarg);
 +            if (status != 0)
 +            {
 +                rrd_set_error ("rrdc_connect(%s) failed with status %i.",
 +                        optarg, status);
 +                return;
 +            }
 +            im->use_rrdcached = 1;
 +            break;
 +        }
          case '?':
              if (optopt != 0)
                  rrd_set_error("unknown option '%c'", optopt);
                  rrd_set_error("unknown option '%s'", argv[optind - 1]);
              return;
          }
 +    } /* while (1) */
 +
 +    if (im->use_rrdcached == 0)
 +    {
 +        char *temp;
 +
 +        temp = getenv (ENV_RRDCACHED_ADDRESS);
 +        if (temp != NULL)
 +        {
 +            int status;
 +
 +            status = rrdc_connect (temp);
 +            if (status != 0)
 +            {
 +                rrd_set_error ("rrdc_connect(%s) failed with status %i.",
 +                        temp, status);
 +                return;
 +            }
 +            im->use_rrdcached = 1;
 +        }
      }
+     
+     pango_cairo_context_set_font_options(pango_layout_get_context(im->layout), im->font_options);
+     pango_layout_context_changed(im->layout);
  
      if (im->logarithmic && im->minval <= 0) {
          rrd_set_error
@@@ -4527,9 -4479,9 +4558,9 @@@ int vdef_calc
      src = &im->gdes[dst->vidx];
      data = src->data + src->ds;
      end =
-         src->end_orig % (long)src->step ==
-         0 ? src->end_orig : (src->end_orig + (long)src->step -
-                              src->end_orig % (long)src->step);
+         src->end_orig % (long) src->step ==
+         0 ? src->end_orig : (src->end_orig + (long) src->step -
+                              src->end_orig % (long) src->step);
  
      steps = (end - src->start) / src->step;
  #if 0
diff --combined src/rrd_graph.h
@@@ -61,11 -61,13 +61,13 @@@ enum vdef_op_en 
          , VDEF_LSLINT   /* least squares line y_intercept */
          , VDEF_LSLCORREL    /* least squares line correlation coefficient */
  };
- enum text_prop_en { TEXT_PROP_DEFAULT = 0,  /* default settings */
+ enum text_prop_en { 
+     TEXT_PROP_DEFAULT = 0,  /* default settings */
      TEXT_PROP_TITLE,    /* properties for the title */
      TEXT_PROP_AXIS,     /* for the numbers next to the axis */
      TEXT_PROP_UNIT,     /* for the vertical unit description */
-     TEXT_PROP_LEGEND,   /* fot the legend below the graph */
+     TEXT_PROP_LEGEND,   /* for the legend below the graph */
+     TEXT_PROP_WATERMARK, /* for the little text to the side of the graph */
      TEXT_PROP_LAST
  };
  
@@@ -87,6 -89,7 +89,7 @@@ typedef struct gfx_color_t 
  typedef struct text_prop_t {
      double    size;
      char      font[1024];
+     PangoFontDescription *font_desc;
  } text_prop_t;
  
  
@@@ -210,7 -213,6 +213,7 @@@ typedef struct image_desc_t 
      char     *imginfo;  /* construct an <IMG ... tag and return 
                             as first retval */
      enum gfx_if_en imgformat;   /* image format */
 +    int       use_rrdcached;
      int       lazy;     /* only update the image if there is
                             reasonable probablility that the
                             existing one is out of date */
      cairo_t  *cr;       /* drawin context */
      cairo_font_options_t *font_options; /* cairo font options */
      cairo_antialias_t graph_antialias;  /* antialiasing for the graph */
+     PangoLayout *layout; /* the pango layout we use for writing fonts */
      rrd_info_t *grinfo; /* root pointer to extra graph info */
      rrd_info_t *grinfo_current; /* pointing to current entry */
  } image_desc_t;
@@@ -339,6 -341,7 +342,7 @@@ int       scan_for_col
      char *const);
  void      rrd_graph_init(
      image_desc_t *);
  void      rrd_graph_options(
      int,
      char **,
@@@ -418,8 -421,7 +422,7 @@@ void      gfx_text
      double x,
      double y,
      gfx_color_t color,
-     char *font,
-     double size,
+     PangoFontDescription *font_desc,
      double tabwidth,
      double angle,
      enum gfx_h_align_en h_align,
  double    gfx_get_text_width(
      image_desc_t *im,
      double start,
-     char *font,
-     double size,
+     PangoFontDescription *font_desc,
      double tabwidth,
      char *text);
  
@@@ -455,5 -456,4 +457,4 @@@ void      gfx_area_fit
  void      grinfo_push(
      image_desc_t *im,
      char *key,
-     rrd_info_type_t type,
-     rrd_infoval_t value);
+     rrd_info_type_t type,    rrd_infoval_t value);
diff --combined src/rrd_info.c
@@@ -1,12 -1,11 +1,12 @@@
  /*****************************************************************************
-  * RRDtool 1.3.0  Copyright by Tobi Oetiker, 1997-2008
+  * RRDtool 1.3.1  Copyright by Tobi Oetiker, 1997-2008
   *****************************************************************************
   * rrd_info  Get Information about the configuration of an RRD
   *****************************************************************************/
  
  #include "rrd_tool.h"
  #include "rrd_rpncalc.h"
 +#include "rrd_client.h"
  #include <stdarg.h>
  
  /* proto */
@@@ -81,92 -80,18 +81,92 @@@ rrd_info_t *rrd_info
      char **argv)
  {
      rrd_info_t *info;
 +    char *opt_daemon = NULL;
  
 -    if (argc < 2) {
 -        rrd_set_error("please specify an rrd");
 -        return NULL;
 +    optind = 0;
 +    opterr = 0;         /* initialize getopt */
 +
 +    while (42) {
 +        int       opt;
 +        int       option_index = 0;
 +        static struct option long_options[] = {
 +            {"daemon", required_argument, 0, 'd'},
 +            {0, 0, 0, 0}
 +        };
 +
 +        opt = getopt_long(argc, argv, "d:", long_options, &option_index);
 +
 +        if (opt == EOF)
 +            break;
 +
 +        switch (opt) {
 +        case 'd':
 +            if (opt_daemon != NULL)
 +                    free (opt_daemon);
 +            opt_daemon = strdup (optarg);
 +            if (opt_daemon == NULL)
 +            {
 +                rrd_set_error ("strdup failed.");
 +                return (NULL);
 +            }
 +            break;
 +
 +        default:
 +            rrd_set_error ("Usage: rrdtool %s [--daemon <addr>] <file>",
 +                    argv[0]);
 +            return (NULL);
 +            break;
 +        }
 +    }                   /* while (42) */
 +
 +    if ((argc - optind) != 1) {
 +        rrd_set_error ("Usage: rrdtool %s [--daemon <addr>] <file>",
 +                argv[0]);
 +        return (NULL);
      }
  
 -    info = rrd_info_r(argv[1]);
 +    if (opt_daemon == NULL)
 +    {
 +        char *temp;
  
 -    return (info);
 -}
 +        temp = getenv (ENV_RRDCACHED_ADDRESS);
 +        if (temp != NULL)
 +        {
 +            opt_daemon = strdup (temp);
 +            if (opt_daemon == NULL)
 +            {
 +                rrd_set_error("strdup failed.");
 +                return (NULL);
 +            }
 +        }
 +    }
 +
 +    if (opt_daemon != NULL)
 +    {
 +        int status;
 +
 +        status = rrdc_connect (opt_daemon);
 +        if (status != 0)
 +        {
 +            rrd_set_error ("rrdc_connect failed with status %i.", status);
 +            return (NULL);
 +        }
  
 +        status = rrdc_flush (argv[optind]);
 +        if (status != 0)
 +        {
 +            rrd_set_error ("rrdc_flush (%s) failed with status %i.",
 +                    argv[optind], status);
 +            return (NULL);
 +        }
  
 +        rrdc_disconnect ();
 +    } /* if (opt_daemon) */
 +
 +    info = rrd_info_r(argv[optind]);
 +
 +    return (info);
 +} /* rrd_info_t *rrd_info */
  
  rrd_info_t *rrd_info_r(
      char *filename)
diff --combined src/rrd_last.c
@@@ -1,5 -1,5 +1,5 @@@
  /*****************************************************************************
-  * RRDtool 1.3.0  Copyright by Tobi Oetiker, 1997-2008
+  * RRDtool 1.3.1  Copyright by Tobi Oetiker, 1997-2008
   *****************************************************************************
   * rrd_last.c
   *****************************************************************************
@@@ -7,96 -7,19 +7,96 @@@
   *****************************************************************************/
  
  #include "rrd_tool.h"
 +#include "rrd_client.h"
  
  time_t rrd_last(
      int argc,
      char **argv)
  {
 -    if (argc < 2) {
 -        rrd_set_error("please specify an rrd");
 +    char *opt_daemon = NULL;
 +
 +    optind = 0;
 +    opterr = 0;         /* initialize getopt */
 +
 +    while (42) {
 +        int       opt;
 +        int       option_index = 0;
 +        static struct option long_options[] = {
 +            {"daemon", required_argument, 0, 'd'},
 +            {0, 0, 0, 0}
 +        };
 +
 +        opt = getopt_long(argc, argv, "d:", long_options, &option_index);
 +
 +        if (opt == EOF)
 +            break;
 +
 +        switch (opt) {
 +        case 'd':
 +            if (opt_daemon != NULL)
 +                    free (opt_daemon);
 +            opt_daemon = strdup (optarg);
 +            if (opt_daemon == NULL)
 +            {
 +                rrd_set_error ("strdup failed.");
 +                return (-1);
 +            }
 +            break;
 +
 +        default:
 +            rrd_set_error ("Usage: rrdtool %s [--daemon <addr>] <file>",
 +                    argv[0]);
 +            return (-1);
 +            break;
 +        }
 +    }                   /* while (42) */
 +
 +    if ((argc - optind) != 1) {
 +        rrd_set_error ("Usage: rrdtool %s [--daemon <addr>] <file>",
 +                argv[0]);
          return (-1);
      }
  
 -    return (rrd_last_r(argv[1]));
 -}
 +    if (opt_daemon == NULL)
 +    {
 +        char *temp;
  
 +        temp = getenv (ENV_RRDCACHED_ADDRESS);
 +        if (temp != NULL)
 +        {
 +            opt_daemon = strdup (temp);
 +            if (opt_daemon == NULL)
 +            {
 +                rrd_set_error("strdup failed.");
 +                return (-1);
 +            }
 +        }
 +    }
 +
 +    if (opt_daemon != NULL)
 +    {
 +        int status;
 +
 +        status = rrdc_connect (opt_daemon);
 +        if (status != 0)
 +        {
 +            rrd_set_error ("rrdc_connect failed with status %i.", status);
 +            return (-1);
 +        }
 +
 +        status = rrdc_flush (argv[optind]);
 +        if (status != 0)
 +        {
 +            rrd_set_error ("rrdc_flush (%s) failed with status %i.",
 +                    argv[optind], status);
 +            return (-1);
 +        }
 +
 +        rrdc_disconnect ();
 +    } /* if (opt_daemon) */
 +
 +    return (rrd_last_r (argv[optind]));
 +}
  
  time_t rrd_last_r(
      const char *filename)
diff --combined src/rrd_lastupdate.c
  /*****************************************************************************
-  * RRDtool 1.3.0  Copyright by Tobi Oetiker, 1997-2008
+  * RRDtool 1.3.1  Copyright by Tobi Oetiker, 1997-2008
 + *                Copyright by Florian Forster, 2008
   *****************************************************************************
   * rrd_lastupdate  Get the last datum entered for each DS
   *****************************************************************************/
  
  #include "rrd_tool.h"
  #include "rrd_rpncalc.h"
 +#include "rrd_client.h"
  #include <stdarg.h>
  
 -int rrd_lastupdate(
 -    int argc,
 -    char **argv,
 -    time_t *last_update,
 -    unsigned long *ds_cnt,
 -    char ***ds_namv,
 -    char ***last_ds)
 +int rrd_lastupdate (int argc, char **argv)
 +{
 +    time_t    last_update;
 +    char    **ds_names;
 +    char    **last_ds;
 +    unsigned long ds_count, i;
 +    int status;
 +
 +    char *opt_daemon = NULL;
 +
 +    optind = 0;
 +    opterr = 0;         /* initialize getopt */
 +
 +    while (42) {
 +        int       opt;
 +        int       option_index = 0;
 +        static struct option long_options[] = {
 +            {"daemon", required_argument, 0, 'd'},
 +            {0, 0, 0, 0}
 +        };
 +
 +        opt = getopt_long (argc, argv, "d:", long_options, &option_index);
 +
 +        if (opt == EOF)
 +            break;
 +
 +        switch (opt) {
 +        case 'd':
 +            if (opt_daemon != NULL)
 +                    free (opt_daemon);
 +            opt_daemon = strdup (optarg);
 +            if (opt_daemon == NULL)
 +            {
 +                rrd_set_error ("strdup failed.");
 +                return (-1);
 +            }
 +            break;
 +
 +        default:
 +            rrd_set_error ("Usage: rrdtool %s [--daemon <addr>] <file>",
 +                    argv[0]);
 +            return (-1);
 +            break;
 +        }
 +    }                   /* while (42) */
 +
 +    if ((argc - optind) != 1) {
 +        rrd_set_error ("Usage: rrdtool %s [--daemon <addr>] <file>",
 +                argv[0]);
 +        return (-1);
 +    }
 +
 +    if (opt_daemon == NULL)
 +    {
 +        char *temp;
 +
 +        temp = getenv (ENV_RRDCACHED_ADDRESS);
 +        if (temp != NULL)
 +        {
 +            opt_daemon = strdup (temp);
 +            if (opt_daemon == NULL)
 +            {
 +                rrd_set_error("strdup failed.");
 +                return (-1);
 +            }
 +        }
 +    }
 +
 +    if (opt_daemon != NULL)
 +    {
 +        status = rrdc_connect (opt_daemon);
 +        if (status != 0)
 +        {
 +            rrd_set_error ("rrdc_connect failed with status %i.", status);
 +            return (-1);
 +        }
 +
 +        status = rrdc_flush (argv[optind]);
 +        if (status != 0)
 +        {
 +            rrd_set_error ("rrdc_flush (%s) failed with status %i.",
 +                    argv[optind], status);
 +            return (-1);
 +        }
 +
 +        rrdc_disconnect ();
 +    } /* if (opt_daemon) */
 +
 +    status = rrd_lastupdate_r (argv[optind],
 +            &last_update, &ds_count, &ds_names, &last_ds);
 +    if (status != 0)
 +        return (status);
 +
 +    for (i = 0; i < ds_count; i++)
 +        printf(" %s", ds_names[i]);
 +    printf ("\n\n");
 +
 +    printf ("%10lu:", last_update);
 +    for (i = 0; i < ds_count; i++) {
 +        printf(" %s", last_ds[i]);
 +        free(last_ds[i]);
 +        free(ds_names[i]);
 +    }
 +    printf("\n");
 +
 +    free(last_ds);
 +    free(ds_names);
 +
 +    return (0);
 +} /* int rrd_lastupdate */
 +
 +int rrd_lastupdate_r(const char *filename,
 +        time_t *ret_last_update,
 +        unsigned long *ret_ds_count,
 +        char ***ret_ds_names,
 +        char ***ret_last_ds)
  {
      unsigned long i = 0;
 -    char     *filename;
      rrd_t     rrd;
      rrd_file_t *rrd_file;
  
 -    if (argc < 2) {
 -        rrd_set_error("please specify an rrd");
 -        goto err_out;
 +    rrd_file = rrd_open(filename, &rrd, RRD_READONLY);
 +    if (rrd_file == NULL) {
 +        rrd_free(&rrd);
 +        return (-1);
      }
 -    filename = argv[1];
  
 -    rrd_file = rrd_open(filename, &rrd, RRD_READONLY);
 -    if (rrd_file == NULL)
 -        goto err_free;
 -
 -    *last_update = rrd.live_head->last_up;
 -    *ds_cnt = rrd.stat_head->ds_cnt;
 -    if (((*ds_namv) =
 -         (char **) malloc(rrd.stat_head->ds_cnt * sizeof(char *))) == NULL) {
 -        rrd_set_error("malloc fetch ds_namv array");
 -        goto err_close;
 +    *ret_last_update = rrd.live_head->last_up;
 +    *ret_ds_count = rrd.stat_head->ds_cnt;
 +    *ret_ds_names = (char **) malloc (rrd.stat_head->ds_cnt * sizeof(char *));
 +    if (*ret_ds_names == NULL) {
 +        rrd_set_error ("malloc fetch ret_ds_names array");
 +        rrd_close (rrd_file);
 +        rrd_free (&rrd);
 +        return (-1);
      }
 +    memset (*ret_ds_names, 0, rrd.stat_head->ds_cnt * sizeof(char *));
  
 -    if (((*last_ds) =
 -         (char **) malloc(rrd.stat_head->ds_cnt * sizeof(char *))) == NULL) {
 -        rrd_set_error("malloc fetch last_ds array");
 -        goto err_free_ds_namv;
 +    *ret_last_ds = (char **) malloc (rrd.stat_head->ds_cnt * sizeof(char *));
 +    if (*ret_last_ds == NULL) {
 +        rrd_set_error ("malloc fetch ret_last_ds array");
 +        free (*ret_ds_names);
 +        *ret_ds_names = NULL;
 +        rrd_close (rrd_file);
 +        rrd_free (&rrd);
 +        return (-1);
      }
 +    memset (*ret_last_ds, 0, rrd.stat_head->ds_cnt * sizeof(char *));
  
      for (i = 0; i < rrd.stat_head->ds_cnt; i++) {
 -        (*ds_namv)[i] = sprintf_alloc("%s", rrd.ds_def[i].ds_nam);
 -        (*last_ds)[i] = sprintf_alloc("%s", rrd.pdp_prep[i].last_ds);
 +        (*ret_ds_names)[i] = sprintf_alloc("%s", rrd.ds_def[i].ds_nam);
 +        (*ret_last_ds)[i] = sprintf_alloc("%s", rrd.pdp_prep[i].last_ds);
 +
 +        if (((*ret_ds_names)[i] == NULL) || ((*ret_last_ds)[i] == NULL))
 +            break;
 +    }
 +
 +    /* Check if all names and values could be copied and free everything if
 +     * not. */
 +    if (i < rrd.stat_head->ds_cnt) {
 +        rrd_set_error ("sprintf_alloc failed");
 +        for (i = 0; i < rrd.stat_head->ds_cnt; i++) {
 +            if ((*ret_ds_names)[i] != NULL)
 +            {
 +                free ((*ret_ds_names)[i]);
 +                (*ret_ds_names)[i] = NULL;
 +            }
 +            if ((*ret_last_ds)[i] != NULL)
 +            {
 +                free ((*ret_last_ds)[i]);
 +                (*ret_last_ds)[i] = NULL;
 +            }
 +        }
 +        free (*ret_ds_names);
 +        *ret_ds_names = NULL;
 +        free (*ret_last_ds);
 +        *ret_last_ds = NULL;
 +        rrd_close (rrd_file);
 +        rrd_free (&rrd);
 +        return (-1);
      }
  
      rrd_free(&rrd);
      rrd_close(rrd_file);
      return (0);
 -
 -  err_free_ds_namv:
 -    free(*ds_namv);
 -  err_close:
 -    rrd_close(rrd_file);
 -  err_free:
 -    rrd_free(&rrd);
 -  err_out:
 -    return (-1);
 -}
 +} /* int rrd_lastupdate_r */
diff --combined src/rrd_tool.c
@@@ -1,5 -1,5 +1,5 @@@
  /*****************************************************************************
-  * RRDtool 1.3.0  Copyright by Tobi Oetiker, 1997-2008
+  * RRDtool 1.3.1  Copyright by Tobi Oetiker, 1997-2008
   *****************************************************************************
   * rrd_tool.c  Startup wrapper
   *****************************************************************************/
@@@ -55,7 -55,7 +55,7 @@@ void PrintUsage
          N_
          ("Valid commands: create, update, updatev, graph, graphv,  dump, restore,\n"
           "\t\tlast, lastupdate, first, info, fetch, tune,\n"
 -         "\t\tresize, xport\n\n");
 +         "\t\tresize, xport, flush\n\n");
  
      const char *help_listremote =
          N_("Valid remote commands: quit, ls, cd, mkdir, pwd\n\n");
@@@ -95,8 -95,7 +95,8 @@@
      const char *help_update =
          N_("* update - update an RRD\n\n"
             "\trrdtool update filename\n"
 -           "\t\t--template|-t ds-name:ds-name:...\n"
 +           "\t\t[--template|-t ds-name:ds-name:...]\n"
 +         "\t\t[--daemon <address>]\n"
             "\t\ttime|N:value[:value...]\n\n"
             "\t\tat-time@value[:value...]\n\n"
             "\t\t[ time:value[:value...] ..]\n\n");
          N_("* updatev - a verbose version of update\n"
             "\treturns information about values, RRAs, and datasources updated\n\n"
             "\trrdtool updatev filename\n"
 -           "\t\t--template|-t ds-name:ds-name:...\n"
 +           "\t\t[--template|-t ds-name:ds-name:...]\n"
             "\t\ttime|N:value[:value...]\n\n"
             "\t\tat-time@value[:value...]\n\n"
             "\t\t[ time:value[:value...] ..]\n\n");
          N_("* fetch - fetch data out of an RRD\n\n"
             "\trrdtool fetch filename.rrd CF\n"
             "\t\t[-r|--resolution resolution]\n"
 -           "\t\t[-s|--start start] [-e|--end end]\n\n");
 +           "\t\t[-s|--start start] [-e|--end end]\n"
 +         "\t\t[--daemon <address>]\n\n");
 +
 +    const char *help_flush =
 +        N_("* flush - flush cached data out to an RRD file\n\n"
 +           "\trrdtool flush filename.rrd\n"
 +         "\t\t[--daemon <address>]\n\n");
  
  /* break up very large strings (help_graph, help_tune) for ISO C89 compliance*/
  
             "\t\t[-h|--height pixels] [-o|--logarithmic]\n"
             "\t\t[-u|--upper-limit value] [-z|--lazy]\n"
             "\t\t[-l|--lower-limit value] [-r|--rigid]\n"
 -           "\t\t[-g|--no-legend]\n"
 +           "\t\t[-g|--no-legend] [--daemon <address>]\n"
             "\t\t[-F|--force-rules-legend]\n" "\t\t[-j|--only-graph]\n");
      const char *help_graph2 =
          N_("\t\t[-n|--font FONTTAG:size:font]\n"
          C_LASTUPDATE, C_FIRST, C_UPDATE, C_FETCH, C_GRAPH, C_GRAPHV,
          C_TUNE,
          C_RESIZE, C_XPORT, C_QUIT, C_LS, C_CD, C_MKDIR, C_PWD,
 -        C_UPDATEV
 +        C_UPDATEV, C_FLUSH
      };
      int       help_cmd = C_NONE;
  
              help_cmd = C_UPDATEV;
          else if (!strcmp(cmd, "fetch"))
              help_cmd = C_FETCH;
 +        else if (!strcmp(cmd, "flush"))
 +            help_cmd = C_FLUSH;
          else if (!strcmp(cmd, "graph"))
              help_cmd = C_GRAPH;
          else if (!strcmp(cmd, "graphv"))
      case C_FETCH:
          fputs(_(help_fetch), stdout);
          break;
 +    case C_FLUSH:
 +        fputs(_(help_flush), stdout);
 +        break;
      case C_GRAPH:
          fputs(_(help_graph0), stdout);
          fputs(_(help_graph1), stdout);
@@@ -376,11 -364,16 +376,16 @@@ static char *fgetslong
              return *aLinePtr = linebuf;
          bufsize += MAX_LENGTH;
          if (!(linebuf = realloc(linebuf, bufsize))) {
+             free(linebuf);
              perror("fgetslong: realloc");
              exit(1);
          }
      }
-     return *aLinePtr = linebuf[0] ? linebuf : 0;
+     if (linebuf[0]){
+         return  *aLinePtr = linebuf;
+     }
+     free(linebuf);
+     return *aLinePtr = 0;
  }
  
  int main(
                     == 0) {
  
  #ifdef HAVE_CHROOT
-                 chroot(argv[2]);
-                 if (errno != 0) {
-                     fprintf(stderr,
-                             "ERROR: can't change root to '%s' errno=%d\n",
-                             argv[2], errno);
+                 if (chroot(argv[2]) != 0){
+                     fprintf(stderr, "ERROR: chroot %s: %s\n", argv[2],rrd_strerror(errno));
                      exit(errno);
                  }
                  ChangeRoot = 1;
              }
          }
          if (strcmp(firstdir, "")) {
-             chdir(firstdir);
-             if (errno != 0) {
-                 fprintf(stderr, "ERROR: %s\n", rrd_strerror(errno));
+             if (chdir(firstdir) != 0){
+                 fprintf(stderr, "ERROR: chdir %s %s\n", firstdir,rrd_strerror(errno));
                  exit(errno);
              }
          }
  
          while (fgetslong(&aLine, stdin)) {
              if ((argc = CountArgs(aLine)) == 0) {
+                 free(aLine);
                  printf("ERROR: not enough arguments\n");
              }
              if ((myargv = (char **) malloc((argc + 1) *
                  exit(1);
              }
              if ((argc = CreateArgs(argv[0], aLine, argc, myargv)) < 0) {
+                 free(aLine);
+                 free(myargv);
                  printf("ERROR: creating arguments\n");
              } else {
                  int       ret = HandleInputLine(argc, myargv, stdout);
@@@ -524,7 -516,6 +528,6 @@@ int HandleInputLine
  
      /* Reset errno to 0 before we start.
       */
-     errno = 0;
      if (RemoteMode) {
          if (argc > 1 && strcmp("quit", argv[1]) == 0) {
              if (argc > 2) {
                  return (1);
              }
  #endif
-             chdir(argv[2]);
-             if (errno != 0) {
-                 printf("ERROR: %s\n", rrd_strerror(errno));
+             if (chdir(argv[2]) != 0){
+                 printf("ERROR: chdir %s %s\n", argv[2], rrd_strerror(errno));
                  return (1);
              }
              return (0);
              }
              cwd = getcwd(NULL, MAXPATH);
              if (cwd == NULL) {
-                 printf("ERROR: %s\n", rrd_strerror(errno));
+                 printf("ERROR: getcwd %s\n", rrd_strerror(errno));
                  return (1);
              }
              printf("%s\n", cwd);
                  return (1);
              }
  #endif
-             mkdir(argv[2], 0777);
-             if (errno != 0) {
-                 printf("ERROR: %s\n", rrd_strerror(errno));
+             if(mkdir(argv[2], 0777)!=0){
+                 printf("ERROR: mkdir %s: %s\n", argv[2],rrd_strerror(errno));
                  return (1);
              }
              return (0);
                  }
                  closedir(curdir);
              } else {
-                 printf("ERROR: %s\n", rrd_strerror(errno));
+                 printf("ERROR: opendir .: %s\n", rrd_strerror(errno));
                  return (errno);
              }
              return (0);
      else if (strcmp("last", argv[1]) == 0)
          printf("%ld\n", rrd_last(argc - 1, &argv[1]));
      else if (strcmp("lastupdate", argv[1]) == 0) {
 -        time_t    last_update;
 -        char    **ds_namv;
 -        char    **last_ds;
 -        unsigned long ds_cnt, i;
 -
 -        if (rrd_lastupdate(argc - 1, &argv[1], &last_update,
 -                           &ds_cnt, &ds_namv, &last_ds) == 0) {
 -            for (i = 0; i < ds_cnt; i++)
 -                printf(" %s", ds_namv[i]);
 -            printf("\n\n");
 -            printf("%10lu:", last_update);
 -            for (i = 0; i < ds_cnt; i++) {
 -                printf(" %s", last_ds[i]);
 -                free(last_ds[i]);
 -                free(ds_namv[i]);
 -            }
 -            printf("\n");
 -            free(last_ds);
 -            free(ds_namv);
 -        }
 +        rrd_lastupdate(argc - 1, &argv[1]);
      } else if (strcmp("first", argv[1]) == 0)
          printf("%ld\n", rrd_first(argc - 1, &argv[1]));
      else if (strcmp("update", argv[1]) == 0)
  
      } else if (strcmp("tune", argv[1]) == 0)
          rrd_tune(argc - 1, &argv[1]);
 +    else if (strcmp("flush", argv[1]) == 0)
 +        rrd_cmd_flush(argc - 1, &argv[1]);
      else {
          rrd_set_error("unknown function '%s'", argv[1]);
      }
diff --combined src/rrd_tool.h
@@@ -1,5 -1,5 +1,5 @@@
  /*****************************************************************************
-  * RRDtool 1.3.0  Copyright by Tobi Oetiker, 1997-2008
+  * RRDtool 1.3.1  Copyright by Tobi Oetiker, 1997-2008
   *****************************************************************************
   * rrd_tool.h   Common Header File
   *****************************************************************************/
@@@ -77,14 -77,15 +77,14 @@@ extern    "C" 
      int       rrd_create_fn(
      const char *file_name,
      rrd_t *rrd);
 -    int       rrd_fetch_fn(
 -    const char *filename,
 -    enum cf_en cf_idx,
 -    time_t *start,
 -    time_t *end,
 -    unsigned long *step,
 -    unsigned long *ds_cnt,
 -    char ***ds_namv,
 -    rrd_value_t **data);
 +    int rrd_fetch_fn (const char *filename,
 +            enum cf_en cf_idx,
 +            time_t *start,
 +            time_t *end,
 +            unsigned long *step,
 +            unsigned long *ds_cnt,
 +            char ***ds_namv,
 +            rrd_value_t **data);
  
  #define RRD_READONLY    (1<<0)
  #define RRD_READWRITE   (1<<1)
diff --combined src/rrd_update.c
@@@ -1,7 -1,6 +1,7 @@@
  
  /*****************************************************************************
-  * RRDtool 1.3.0  Copyright by Tobi Oetiker, 1997-2008
+  * RRDtool 1.3.1  Copyright by Tobi Oetiker, 1997-2008
 + *                Copyright by Florian Forster, 2008
   *****************************************************************************
   * rrd_update.c  RRD Update Function
   *****************************************************************************
@@@ -24,8 -23,6 +24,8 @@@
  #include "rrd_is_thread_safe.h"
  #include "unused.h"
  
 +#include "rrd_client.h"
 +
  #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
  /*
   * WIN32 does not have gettimeofday   and struct timeval. This is a quick and dirty
@@@ -377,20 -374,18 +377,20 @@@ int rrd_update
  {
      struct option long_options[] = {
          {"template", required_argument, 0, 't'},
 +        {"daemon",   required_argument, 0, 'd'},
          {0, 0, 0, 0}
      };
      int       option_index = 0;
      int       opt;
      char     *tmplt = NULL;
      int       rc = -1;
 +    char     *opt_daemon = NULL;
  
      optind = 0;
      opterr = 0;         /* initialize getopt */
  
      while (1) {
 -        opt = getopt_long(argc, argv, "t:", long_options, &option_index);
 +        opt = getopt_long(argc, argv, "t:d:", long_options, &option_index);
  
          if (opt == EOF)
              break;
              tmplt = strdup(optarg);
              break;
  
 +        case 'd':
 +            if (opt_daemon != NULL)
 +                free (opt_daemon);
 +            opt_daemon = strdup (optarg);
 +            if (opt_daemon == NULL)
 +            {
 +                rrd_set_error("strdup failed.");
 +                goto out;
 +            }
 +            break;
 +
          case '?':
              rrd_set_error("unknown option '%s'", argv[optind - 1]);
              goto out;
          goto out;
      }
  
 +    if ((tmplt != NULL) && (opt_daemon != NULL))
 +    {
 +        rrd_set_error("The caching opt_daemon cannot be used together with "
 +                "templates yet.");
 +        goto out;
 +    }
 +
 +    if ((tmplt == NULL) && (opt_daemon == NULL))
 +    {
 +        char *temp;
 +
 +        temp = getenv (ENV_RRDCACHED_ADDRESS);
 +        if (temp != NULL)
 +        {
 +            opt_daemon = strdup (temp);
 +            if (opt_daemon == NULL)
 +            {
 +                rrd_set_error("strdup failed.");
 +                goto out;
 +            }
 +        }
 +    }
 +
 +    if (opt_daemon != NULL)
 +    {
 +        int status;
 +
 +        status = rrdc_connect (opt_daemon);
 +        if (status != 0)
 +        {
 +            rrd_set_error("Unable to connect to opt_daemon: %s",
 +                    (status < 0)
 +                    ? "Internal error"
 +                    : rrd_strerror (status));
 +            goto out;
 +        }
 +
 +        status = rrdc_update (/* file = */ argv[optind],
 +                /* values_num = */ argc - optind - 1,
 +                /* values = */ (void *) (argv + optind + 1));
 +        if (status != 0)
 +        {
 +            rrd_set_error("Failed sending the values to the opt_daemon: %s",
 +                    (status < 0)
 +                    ? "Internal error"
 +                    : rrd_strerror (status));
 +        }
 +        else
 +        {
 +            rc = 0;
 +        }
 +
 +        rrdc_disconnect ();
 +        goto out;
 +    } /* if (opt_daemon != NULL) */
 +
      rc = rrd_update_r(argv[optind], tmplt,
                        argc - optind - 1, (const char **) (argv + optind + 1));
    out:
 -    free(tmplt);
 +    if (tmplt != NULL)
 +    {
 +        free(tmplt);
 +        tmplt = NULL;
 +    }
 +    if (opt_daemon != NULL)
 +    {
 +        free (opt_daemon);
 +        opt_daemon = NULL;
 +    }
      return rc;
  }
  
@@@ -583,15 -502,15 +583,15 @@@ int _rrd_update
                          rra_step_cnt, updvals, tmpl_idx, tmpl_cnt,
                          &pcdp_summary, version, skip_update,
                          &schedule_smooth) == -1) {
-           if (rrd_test_error()) { /* Should have error string always here */
-               char *save_error;
-               /* Prepend file name to error message */
-               if ((save_error = strdup(rrd_get_error())) != NULL) {
-                   rrd_set_error("%s: %s", filename, save_error);
-                   free(save_error);
-               }
-           }
+             if (rrd_test_error()) { /* Should have error string always here */
+                 char     *save_error;
+                 /* Prepend file name to error message */
+                 if ((save_error = strdup(rrd_get_error())) != NULL) {
+                     rrd_set_error("%s: %s", filename, save_error);
+                     free(save_error);
+                 }
+             }
              free(arg_copy);
              break;
          }
diff --combined src/rrd_xport.c
@@@ -1,5 -1,5 +1,5 @@@
  /****************************************************************************
-  * RRDtool 1.3.0  Copyright by Tobi Oetiker, 1997-2008
+  * RRDtool 1.3.1  Copyright by Tobi Oetiker, 1997-2008
   ****************************************************************************
   * rrd_xport.c  export RRD data 
   ****************************************************************************/
@@@ -10,7 -10,6 +10,7 @@@
  #include "rrd_graph.h"
  #include "rrd_xport.h"
  #include "unused.h"
 +#include "rrd_client.h"
  
  #if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
  #include <io.h>
@@@ -54,6 -53,7 +54,6 @@@ int rrd_xport
      char ***legend_v,   /* legend entries */
      rrd_value_t **data)
  {                       /* two dimensional array containing the data */
 -
      image_desc_t im;
      time_t    start_tmp = 0, end_tmp = 0;
      rrd_time_value_t start_tv, end_tv;
@@@ -64,7 -64,6 +64,7 @@@
          {"maxrows", required_argument, 0, 'm'},
          {"step", required_argument, 0, 261},
          {"enumds", no_argument, 0, 262},    /* these are handled in the frontend ... */
 +        {"daemon", required_argument, 0, 'd'},
          {0, 0, 0, 0}
      };
  
@@@ -80,7 -79,7 +80,7 @@@
          int       option_index = 0;
          int       opt;
  
 -        opt = getopt_long(argc, argv, "s:e:m:", long_options, &option_index);
 +        opt = getopt_long(argc, argv, "s:e:m:d:", long_options, &option_index);
  
          if (opt == EOF)
              break;
                  return -1;
              }
              break;
 +        case 'd':
 +        {
 +            int status;
 +            if (im.use_rrdcached)
 +            {
 +                rrd_set_error ("You cannot specify --daemon "
 +                        "more than once.");
 +                return (-1);
 +            }
 +            status = rrdc_connect (optarg);
 +            if (status != 0)
 +            {
 +                rrd_set_error ("rrdc_connect(%s) failed with status %i.",
 +                        optarg, status);
 +                return (-1);
 +            }
 +            im.use_rrdcached = 1;
 +            break;
 +        }
 +
          case '?':
              rrd_set_error("unknown option '%s'", argv[optind - 1]);
              return -1;
          return (-1);
      }
  
 +    if (im.use_rrdcached == 0)
 +    {
 +        char *temp;
 +
 +        temp = getenv (ENV_RRDCACHED_ADDRESS);
 +        if (temp != NULL)
 +        {
 +            int status;
 +
 +            status = rrdc_connect (temp);
 +            if (status != 0)
 +            {
 +                rrd_set_error ("rrdc_connect(%s) failed with status %i.",
 +                        temp, status);
 +                return (-1);
 +            }
 +            im.use_rrdcached = 1;
 +        }
 +    }
 +
      if (rrd_xport_fn(&im, start, end, step, col_cnt, legend_v, data) == -1) {
          im_free(&im);
          return -1;