char* printtimelast(long argc, const char **args) {
  time_t last;
  struct tm tm_last;
  char *buf;
  if ( argc == 2 ) {
    buf = malloc(255);
    if (buf == NULL){	
	return stralloc("[ERROR: allocating strftime buffer]");
    };
    last = rrd_last(argc+1, (char **) args-1); 
    if (rrd_test_error()) {
      char *err = malloc((strlen(rrd_get_error())+DS_NAM_SIZE)*sizeof(char));
      sprintf(err, "[ERROR: %s]",rrd_get_error());
      rrd_clear_error();
      return err;
    }
    tm_last = *localtime(&last);
    strftime(buf,254,args[1],&tm_last);
    return buf;
  }
  if ( argc < 2 ) {
    return stralloc("[ERROR: too few arguments for RRD::TIME::LAST]");
  }
  return stralloc("[ERROR: not enough arguments for RRD::TIME::LAST]");
}
示例#2
0
time_t	RRD_LastUpdate(char *path) {
struct stat statbuf;
char 	rrd_filename[1024];
char	*rrd_arg[10];
time_t	when;
int 	len, argc;

	// Get timestamp from the first file
	len = snprintf(rrd_filename, 1024, "%s/%s-%s-%d.rrd", path, "tcp", "flows", 0);
	if ( len >= 1024 ) {
		fprintf(stderr, "Failed to concat RRD filename: string overflow");
		return 0;
	}
		
	// Check if RRD file exists
	if ( (stat(rrd_filename, &statbuf) < 0 ) || !(statbuf.st_mode & S_IFREG) ) {
		fprintf(stderr, "RRD files not found in '%s'\n", path);
		return 0;
	}

	argc = 0;
	rrd_arg[argc++] = "last";
	rrd_arg[argc++] = rrd_filename;
	rrd_arg[argc]   = NULL;

	when = rrd_last(argc, rrd_arg);
	
	return when;

} // End of RRD_LastUpdate
示例#3
0
char     *printtimelast(
    long argc,
    const char **args)
{
    time_t    last;
    struct tm tm_last;
    char     *buf;

    if (argc == 2) {
        buf = malloc(255);
        if (buf == NULL) {
            return stralloc("[ERROR: allocating strftime buffer]");
        };
        /* not raising argc in step with args - 1 since the last argument
           will be used below for strftime  */

        last = rrd_last(argc, (char **) args - 1);
        if (rrd_test_error()) {
            const size_t len = strlen(rrd_get_error()) + DS_NAM_SIZE;
            char *err = malloc(len);
            snprintf(err, len, "[ERROR: %s]", rrd_get_error());
            rrd_clear_error();
            return err;
        }
        tm_last = *localtime(&last);
        strftime(buf, 254, args[1], &tm_last);
        return buf;
    }
    return stralloc("[ERROR: expected <RRD::TIME::LAST file.rrd strftime-format>]");
}
示例#4
0
文件: rrrd.c 项目: tylerhunt/rrrd
static VALUE rrrd_rrd_last(VALUE self) {
  list arguments = rrrd_list_new();
  rrrd_add_filename_arg(self, &arguments);

  time_t last = rrd_last(arguments.length, arguments.strings);
  rrrd_free_arguments(arguments);
  rrrd_check_for_errors();

  return rb_time_new(last, 0);
}
示例#5
0
VALUE rb_rrd_last(VALUE self, VALUE args)
{
    string_arr a;
    time_t last;

    a = string_arr_new(args);
    reset_rrd_state();
    last = rrd_last(a.len, a.strings);
    string_arr_delete(a);

    RRD_CHECK_ERROR

    return rb_funcall(rb_cTime, rb_intern("at"), 1, INT2FIX(last));
}
示例#6
0
static PyObject * _RRD_call(PyObject *self, PyObject *args) {

    char **argv;
    int argc, rc;

    argv = parse_args(args, &argc);
    if (!argv)
        return NULL;

    if (!strcmp("create", argv[0])) 
        rc = rrd_create(argc, argv);
    else if (!strcmp("update", argv[0]))
        rc = rrd_update(argc, argv);
    else if (!strcmp("restore", argv[0]))
        rc = rrd_restore(argc, argv);
    else if (!strcmp("dump", argv[0]))
        rc = rrd_dump(argc, argv);
    else if (!strcmp("tune", argv[0]))
        rc = rrd_tune(argc, argv);
    else if (!strcmp("last", argv[0]))
        rc = rrd_last(argc, argv);
    else if (!strcmp("resize", argv[0]))
        rc = rrd_resize(argc, argv);
    else if (!strcmp("fetch", argv[0])) 
        return _RRD_fetch(argc, argv);
    else if (!strcmp("graph", argv[0])) {
        return _RRD_graph(argc, argv);
    }
    else {
        PyMem_DEL(argv);
        PyErr_SetString(PyExc_TypeError,
                        "invalid action");
        return NULL;
    }
    
    if (rc == -1) {
        PyMem_DEL(argv);
        PyErr_SetString(PyExc_ValueError,
                        rrd_get_error());
        rrd_clear_error();
        return NULL;
    }
    
    PyMem_DEL(argv);
    return PyLong_FromLong(rc);
}
示例#7
0
static PyObject *
PyRRD_last(PyObject UNUSED(*self), PyObject *args)
{
    PyObject        *r;
    int              argc, ts;
    char           **argv;

    if (create_args("last", args, &argc, &argv) < 0)
        return NULL;

    if ((ts = rrd_last(argc, argv)) == -1) {
        PyErr_SetString(ErrorObject, rrd_get_error());
        rrd_clear_error();
        r = NULL;
    } else
        r = PyInt_FromLong((long)ts);

    destroy_args(&argv);
    return r;
}
示例#8
0
JNIEXPORT jobject JNICALL Java_gnu_rrd_RRDJNI_last
(JNIEnv *env, jclass cl, jobjectArray argv) {
  char      **argv2;
  time_t    t;
  
  jclass    DateClass;
  jmethodID DateMethodInit;
  jobject   DateObj;
  jlong     timestamp;
  
  argv2 = initArgs(env, argv, "last");
  t = rrd_last((*env)->GetArrayLength(env, argv)+1, argv2);
  timestamp = t;
 
  DateClass      = (*env)->FindClass(env, "java/util/Date");
  DateMethodInit = (*env)->GetMethodID(env, DateClass, "<init>", "(J)V");
  DateObj        = (*env)->NewObject(env, DateClass, DateMethodInit, timestamp*1000);
  
  freeArgs(env, argv, argv2);
  if (rrd_test_error())
    throwException(env, "gnu/rrd/RRDException", rrd_get_error());

  return DateObj;
}
示例#9
0
/* HandleInputLine is NOT thread safe - due to readdir issues,
   resolving them portably is not really simple. */
int HandleInputLine(
    int argc,
    char **argv,
    FILE * out)
{
#if defined(HAVE_OPENDIR) && defined (HAVE_READDIR)
    DIR      *curdir;   /* to read current dir with ls */
    struct dirent *dent;
#endif

    /* Reset errno to 0 before we start.
     */
    if (RemoteMode) {
        if (argc > 1 && strcmp("quit", argv[1]) == 0) {
            if (argc != 2) {
                printf("ERROR: invalid parameter count for quit\n");
                return (1);
            }
            exit(0);
        }
#if defined(HAVE_OPENDIR) && defined(HAVE_READDIR) && defined(HAVE_CHDIR) && defined(HAVE_SYS_STAT_H)
        if (argc > 1 && strcmp("cd", argv[1]) == 0) {
            if (argc != 3) {
                printf("ERROR: invalid parameter count for cd\n");
                return (1);
            }
#if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
            if (getuid() == 0 && !ChangeRoot) {
                printf
                    ("ERROR: chdir security problem - rrdtool is running as "
                     "root but not chroot!\n");
                return (1);
            }
#endif
            if (chdir(argv[2]) != 0){
                printf("ERROR: chdir %s %s\n", argv[2], rrd_strerror(errno));
                return (1);
            }
            return (0);
        }
        if (argc > 1 && strcmp("pwd", argv[1]) == 0) {
            char     *cwd;      /* To hold current working dir on call to pwd */
            if (argc != 2) {
                printf("ERROR: invalid parameter count for pwd\n");
                return (1);
            }
            cwd = getcwd(NULL, MAXPATH);
            if (cwd == NULL) {
                printf("ERROR: getcwd %s\n", rrd_strerror(errno));
                return (1);
            }
            printf("%s\n", cwd);
            free(cwd);
            return (0);
        }
        if (argc > 1 && strcmp("mkdir", argv[1]) == 0) {
            if (argc != 3) {
                printf("ERROR: invalid parameter count for mkdir\n");
                return (1);
            }
#if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
            if (getuid() == 0 && !ChangeRoot) {
                printf
                    ("ERROR: mkdir security problem - rrdtool is running as "
                     "root but not chroot!\n");
                return (1);
            }
#endif
            if(mkdir(argv[2], 0777)!=0){
                printf("ERROR: mkdir %s: %s\n", argv[2],rrd_strerror(errno));
                return (1);
            }
            return (0);
        }
        if (argc > 1 && strcmp("ls", argv[1]) == 0) {
            if (argc != 2) {
                printf("ERROR: invalid parameter count for ls\n");
                return (1);
            }
            if ((curdir = opendir(".")) != NULL) {
                struct stat st;
                while ((dent = readdir(curdir)) != NULL) {
                    if (!stat(dent->d_name, &st)) {
                        if (S_ISDIR(st.st_mode)) {
                            printf("d %s\n", dent->d_name);
                        }
                        if (strlen(dent->d_name) > 4 && S_ISREG(st.st_mode)) {
                            if (!strcmp
                                (dent->d_name + NAMLEN(dent) - 4, ".rrd")
                                || !strcmp(dent->d_name + NAMLEN(dent) - 4,
                                           ".RRD")) {
                                printf("- %s\n", dent->d_name);
                            }
                        }
                    }
                }
                closedir(curdir);
            } else {
                printf("ERROR: opendir .: %s\n", rrd_strerror(errno));
                return (errno);
            }
            return (0);
        }
#endif                          /* opendir and readdir */

    }
    if (argc < 3
        || strcmp("help", argv[1]) == 0
        || strcmp("--help", argv[1]) == 0
        || strcmp("-help", argv[1]) == 0
        || strcmp("-?", argv[1]) == 0 || strcmp("-h", argv[1]) == 0) {
        PrintUsage("");
        return 0;
    }

    if (strcmp("create", argv[1]) == 0)
        rrd_create(argc - 1, &argv[1]);
    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) {
        rrd_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]);
        rrd_info_print(data);
        rrd_info_free(data);
    }

    else if (strcmp("--version", argv[1]) == 0 ||
             strcmp("version", argv[1]) == 0 ||
             strcmp("v", argv[1]) == 0 ||
             strcmp("-v", argv[1]) == 0 || strcmp("-version", argv[1]) == 0)
        printf("RRDtool " PACKAGE_VERSION
               "  Copyright by Tobi Oetiker, 1997-2008 (%f)\n",
               rrd_version());
    else if (strcmp("restore", argv[1]) == 0)
        rrd_restore(argc - 1, &argv[1]);
    else if (strcmp("resize", argv[1]) == 0)
        rrd_resize(argc - 1, &argv[1]);
    else if (strcmp("last", argv[1]) == 0)
        printf("%ld\n", rrd_last(argc - 1, &argv[1]));
    else if (strcmp("lastupdate", argv[1]) == 0) {
        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)
        rrd_update(argc - 1, &argv[1]);
    else if (strcmp("fetch", argv[1]) == 0) {
        time_t    start, end, ti;
        unsigned long step, ds_cnt, i, ii;
        rrd_value_t *data, *datai;
        char    **ds_namv;

        if (rrd_fetch
            (argc - 1, &argv[1], &start, &end, &step, &ds_cnt, &ds_namv,
             &data) == 0) {
            datai = data;
            printf("           ");
            for (i = 0; i < ds_cnt; i++)
                printf("%20s", ds_namv[i]);
            printf("\n\n");
            for (ti = start + step; ti <= end; ti += step) {
                printf("%10lu:", ti);
                for (ii = 0; ii < ds_cnt; ii++)
                    printf(" %0.10e", *(datai++));
                printf("\n");
            }
            for (i = 0; i < ds_cnt; i++)
                free(ds_namv[i]);
            free(ds_namv);
            free(data);
        }
    } else if (strcmp("xport", argv[1]) == 0) {
#ifdef HAVE_RRD_GRAPH
      time_t    start, end;
      unsigned long step, col_cnt;
      rrd_value_t *data;
      char    **legend_v;
      rrd_xport
	(argc - 1, &argv[1], NULL, &start, &end, &step, &col_cnt,
	 &legend_v, &data);
#else
        rrd_set_error("the instance of rrdtool has been compiled without graphics");
#endif
    } else if (strcmp("graph", argv[1]) == 0) {
#ifdef HAVE_RRD_GRAPH
        char    **calcpr;

#ifdef notused /*XXX*/
        const char *imgfile = argv[2];  /* rrd_graph changes argv pointer */
#endif
        int       xsize, ysize;
        double    ymin, ymax;
        int       i;
        int       tostdout = (strcmp(argv[2], "-") == 0);
        int       imginfo = 0;

        for (i = 2; i < argc; i++) {
            if (strcmp(argv[i], "--imginfo") == 0
                || strcmp(argv[i], "-f") == 0) {
                imginfo = 1;
                break;
            }
        }
        if (rrd_graph
            (argc - 1, &argv[1], &calcpr, &xsize, &ysize, NULL, &ymin,
             &ymax) == 0) {
            if (!tostdout && !imginfo)
                printf("%dx%d\n", xsize, ysize);
            if (calcpr) {
                for (i = 0; calcpr[i]; i++) {
                    if (!tostdout)
                        printf("%s\n", calcpr[i]);
                    free(calcpr[i]);
                }
                free(calcpr);
            }
        }

#else
       rrd_set_error("the instance of rrdtool has been compiled without graphics");
#endif
    } else if (strcmp("graphv", argv[1]) == 0) {
#ifdef HAVE_RRD_GRAPH
        rrd_info_t *grinfo = NULL;  /* 1 to distinguish it from the NULL that rrd_graph sends in */

        grinfo = rrd_graph_v(argc - 1, &argv[1]);
        if (grinfo) {
            rrd_info_print(grinfo);
            rrd_info_free(grinfo);
        }
#else
       rrd_set_error("the instance of rrdtool has been compiled without graphics");
#endif
    } else if (strcmp("tune", argv[1]) == 0)
        rrd_tune(argc - 1, &argv[1]);
    else if (strcmp("flushcached", argv[1]) == 0)
        rrd_flushcached(argc - 1, &argv[1]);
    else if (strcmp("modify", argv[1]) == 0)
        rrd_modify(argc - 1, &argv[1]);
    else {
        rrd_set_error("unknown function '%s'", argv[1]);
    }
    if (rrd_test_error()) {
        fprintf(out, "ERROR: %s\n", rrd_get_error());
        rrd_clear_error();
        return 1;
    }
    return (0);
}
示例#10
0
/* HandleInputLine is NOT thread safe - due to readdir issues,
   resolving them portably is not really simple. */
int HandleInputLine(
    int argc,
    char **argv,
    FILE * out)
{
#if defined(HAVE_OPENDIR) && defined (HAVE_READDIR)
    DIR      *curdir;   /* to read current dir with ls */
    struct dirent *dent;
#endif
#if defined(HAVE_SYS_STAT_H)
    struct stat st;
#endif

    /* Reset errno to 0 before we start.
     */
    if (RemoteMode) {
        if (argc > 1 && strcmp("quit", argv[1]) == 0) {
            if (argc > 2) {
                printf("ERROR: invalid parameter count for quit\n");
                return (1);
            }
            exit(0);
        }
#if defined(HAVE_OPENDIR) && defined(HAVE_READDIR) && defined(HAVE_CHDIR)
        if (argc > 1 && strcmp("cd", argv[1]) == 0) {
            if (argc > 3) {
                printf("ERROR: invalid parameter count for cd\n");
                return (1);
            }
#if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
            if (getuid() == 0 && !ChangeRoot) {
                printf
                ("ERROR: chdir security problem - rrdtool is running as "
                 "root but not chroot!\n");
                return (1);
            }
#endif
            if (chdir(argv[2]) != 0) {
                printf("ERROR: chdir %s %s\n", argv[2], rrd_strerror(errno));
                return (1);
            }
            return (0);
        }
        if (argc > 1 && strcmp("pwd", argv[1]) == 0) {
            char     *cwd;      /* To hold current working dir on call to pwd */
            if (argc > 2) {
                printf("ERROR: invalid parameter count for pwd\n");
                return (1);
            }
            cwd = getcwd(NULL, MAXPATH);
            if (cwd == NULL) {
                printf("ERROR: getcwd %s\n", rrd_strerror(errno));
                return (1);
            }
            printf("%s\n", cwd);
            free(cwd);
            return (0);
        }
        if (argc > 1 && strcmp("mkdir", argv[1]) == 0) {
            if (argc > 3) {
                printf("ERROR: invalid parameter count for mkdir\n");
                return (1);
            }
#if ! defined(HAVE_CHROOT) || ! defined(HAVE_GETUID)
            if (getuid() == 0 && !ChangeRoot) {
                printf
                ("ERROR: mkdir security problem - rrdtool is running as "
                 "root but not chroot!\n");
                return (1);
            }
#endif
            if(mkdir(argv[2], 0777)!=0) {
                printf("ERROR: mkdir %s: %s\n", argv[2],rrd_strerror(errno));
                return (1);
            }
            return (0);
        }
        if (argc > 1 && strcmp("ls", argv[1]) == 0) {
            if (argc > 2) {
                printf("ERROR: invalid parameter count for ls\n");
                return (1);
            }
            if ((curdir = opendir(".")) != NULL) {
                while ((dent = readdir(curdir)) != NULL) {
                    if (!stat(dent->d_name, &st)) {
                        if (S_ISDIR(st.st_mode)) {
                            printf("d %s\n", dent->d_name);
                        }
                        if (strlen(dent->d_name) > 4 && S_ISREG(st.st_mode)) {
                            if (!strcmp
                                    (dent->d_name + NAMLEN(dent) - 4, ".rrd")
                                    || !strcmp(dent->d_name + NAMLEN(dent) - 4,
                                               ".RRD")) {
                                printf("- %s\n", dent->d_name);
                            }
                        }
                    }
                }
                closedir(curdir);
            } else {
                printf("ERROR: opendir .: %s\n", rrd_strerror(errno));
                return (errno);
            }
            return (0);
        }
#endif                          /* opendir and readdir */

    }
    if (argc < 3
            || strcmp("help", argv[1]) == 0
            || strcmp("--help", argv[1]) == 0
            || strcmp("-help", argv[1]) == 0
            || strcmp("-?", argv[1]) == 0 || strcmp("-h", argv[1]) == 0) {
        PrintUsage("");
        return 0;
    }

    if (strcmp("create", argv[1]) == 0)
        rrd_create(argc - 1, &argv[1]);
    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) {
        rrd_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]);
        rrd_info_print(data);
        rrd_info_free(data);
    }

    else if (strcmp("--version", argv[1]) == 0 ||
             strcmp("version", argv[1]) == 0 ||
             strcmp("v", argv[1]) == 0 ||
             strcmp("-v", argv[1]) == 0 || strcmp("-version", argv[1]) == 0)
        printf("RRDtool " PACKAGE_VERSION
               "  Copyright by Tobi Oetiker, 1997-2008 (%f)\n",
               rrd_version());
    else if (strcmp("restore", argv[1]) == 0)
        rrd_restore(argc - 1, &argv[1]);
    else if (strcmp("resize", argv[1]) == 0)
        rrd_resize(argc - 1, &argv[1]);
    else if (strcmp("last", argv[1]) == 0)
        printf("%ld\n", rrd_last(argc - 1, &argv[1]));
    else if (strcmp("lastupdate", argv[1]) == 0) {
        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)
        rrd_update(argc - 1, &argv[1]);
    else if (strcmp("fetch", argv[1]) == 0) {
        time_t    start, end, ti;
        unsigned long step, ds_cnt, i, ii;
        rrd_value_t *data, *datai;
        char    **ds_namv;

        if (rrd_fetch
                (argc - 1, &argv[1], &start, &end, &step, &ds_cnt, &ds_namv,
                 &data) != -1) {
            datai = data;
            printf("           ");
            for (i = 0; i < ds_cnt; i++)
                printf("%20s", ds_namv[i]);
            printf("\n\n");
            for (ti = start + step; ti <= end; ti += step) {
                printf("%10lu:", ti);
                for (ii = 0; ii < ds_cnt; ii++)
                    printf(" %0.10e", *(datai++));
                printf("\n");
            }
            for (i = 0; i < ds_cnt; i++)
                free(ds_namv[i]);
            free(ds_namv);
            free(data);
        }
    } else if (strcmp("xport", argv[1]) == 0) {
        int       xxsize;
        unsigned long int j = 0;
        time_t    start, end, ti;
        unsigned long step, col_cnt, row_cnt;
        rrd_value_t *data, *ptr;
        char    **legend_v;
        int       enumds = 0;
        int       i;
        size_t    vtag_s = strlen(COL_DATA_TAG) + 10;
        char     *vtag = malloc(vtag_s);

        for (i = 2; i < argc; i++) {
            if (strcmp("--enumds", argv[i]) == 0)
                enumds = 1;
        }

        if (rrd_xport
                (argc - 1, &argv[1], &xxsize, &start, &end, &step, &col_cnt,
                 &legend_v, &data) != -1) {
            char *old_locale = setlocale(LC_NUMERIC, "C");
            row_cnt = (end - start) / step;
            ptr = data;
            printf("<?xml version=\"1.0\" encoding=\"%s\"?>\n\n",
                   XML_ENCODING);
            printf("<%s>\n", ROOT_TAG);
            printf("  <%s>\n", META_TAG);
            printf("    <%s>%lld</%s>\n", META_START_TAG,
                   (long long int) start + step, META_START_TAG);
            printf("    <%s>%lu</%s>\n", META_STEP_TAG, step, META_STEP_TAG);
            printf("    <%s>%lld</%s>\n", META_END_TAG, (long long int) end,
                   META_END_TAG);
            printf("    <%s>%lu</%s>\n", META_ROWS_TAG, row_cnt,
                   META_ROWS_TAG);
            printf("    <%s>%lu</%s>\n", META_COLS_TAG, col_cnt,
                   META_COLS_TAG);
            printf("    <%s>\n", LEGEND_TAG);
            for (j = 0; j < col_cnt; j++) {
                char     *entry = NULL;

                entry = legend_v[j];
                printf("      <%s>%s</%s>\n", LEGEND_ENTRY_TAG, entry,
                       LEGEND_ENTRY_TAG);
                free(entry);
            }
            free(legend_v);
            printf("    </%s>\n", LEGEND_TAG);
            printf("  </%s>\n", META_TAG);
            printf("  <%s>\n", DATA_TAG);
            for (ti = start + step; ti <= end; ti += step) {
                printf("    <%s>", DATA_ROW_TAG);
                printf("<%s>%lld</%s>", COL_TIME_TAG, (long long int)ti, COL_TIME_TAG);
                for (j = 0; j < col_cnt; j++) {
                    rrd_value_t newval = DNAN;

                    if (enumds == 1)

                        snprintf(vtag, vtag_s, "%s%lu", COL_DATA_TAG, j);
                    else
                        snprintf(vtag, vtag_s, "%s", COL_DATA_TAG);
                    newval = *ptr;
                    if (isnan(newval)) {
                        printf("<%s>NaN</%s>", vtag, vtag);
                    } else {
                        printf("<%s>%0.10e</%s>", vtag, newval, vtag);
                    };
                    ptr++;
                }
                printf("</%s>\n", DATA_ROW_TAG);
            }
            free(data);
            printf("  </%s>\n", DATA_TAG);
            printf("</%s>\n", ROOT_TAG);
            setlocale(LC_NUMERIC, old_locale);
        }
        free(vtag);
    } else if (strcmp("graph", argv[1]) == 0) {
        char    **calcpr;

#ifdef notused /*XXX*/
        const char *imgfile = argv[2];  /* rrd_graph changes argv pointer */
#endif
        int       xsize, ysize;
        double    ymin, ymax;
        int       i;
        int       tostdout = (strcmp(argv[2], "-") == 0);
        int       imginfo = 0;

        for (i = 2; i < argc; i++) {
            if (strcmp(argv[i], "--imginfo") == 0
                    || strcmp(argv[i], "-f") == 0) {
                imginfo = 1;
                break;
            }
        }
        if (rrd_graph
                (argc - 1, &argv[1], &calcpr, &xsize, &ysize, NULL, &ymin,
                 &ymax) != -1) {
            if (!tostdout && !imginfo)
                printf("%dx%d\n", xsize, ysize);
            if (calcpr) {
                for (i = 0; calcpr[i]; i++) {
                    if (!tostdout)
                        printf("%s\n", calcpr[i]);
                    free(calcpr[i]);
                }
                free(calcpr);
            }
        }

    } else if (strcmp("graphv", argv[1]) == 0) {
        rrd_info_t *grinfo = NULL;  /* 1 to distinguish it from the NULL that rrd_graph sends in */

        grinfo = rrd_graph_v(argc - 1, &argv[1]);
        if (grinfo) {
            rrd_info_print(grinfo);
            rrd_info_free(grinfo);
        }

    } else if (strcmp("tune", argv[1]) == 0)
        rrd_tune(argc - 1, &argv[1]);
    else if (strcmp("flushcached", argv[1]) == 0)
        rrd_flushcached(argc - 1, &argv[1]);
    else {
        rrd_set_error("unknown function '%s'", argv[1]);
    }
    if (rrd_test_error()) {
        fprintf(out, "ERROR: %s\n", rrd_get_error());
        rrd_clear_error();
        return 1;
    }
    return (0);
}