I've been struggling with this for a week now and am hoping someone can point 
out what I am doing wrong.  
I'm sure its just a really silly bug in my code, but I can't seem to find it!   
I would really appreciate any help on this... I'm trying to create a utility 
library that I can call from other programs to manipulate rrd files.

Context:

- using Raspian on a Raspberry Pi
  - Linux raspberryospi 3.12.20+ #686 PREEMPT Tue May 27 15:48:33 BST 2014 
armv6l GNU/Linux
- installed rrdtool using apt-get
  - RRDtool 1.4.7  Copyright 1997-2012 by Tobias Oetiker <[email protected]>
               Compiled Sep  4 2012 23:43:06
- using rrdtool to graph cpu temperatures
- works fine using the command line tools from a shell script
- same calls cause rrd file to be corrupted after rrdupdate() command

Here's the working shell script, called every 5 minutes via cron:

-------------
#!/bin/bash
#
# update .rrd database with CPU temperature
#
# This sets up an RRD called temperature.rrd which accepts one temperature 
value every 300
# seconds. If no new data is supplied for more than 1200 seconds, the 
temperature becomes
# *UNKNOWN*.  The minimum and maximum acceptable values are Undefined (U)
#
# A few archive areas are also defined. The first stores the temperatures 
supplied for 100
# hours (1'200 * 300 seconds = 100 hours). The second RRA stores the minimum 
temperature
# recorded over every hour (12 * 300 seconds = 1 hour), for 100 days (2'400 
hours). The third
# and the fourth RRA's do the same for the maximum and average temperature, 
respectively.
# 
INTERVAL=300
# This script is designed to be called from CRON every INTERVALseconds

PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
export PATH

cd /home/pi/temperature
# create rrd database if not exists
[ -f cputemp.rrd ] || { rrdtool create cputemp.rrd --step $INTERVAL \
DS:cputemp:GAUGE:1200:U:U \
RRA:AVERAGE:0.5:1:1200 \
RRA:MIN:0.5:12:2400 \
RRA:MAX:0.5:12:2400 \
RRA:AVERAGE:0.5:12:2400
}

# read the temperature and convert “59234″ into “59.234″ (degrees celsius)
TEMPERATURE=`cat /sys/class/thermal/thermal_zone0/temp`
TEMPERATURE=`echo -n ${TEMPERATURE:0:2}; echo -n .; echo -n ${TEMPERATURE:2}`
rrdtool update cputemp.rrd `date +%s`:$TEMPERATURE
rrdtool graph cputemp.png DEF:temp=cputemp.rrd:cputemp:AVERAGE 
LINE2:temp#00FF00 --width 800 --start end-4d --end 00:00 >/dev/null 2>&1

-------------

the above works just fine.

Now, here's my C program, which successfully creates the rrd file.  I changed 
the interval to 20 seconds so its easier to test.

The problem is that after the first rrd_upate(), which returns OK, the rrd file 
is corrupted, which causes the next rrd_update() to fail.
The rrd_create() is working OK: If i comment out the rrd_update(), and run 
"rrdtool info" on the rrd file, its fine.

What am i doing wrong??  

-------------

#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <rrd.h> 
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

#include "rrdutil.h"

int initRRD(char *rrdfile) {

    char *createparams[] = {
        "rrdcreate",
        rrdfile,
        "--step",
        "20",
        "DS:cputemp:GAUGE:1200:U:U",
        "RRA:AVERAGE:0.5:1:1200",
        "RRA:MIN:0.5:12:2400",
        "RRA:MAX:0.5:12:2400",
        "RRA:AVERAGE:0.5:12:2400",
        NULL
    };

    struct stat sb;

    /* if rrd database file does not exist, then create it */
    if (stat(rrdfile, &sb) == -1) {
        optind = opterr = 0; /* Because rrdtool uses getopt() */
        rrd_clear_error();
        rrd_create(9, createparams);
        if (rrd_test_error() != 0) {
            fprintf(stderr, "rrd_create() failed\n");
            return(1);
        }
        printf("created rrd database: %s\n", rrdfile);
    }
    else {
        fprintf(stderr, "rrd file %s already exists\n", rrdfile);
    }


    return(0);

};

int updateRRD(char *rrdfile, char *value) {

    /* construct time string as secs since 1/1/1970 */
    char timestr[30];
    time_t t;
    struct tm *ttm;

    t = time(NULL);
    ttm = localtime(&t);
    strftime(timestr, sizeof(timestr), "%s", ttm);

    char tbuf[30];
    /* rrd needs "time-in-secs:value */
    sprintf(tbuf, "%s:%s", timestr, value);

    printf("updating %s with %s\n", rrdfile, tbuf);

    char *updateparams[] = {
       "rrdupdate",
       rrdfile,
       tbuf,
       NULL
    };

    /* update the rrd database with the new reading */
    optind = opterr = 0;
    rrd_clear_error();
    rrd_update(3, updateparams);
    if (rrd_test_error() != 0) {
        fprintf(stderr, "rrd_update(%s, %s) failed with %s\n", rrdfile, tbuf, 
rrd_get_error());
        return(1);
        }

    /* graph the results */
    char **calcpr  = NULL;
    int rrdargcount, xsize, ysize, result;
    double ymin, ymax;
    char def[100];

    sprintf(def, "DEF:temp=%s:cputemp:AVERAGE", rrdfile);

     char *rrdgraphargs[] = {
        "rrdgraph",
        rrdfile,
        def,
        "LINE2:temp#00FF00",
        "--width",
        "800",
        "--start",
        "end-4d",
        "--end",
        "00:00",
        NULL
    };

    optind = opterr = 0;
    rrd_clear_error();
    result = rrd_graph(10, rrdgraphargs, &calcpr, &xsize, &ysize, NULL, &ymin, 
&ymax);

    /* Was it OK ? */
    if (rrd_test_error() || (result != 0)) {
        if (calcpr) {
            int i;
            for (i=0; (calcpr[i]); i++) free(calcpr[i]);
            calcpr = NULL;
        }

        fprintf(stderr,"Graph error: %s\n", rrd_get_error());
        return(2);
    }

    return(0);

};

#ifdef TEST
extern char *optarg;
extern int optind, opterr, optopt;

int main(int argc, char **argv) {

    if (argc != 2) {
        fprintf(stderr, "usage: %s <rrd file path>\n", argv[0]);
        return(1);
    }

    char rrdfile[100];
    strncpy(rrdfile, argv[1], sizeof(rrdfile));

    if (initRRD(rrdfile) != 0)
        return(2);

    /* temperature returned as 5 digits, centigrade, no decimal */
    int fd = open("/sys/class/thermal/thermal_zone0/temp", O_RDONLY);
    if (fd < 0) {
        fprintf(stderr, "open() of cpu temperature file failed\n");
        return(3);
    }

    /* optimistic */
    char temp[10];
    (void) read(fd, temp, sizeof(temp));
    (void) close(fd);

    char tempstr[10];

    strncpy(tempstr, temp, 2);
    tempstr[2]= '.';
    strncpy(&tempstr[3], &temp[2], 3);
    tempstr[6] = 0;

    if (updateRRD(rrdfile, tempstr) != 0)
        return(4);

    return(0);
}
#endif

----------

Makefile:

rrdutil:        rrdutil.cpp rrdutil.h
        gcc -Wno-write-strings -o rrdutil -DTEST -l :librrd.so.4 rrdutil.cpp

clean:
        rm -f rrdutil

----------------

here's the output:

pi@raspberryospi ~/temperature $ ./rrdutil fee.rrd
created rrd database: fee.rrd
updating fee.rrd with 1401552682:55.148
pi@raspberryospi ~/temperature $ ./rrdutil fee.rrd
rrd file fee.rrd already exists
updating fee.rrd with 1401552704:55.686
rrd_update(fee.rrd, 1401552704:55.686) failed with 'fee.rrd' is not an RRD file

---------


_______________________________________________
rrd-users mailing list
[email protected]
https://lists.oetiker.ch/cgi-bin/listinfo/rrd-users

Reply via email to