diff -u -ur rrdtool-trunk/doc/rrdgraph.pod rrdtool-trunk-happy/doc/rrdgraph.pod
--- rrdtool-trunk/doc/rrdgraph.pod	2007-08-16 10:28:34.000000000 -0400
+++ rrdtool-trunk-happy/doc/rrdgraph.pod	2007-12-13 09:48:57.000000000 -0500
@@ -153,6 +153,11 @@
 
 Gridfitting is turned off for PDF, EPS, SVG output by default.
 
+[B<-k>|B<--force-scale> I<min>:I<max>]
+
+Force scale (sKale) of graph.  I<min> is the lowest number on the y-axis,
+I<max> is the highest.  Can be used in conjunction with I<-p scale>.
+
 =item Grid
 
 =over 4
@@ -391,6 +396,28 @@
 Adds the given string as a watermark, horizontally centred, at the bottom 
 of the graph.
 
+[B<-p>|B<--print-info> I<DATA[:DATA]...>
+
+Print extra information about the graph.  DATA can be one of I<scale>,
+I<coords>, or I<all>.  Normally rrdgraph only prints the size of the image.
+B<--print-info> data is displayed before the size.
+
+I<scale> shows the minimum and maximum Y values on the graph.  For
+example:
+
+  scale_min = 0.0000000000e+00
+  scale_max = 9.9000000000e+01
+
+I<coords> prints the x and y origins and the size of the graph itself.
+For example:
+
+  xorigin = 51
+  yorigin = 122
+  xsize = 400
+  ysize = 100
+
+I<all> prints all extra information (currently just scale and coords).
+
 =item Data and variables
 
 B<DEF:>I<vname>B<=>I<rrdfile>B<:>I<ds-name>B<:>I<CF>[B<:step=>I<step>][B<:start=>I<time>][B<:end=>I<time>]
diff -u -ur rrdtool-trunk/src/rrd.h rrdtool-trunk-happy/src/rrd.h
--- rrdtool-trunk/src/rrd.h	2007-12-11 15:05:19.000000000 -0500
+++ rrdtool-trunk-happy/src/rrd.h	2007-12-13 10:29:45.000000000 -0500
@@ -86,6 +86,28 @@
         off_t     pos;  /* current pos in file */
     } rrd_file_t;
 
+/* rrd info interface */
+    enum info_type { RD_I_VAL = 0,
+        RD_I_CNT,
+        RD_I_STR,
+        RD_I_INT
+    };
+
+    typedef union infoval {
+        unsigned long u_cnt;
+        rrd_value_t u_val;
+        char     *u_str;
+        int       u_int;
+    } infoval;
+
+    typedef struct info_t {
+        char     *key;
+        enum info_type type;
+        union infoval value;
+        struct info_t *next;
+    } info_t;
+
+
 /* main function blocks */
     int       rrd_create(
     int,
@@ -102,6 +124,16 @@
     FILE *,
     double *,
     double *);
+    int       rrd_graph_info(
+    int,
+    char **,
+    char ***,
+    int *,
+    int *,
+    FILE *,
+    double *,
+    double *,
+    info_t **);
 
     unsigned char *rrd_graph_in_memory(
     int argc,
diff -u -ur rrdtool-trunk/src/rrd_graph.c rrdtool-trunk-happy/src/rrd_graph.c
--- rrdtool-trunk/src/rrd_graph.c	2007-12-11 15:05:19.000000000 -0500
+++ rrdtool-trunk-happy/src/rrd_graph.c	2007-12-13 10:29:41.000000000 -0500
@@ -1247,6 +1247,11 @@
        there was no data in the graph ... this is not good ...
        lets set these to dummy values then ... */
 
+    if ( im->extra_flags & FORCE_SCALE ) {
+      minval=im->force_scale_min;
+      maxval=im->force_scale_max;
+    }
+
     if (im->logarithmic) {
         if (isnan(minval))
             minval = 0.2;
@@ -2653,6 +2658,7 @@
 
     int       Xvertical = 0, Ytitle = 0, Xylabel = 0, Xmain = 0, Ymain = 0,
         Yxlabel = 0, Xspacing = 15, Yspacing = 15, Ywatermark = 4;
+    infoval   info;
 
     if (im->extra_flags & ONLY_GRAPH) {
         im->xorigin = 0;
@@ -2877,6 +2883,18 @@
     }
 
     ytr(im, DNAN);
+
+    /* Always display xsize and ysize */
+    info.u_cnt = im->xsize;
+    grinfo_push (im, sprintf_alloc("xsize"), RD_I_CNT, info);
+    info.u_cnt = im->ysize;
+    grinfo_push (im, sprintf_alloc("ysize"), RD_I_CNT, info);
+    if(im->extra_flags & PRINT_COORDS) {
+      info.u_cnt = im->xorigin;
+      grinfo_push (im, sprintf_alloc("xorigin"), RD_I_CNT, info);
+      info.u_cnt = im->yorigin - Ymain;
+      grinfo_push (im, sprintf_alloc("yorigin"), RD_I_CNT, info);
+    }
     return 0;
 }
 
@@ -2922,6 +2940,7 @@
 
     double    areazero = 0.0;
     graph_desc_t *lastgdes = NULL;
+    infoval   info;
 
     PangoFontMap *font_map = pango_cairo_font_map_get_default();
 
@@ -2965,6 +2984,15 @@
     if (!im->logarithmic) {
         si_unit(im);
     }
+
+    if(im->extra_flags & PRINT_SCALE) {
+      /*printf("scale: %.2f,%.2f\n",im->minval,im->maxval);*/
+      info.u_val = im->minval;
+      grinfo_push (im, sprintf_alloc("scale_min"), RD_I_VAL, info);
+      info.u_val = im->maxval;
+      grinfo_push (im, sprintf_alloc("scale_max"), RD_I_VAL, info);
+    }
+
     /* identify si magnitude Kilo, Mega Giga ? */
     if (!im->rigid && !im->logarithmic)
         expand_range(im);   /* make sure the upper and lower limit are
@@ -3455,13 +3483,28 @@
     return inp;
 }
 
+/* Now just a wrapper around rrd_graph_info */
+int rrd_graph(
+    int argc,
+    char **argv,
+    char ***prdata,
+    int *xsize,
+    int *ysize,
+    FILE * stream,
+    double *ymin,
+    double *ymax)
+{
+  return (int) (rrd_graph_info
+	  (argc, argv, prdata, xsize, ysize, stream, ymin, ymax, NULL));
+}
+
 /* Some surgery done on this function, it became ridiculously big.
 ** Things moved:
 ** - initializing     now in rrd_graph_init()
 ** - options parsing  now in rrd_graph_options()
 ** - script parsing   now in rrd_graph_script()
 */
-int rrd_graph(
+int rrd_graph_info(
     int argc,
     char **argv,
     char ***prdata,
@@ -3469,9 +3512,11 @@
     int *ysize,
     FILE * stream,
     double *ymin,
-    double *ymax)
+    double *ymax,
+    info_t **grinfo)
 {
     image_desc_t im;
+    im.grinfo = (info_t *) NULL;
 
     rrd_graph_init(&im);
 
@@ -3520,6 +3565,7 @@
 
     *xsize = im.ximg;
     *ysize = im.yimg;
+
     *ymin = im.minval;
     *ymax = im.maxval;
     if (im.imginfo) {
@@ -3549,6 +3595,9 @@
         sprintf((*prdata)[0], im.imginfo, filename,
                 (long) (im.zoom * im.ximg), (long) (im.zoom * im.yimg));
     }
+    if ( *grinfo == (info_t *) 1 ) {
+      *grinfo = im.grinfo;
+    }
     im_free(&im);
     return 0;
 }
@@ -3666,6 +3715,8 @@
     im->zoom = 1;
     im->font_options = cairo_font_options_create();
     im->graph_antialias = CAIRO_ANTIALIAS_GRAY;
+    im->force_scale_min = 0.0;
+    im->force_scale_max = 0.0;
 
     cairo_font_options_set_hint_style(im->font_options,
                                       CAIRO_HINT_STYLE_FULL);
@@ -3720,9 +3771,9 @@
     char *argv[],
     image_desc_t *im)
 {
-    int       stroff;
+    int       stroff, scan_matches;
     char     *parsetime_error = NULL;
-    char      scan_gtm[12], scan_mtm[12], scan_ltm[12], col_nam[12];
+    char      scan_gtm[12], scan_mtm[12], scan_ltm[12], col_nam[12], scan_info[12];
     time_t    start_tmp = 0, end_tmp = 0;
     long      long_tmp;
     struct rrd_time_value start_tv, end_tv;
@@ -3774,6 +3825,8 @@
         {"font-smoothing-threshold", required_argument, 0, 'B'},
         {"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 */
+        {"force-scale", required_argument, 0, 'k'},
+        {"print-info", required_argument, 0, 'p'},
         {0, 0, 0, 0}
     };
 
@@ -3789,7 +3842,7 @@
         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:",
+                          "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:k:p:",
                           long_options, &option_index);
 
         if (opt == EOF)
@@ -4117,6 +4170,41 @@
             im->watermark[99] = '\0';
             break;
 
+	case 'k':
+            im->extra_flags |= FORCE_SCALE;
+            if(sscanf(optarg, "%lf:%lf", &im->force_scale_min,&im->force_scale_max) != 2) {
+              rrd_set_error("unknown scale factor: %s.  (expecting min:max)",optarg);
+              return;
+            }
+            break;
+
+	case 'p':
+	  /* options must be 12 chars or less */
+	  while ( (scan_matches = sscanf (optarg, "%12[^:]", scan_info)) ) {
+	    if ( scan_matches == 0 || scan_matches == EOF ) {
+	      break;
+	    }
+	    optarg += sizeof (char) * strlen (scan_info);
+	    if ( strcmp (scan_info, "all") == 0 ) {
+	      im->extra_flags |= PRINT_SCALE;
+	      im->extra_flags |= PRINT_COORDS;
+	      break;
+	    }
+	    if ( strcmp (scan_info, "scale") == 0 ) {
+	      im->extra_flags |= PRINT_SCALE;
+	    }
+	    if ( strcmp (scan_info, "coords") == 0 ) {
+	      im->extra_flags |= PRINT_COORDS;
+	    }
+	    /* Either : or we're done */
+	    if ( *optarg == ':' ) {
+	      optarg++;
+	    } else {
+	      break;
+	    }
+	  }
+	  break;
+
         case '?':
             if (optopt != 0)
                 rrd_set_error("unknown option '%c'", optopt);
@@ -4596,3 +4684,16 @@
     else
         return 1;
 }
+
+void grinfo_push (
+    image_desc_t *im,
+    char *key, 
+    enum info_type type,
+    infoval value)
+{
+  if ( im->grinfo == NULL ) {
+    im->grinfo = info_push(NULL, key, type, value);
+  } else {
+    im->grinfo = info_push(im->grinfo, key, type, value);
+  }
+}
diff -u -ur rrdtool-trunk/src/rrd_graph.h rrdtool-trunk-happy/src/rrd_graph.h
--- rrdtool-trunk/src/rrd_graph.h	2007-09-24 14:04:05.000000000 -0400
+++ rrdtool-trunk-happy/src/rrd_graph.h	2007-12-13 10:29:49.000000000 -0500
@@ -30,6 +30,9 @@
 #define FORCE_UNITS_SI 0x100    /* force use of SI units in Y axis (no effect in linear graph, SI instead of E in log graph) */
 
 #define FULL_SIZE_MODE     0x200    /* -width and -height indicate the total size of the image */
+#define PRINT_SCALE        0x400    /* print the scale */
+#define PRINT_COORDS       0x800    /* print graph coords */
+#define FORCE_SCALE        0x1000   /* Force scale */
 
 enum tmt_en { TMT_SECOND = 0, TMT_MINUTE, TMT_HOUR, TMT_DAY,
     TMT_WEEK, TMT_MONTH, TMT_YEAR
@@ -211,6 +214,8 @@
                            existing one is out of date */
     int       slopemode;    /* connect the dots of the curve directly, not using a stair */
     int       logarithmic;  /* scale the yaxis logarithmic */
+    double         force_scale_min;   /* Force a scale--min */
+    double         force_scale_max;   /* Force a scale--max */
 
     /* status information */
 
@@ -237,6 +242,8 @@
     cairo_t  *cr;       /* drawin context */
     cairo_font_options_t *font_options; /* cairo font options */
     cairo_antialias_t graph_antialias;  /* antialiasing for the graph */
+
+    info_t *grinfo; /* extra graph info for printing */
 } image_desc_t;
 
 /* Prototypes */
@@ -338,6 +345,16 @@
     FILE *,
     double *,
     double *);
+int       rrd_graph_info(
+    int,
+    char **,
+    char ***,
+    int *,
+    int *,
+    FILE *,
+    double *,
+    double *,
+    info_t **);
 void      rrd_graph_init(
     image_desc_t *);
 void      rrd_graph_options(
@@ -367,8 +384,7 @@
     const void *);
 int       graph_size_location(
     image_desc_t *,
-    int
-    );
+    int);
 
 
 /* create a new line */
@@ -453,3 +469,9 @@
     double *y);
 
 #endif
+
+void grinfo_push (
+    image_desc_t *im,
+    char *key, 
+    enum info_type type,
+    infoval value);
diff -u -ur rrdtool-trunk/src/rrd_info.c rrdtool-trunk-happy/src/rrd_info.c
--- rrdtool-trunk/src/rrd_info.c	2007-12-11 15:05:19.000000000 -0500
+++ rrdtool-trunk-happy/src/rrd_info.c	2007-12-13 09:48:57.000000000 -0500
@@ -49,30 +49,34 @@
     enum info_type type,
     infoval value)
 {
-    info_t   *next;
+    info_t   *first;
 
-    next = malloc(sizeof(*next));
-    next->next = (info_t *) 0;
-    if (info)
-        info->next = next;
-    next->type = type;
-    next->key = key;
+    first = malloc(sizeof(*first));
+
+    if ( info ) {
+      first->next = info;
+    } else {
+      first->next = (info_t *) 0;
+    }
+
+    first->type = type;
+    first->key = key;
     switch (type) {
     case RD_I_VAL:
-        next->value.u_val = value.u_val;
+        first->value.u_val = value.u_val;
         break;
     case RD_I_CNT:
-        next->value.u_cnt = value.u_cnt;
+        first->value.u_cnt = value.u_cnt;
         break;
     case RD_I_INT:
-        next->value.u_int = value.u_int;
+        first->value.u_int = value.u_int;
         break;
     case RD_I_STR:
-        next->value.u_str = malloc(sizeof(char) * (strlen(value.u_str) + 1));
-        strcpy(next->value.u_str, value.u_str);
+        first->value.u_str = malloc(sizeof(char) * (strlen(value.u_str) + 1));
+        strcpy(first->value.u_str, value.u_str);
         break;
     }
-    return (next);
+    return (first);
 }
 
 
@@ -99,7 +103,7 @@
 {
     unsigned int i, ii = 0;
     rrd_t     rrd;
-    info_t   *data = NULL, *cd;
+    info_t   *data = NULL;
     infoval   info;
     rrd_file_t *rrd_file;
     enum cf_en current_cf;
@@ -110,22 +114,21 @@
         goto err_free;
 
     info.u_str = filename;
-    cd = info_push(NULL, sprintf_alloc("filename"), RD_I_STR, info);
-    data = cd;
+    data = info_push(NULL, sprintf_alloc("filename"), RD_I_STR, info);
 
     info.u_str = rrd.stat_head->version;
-    cd = info_push(cd, sprintf_alloc("rrd_version"), RD_I_STR, info);
+    data = info_push(data, sprintf_alloc("rrd_version"), RD_I_STR, info);
 
     info.u_cnt = rrd.stat_head->pdp_step;
-    cd = info_push(cd, sprintf_alloc("step"), RD_I_CNT, info);
+    data = info_push(data, sprintf_alloc("step"), RD_I_CNT, info);
 
     info.u_cnt = rrd.live_head->last_up;
-    cd = info_push(cd, sprintf_alloc("last_update"), RD_I_CNT, info);
+    data = info_push(data, sprintf_alloc("last_update"), RD_I_CNT, info);
 
     for (i = 0; i < rrd.stat_head->ds_cnt; i++) {
 
         info.u_str = rrd.ds_def[i].dst;
-        cd = info_push(cd, sprintf_alloc("ds[%s].type", rrd.ds_def[i].ds_nam),
+        data = info_push(data, sprintf_alloc("ds[%s].type", rrd.ds_def[i].ds_nam),
                        RD_I_STR, info);
 
         current_ds = dst_conv(rrd.ds_def[i].dst);
@@ -137,7 +140,7 @@
             rpn_compact2str((rpn_cdefds_t *) &(rrd.ds_def[i].par[DS_cdef]),
                             rrd.ds_def, &buffer);
             info.u_str = buffer;
-            cd = info_push(cd,
+            data = info_push(data,
                            sprintf_alloc("ds[%s].cdef", rrd.ds_def[i].ds_nam),
                            RD_I_STR, info);
             free(buffer);
@@ -145,93 +148,93 @@
             break;
         default:
             info.u_cnt = rrd.ds_def[i].par[DS_mrhb_cnt].u_cnt;
-            cd = info_push(cd,
+            data = info_push(data,
                            sprintf_alloc("ds[%s].minimal_heartbeat",
                                          rrd.ds_def[i].ds_nam), RD_I_CNT,
                            info);
 
             info.u_val = rrd.ds_def[i].par[DS_min_val].u_val;
-            cd = info_push(cd,
+            data = info_push(data,
                            sprintf_alloc("ds[%s].min", rrd.ds_def[i].ds_nam),
                            RD_I_VAL, info);
 
             info.u_val = rrd.ds_def[i].par[DS_max_val].u_val;
-            cd = info_push(cd,
+            data = info_push(data,
                            sprintf_alloc("ds[%s].max", rrd.ds_def[i].ds_nam),
                            RD_I_VAL, info);
             break;
         }
 
         info.u_str = rrd.pdp_prep[i].last_ds;
-        cd = info_push(cd,
+        data = info_push(data,
                        sprintf_alloc("ds[%s].last_ds", rrd.ds_def[i].ds_nam),
                        RD_I_STR, info);
 
         info.u_val = rrd.pdp_prep[i].scratch[PDP_val].u_val;
-        cd = info_push(cd,
+        data = info_push(data,
                        sprintf_alloc("ds[%s].value", rrd.ds_def[i].ds_nam),
                        RD_I_VAL, info);
 
         info.u_cnt = rrd.pdp_prep[i].scratch[PDP_unkn_sec_cnt].u_cnt;
-        cd = info_push(cd,
+        data = info_push(data,
                        sprintf_alloc("ds[%s].unknown_sec",
                                      rrd.ds_def[i].ds_nam), RD_I_CNT, info);
     }
 
     for (i = 0; i < rrd.stat_head->rra_cnt; i++) {
         info.u_str = rrd.rra_def[i].cf_nam;
-        cd = info_push(cd, sprintf_alloc("rra[%d].cf", i), RD_I_STR, info);
+        data = info_push(data, sprintf_alloc("rra[%d].cf", i), RD_I_STR, info);
         current_cf = cf_conv(rrd.rra_def[i].cf_nam);
 
         info.u_cnt = rrd.rra_def[i].row_cnt;
-        cd = info_push(cd, sprintf_alloc("rra[%d].rows", i), RD_I_CNT, info);
+        data = info_push(data, sprintf_alloc("rra[%d].rows", i), RD_I_CNT, info);
 
         info.u_cnt = rrd.rra_def[i].pdp_cnt;
-        cd = info_push(cd, sprintf_alloc("rra[%d].pdp_per_row", i), RD_I_CNT,
+        data = info_push(data, sprintf_alloc("rra[%d].pdp_per_row", i), RD_I_CNT,
                        info);
 
         switch (current_cf) {
         case CF_HWPREDICT:
         case CF_MHWPREDICT:
             info.u_val = rrd.rra_def[i].par[RRA_hw_alpha].u_val;
-            cd = info_push(cd, sprintf_alloc("rra[%d].alpha", i), RD_I_VAL,
+            data = info_push(data, sprintf_alloc("rra[%d].alpha", i), RD_I_VAL,
                            info);
             info.u_val = rrd.rra_def[i].par[RRA_hw_beta].u_val;
-            cd = info_push(cd, sprintf_alloc("rra[%d].beta", i), RD_I_VAL,
+            data = info_push(data, sprintf_alloc("rra[%d].beta", i), RD_I_VAL,
                            info);
             break;
         case CF_SEASONAL:
         case CF_DEVSEASONAL:
             info.u_val = rrd.rra_def[i].par[RRA_seasonal_gamma].u_val;
-            cd = info_push(cd, sprintf_alloc("rra[%d].gamma", i), RD_I_VAL,
+            data = info_push(data, sprintf_alloc("rra[%d].gamma", i), RD_I_VAL,
                            info);
             if (atoi(rrd.stat_head->version) >= 4) {
                 info.u_val =
                     rrd.rra_def[i].par[RRA_seasonal_smoothing_window].u_val;
-                cd = info_push(cd,
+                data = info_push(data,
                                sprintf_alloc("rra[%d].smoothing_window", i),
                                RD_I_VAL, info);
             }
             break;
         case CF_FAILURES:
             info.u_val = rrd.rra_def[i].par[RRA_delta_pos].u_val;
-            cd = info_push(cd, sprintf_alloc("rra[%d].delta_pos", i),
+            data = info_push(data, sprintf_alloc("rra[%d].delta_pos", i),
                            RD_I_VAL, info);
             info.u_val = rrd.rra_def[i].par[RRA_delta_neg].u_val;
-            cd = info_push(cd, sprintf_alloc("rra[%d].delta_neg", i),
+            data = info_push(data, sprintf_alloc("rra[%d].delta_neg", i),
                            RD_I_VAL, info);
             info.u_cnt = rrd.rra_def[i].par[RRA_failure_threshold].u_cnt;
-            cd = info_push(cd, sprintf_alloc("rra[%d].failure_threshold", i),
+            data = info_push(data, sprintf_alloc("rra[%d].failure_threshold", i),
                            RD_I_CNT, info);
             info.u_cnt = rrd.rra_def[i].par[RRA_window_len].u_cnt;
-            cd = info_push(cd, sprintf_alloc("rra[%d].window_length", i),
+            data = info_push(data, sprintf_alloc("rra[%d].window_length", i),
                            RD_I_CNT, info);
             break;
         case CF_DEVPREDICT:
             break;
         default:
             info.u_val = rrd.rra_def[i].par[RRA_cdp_xff_val].u_val;
-            cd = info_push(cd, sprintf_alloc("rra[%d].xff", i), RD_I_VAL,
+            data = info_push(data, sprintf_alloc("rra[%d].xff", i), RD_I_VAL,
                            info);
             break;
         }
@@ -243,19 +246,19 @@
                 info.u_val =
                     rrd.cdp_prep[i * rrd.stat_head->ds_cnt +
                                  ii].scratch[CDP_hw_intercept].u_val;
-                cd = info_push(cd,
+                data = info_push(data,
                                sprintf_alloc("rra[%d].cdp_prep[%d].intercept",
                                              i, ii), RD_I_VAL, info);
                 info.u_val =
                     rrd.cdp_prep[i * rrd.stat_head->ds_cnt +
                                  ii].scratch[CDP_hw_slope].u_val;
-                cd = info_push(cd,
+                data = info_push(data,
                                sprintf_alloc("rra[%d].cdp_prep[%d].slope", i,
                                              ii), RD_I_VAL, info);
                 info.u_cnt =
                     rrd.cdp_prep[i * rrd.stat_head->ds_cnt +
                                  ii].scratch[CDP_null_count].u_cnt;
-                cd = info_push(cd,
+                data = info_push(data,
                                sprintf_alloc("rra[%d].cdp_prep[%d].NaN_count",
                                              i, ii), RD_I_CNT, info);
                 break;
@@ -263,7 +266,7 @@
                 info.u_val =
                     rrd.cdp_prep[i * rrd.stat_head->ds_cnt +
                                  ii].scratch[CDP_hw_seasonal].u_val;
-                cd = info_push(cd,
+                data = info_push(data,
                                sprintf_alloc("rra[%d].cdp_prep[%d].seasonal",
                                              i, ii), RD_I_VAL, info);
                 break;
@@ -271,7 +274,7 @@
                 info.u_val =
                     rrd.cdp_prep[i * rrd.stat_head->ds_cnt +
                                  ii].scratch[CDP_seasonal_deviation].u_val;
-                cd = info_push(cd,
+                data = info_push(data,
                                sprintf_alloc("rra[%d].cdp_prep[%d].deviation",
                                              i, ii), RD_I_VAL, info);
                 break;
@@ -290,7 +293,7 @@
                     history[j] = (violations_array[j] == 1) ? '1' : '0';
                 history[j] = '\0';
                 info.u_str = history;
-                cd = info_push(cd,
+                data = info_push(data,
                                sprintf_alloc("rra[%d].cdp_prep[%d].history",
                                              i, ii), RD_I_STR, info);
             }
@@ -299,13 +302,13 @@
                 info.u_val =
                     rrd.cdp_prep[i * rrd.stat_head->ds_cnt +
                                  ii].scratch[CDP_val].u_val;
-                cd = info_push(cd,
+                data = info_push(data,
                                sprintf_alloc("rra[%d].cdp_prep[%d].value", i,
                                              ii), RD_I_VAL, info);
                 info.u_cnt =
                     rrd.cdp_prep[i * rrd.stat_head->ds_cnt +
                                  ii].scratch[CDP_unkn_pdp_cnt].u_cnt;
-                cd = info_push(cd,
+                data = info_push(data,
                                sprintf_alloc
                                ("rra[%d].cdp_prep[%d].unknown_datapoints", i,
                                 ii), RD_I_CNT, info);
@@ -319,3 +322,48 @@
     rrd_free(&rrd);
     return (data);
 }
+
+void info_print (info_t *data) {
+  info_t *save;
+
+  while (data) {
+    save = data;
+    printf("%s = ", data->key);
+    free(data->key);
+
+    switch (data->type) {
+    case RD_I_VAL:
+      if (isnan(data->value.u_val))
+	printf("NaN");
+      else
+	printf("%0.10e", data->value.u_val);
+      break;
+    case RD_I_CNT:
+      printf("%lu", data->value.u_cnt);
+      break;
+    case RD_I_INT:
+      printf("%d", data->value.u_int);
+      break;
+    case RD_I_STR:
+      printf("\"%s\"", data->value.u_str);
+      free(data->value.u_str);
+      break;
+    }
+    data = data->next;
+    free(save);
+    printf("\n");
+  }
+}
+
+void info_free (info_t *data) {
+  info_t *save;
+
+  while (data) {
+    save = data;
+    if ( data->key ) {
+      free(data->key);
+    }
+    data = data->next;
+    free(save);
+  }
+}
diff -u -ur rrdtool-trunk/src/rrd_tool.c rrdtool-trunk-happy/src/rrd_tool.c
--- rrdtool-trunk/src/rrd_tool.c	2007-08-16 10:28:22.000000000 -0400
+++ rrdtool-trunk-happy/src/rrd_tool.c	2007-12-13 11:03:06.000000000 -0500
@@ -593,39 +593,13 @@
     else if (strcmp("dump", argv[1]) == 0)
         rrd_dump(argc - 1, &argv[1]);
     else if (strcmp("info", argv[1]) == 0 || strcmp("updatev", argv[1]) == 0) {
-        info_t   *data, *save;
+        info_t   *data;
 
         if (strcmp("info", argv[1]) == 0)
             data = rrd_info(argc - 1, &argv[1]);
         else
             data = rrd_update_v(argc - 1, &argv[1]);
-        while (data) {
-            save = data;
-            printf("%s = ", data->key);
-            free(data->key);
-
-            switch (data->type) {
-            case RD_I_VAL:
-                if (isnan(data->value.u_val))
-                    printf("NaN");
-                else
-                    printf("%0.10e", data->value.u_val);
-                break;
-            case RD_I_CNT:
-                printf("%lu", data->value.u_cnt);
-                break;
-            case RD_I_INT:
-                printf("%d", data->value.u_int);
-                break;
-            case RD_I_STR:
-                printf("\"%s\"", data->value.u_str);
-                free(data->value.u_str);
-                break;
-            }
-            data = data->next;
-            free(save);
-            printf("\n");
-        }
+	info_print (data);
         free(data);
     }
 
@@ -776,6 +750,7 @@
         int       i;
         int       tostdout = (strcmp(argv[2], "-") == 0);
         int       imginfo = 0;
+	info_t    *grinfo = (info_t *) 1; /* 1 to distinguish it from the NULL that rrd_graph sends in */
 
         for (i = 2; i < argc; i++) {
             if (strcmp(argv[i], "--imginfo") == 0
@@ -784,11 +759,16 @@
                 break;
             }
         }
-        if (rrd_graph
+        if (rrd_graph_info
             (argc - 1, &argv[1], &calcpr, &xsize, &ysize, NULL, &ymin,
-             &ymax) != -1) {
-            if (!tostdout && !imginfo)
-                printf("%dx%d\n", xsize, ysize);
+             &ymax, &grinfo) != -1) {
+            if (!tostdout && !imginfo) {
+		/* print graph info if any */
+		if ( grinfo != NULL && grinfo != (info_t *) 1 ) {
+		  info_print (grinfo);
+		  /* testing free (grinfo);*/
+		}
+	    }
             if (calcpr) {
                 for (i = 0; calcpr[i]; i++) {
                     if (!tostdout)
@@ -797,7 +777,11 @@
                 }
                 free(calcpr);
             }
-        }
+        } else {
+	  if ( grinfo != NULL && grinfo != (info_t *) 1 ) {
+	    info_free (grinfo);
+	  }
+	}
 
     } else if (strcmp("tune", argv[1]) == 0)
         rrd_tune(argc - 1, &argv[1]);
diff -u -ur rrdtool-trunk/src/rrd_tool.h rrdtool-trunk-happy/src/rrd_tool.h
--- rrdtool-trunk/src/rrd_tool.h	2007-08-16 10:28:22.000000000 -0400
+++ rrdtool-trunk-happy/src/rrd_tool.h	2007-12-13 09:48:57.000000000 -0500
@@ -63,27 +63,6 @@
 
 #define DIM(x) (sizeof(x)/sizeof(x[0]))
 
-/* rrd info interface */
-    enum info_type { RD_I_VAL = 0,
-        RD_I_CNT,
-        RD_I_STR,
-        RD_I_INT
-    };
-
-    typedef union infoval {
-        unsigned long u_cnt;
-        rrd_value_t u_val;
-        char     *u_str;
-        int       u_int;
-    } infoval;
-
-    typedef struct info_t {
-        char     *key;
-        enum info_type type;
-        union infoval value;
-        struct info_t *next;
-    } info_t;
-
     info_t   *rrd_info(
     int,
     char **);
@@ -105,6 +84,9 @@
     char *,
     enum info_type,
     infoval);
+    void info_print (
+    info_t *data);
+    void info_free (info_t *);
 
 /* HELPER FUNCTIONS */
 
