prep for 1.2rc9 release
[rrdtool.git] / src / rrd_cgi.c
index 5a47dc2..6f59358 100644 (file)
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * RRDtool 1.1.x  Copyright Tobias Oetiker, 1997 - 2004
+ * RRDtool 1.2rc9  Copyright by Tobi Oetiker, 1997-2005
  *****************************************************************************
  * rrd_cgi.c  RRD Web Page Generator
  *****************************************************************************/
 #define DEBUG_VARS*/
 
 /* global variable for libcgi */
-s_cgi **cgiArg;
+s_cgi *cgiArg;
 
 /* in arg[0] find tags beginning with arg[1] call arg[2] on them
    and replace by result of arg[2] call */
-int parse(char **, long, char *, char *(*)(long , char **));
+int parse(char **, long, char *, char *(*)(long , const char **));
 
 /**************************************************/
 /* tag replacers ... they are called from parse   */
@@ -26,43 +26,43 @@ int parse(char **, long, char *, char *(*)(long , char **));
 /**************************************************/
 
 /* return cgi var named arg[0] */ 
-char* cgiget(long , char **);
+char* cgiget(long , const char **);
 
 /* return a quoted cgi var named arg[0] */ 
-char* cgigetq(long , char **);
+char* cgigetq(long , const char **);
 
 /* return a quoted and sanitized cgi variable */
-char* cgigetqp(long , char **);
+char* cgigetqp(long , const char **);
 
 /* call rrd_graph and insert appropriate image tag */
 char* drawgraph(long, char **);
 
 /* return PRINT functions from last rrd_graph call */
-char* drawprint(long, char **);
+char* drawprint(long, const char **);
 
 /* pretty-print the <last></last> value for some.rrd via strftime() */
-char* printtimelast(long, char **);
+char* printtimelast(long, const char **);
 
 /* pretty-print current time */
-char* printtimenow(long,char **);
+char* printtimenow(long, const char **);
 
 /* set an environment variable */
-char* rrdsetenv(long, char **);
+char* rrdsetenv(long, const char **);
 
 /* get an environment variable */
-char* rrdgetenv(long, char **);
+char* rrdgetenv(long, const char **);
 
 /* include the named file at this point */
-char* includefile(long, char **);
+char* includefile(long, const char **);
 
 /* for how long is the output of the cgi valid ? */
-char* rrdgoodfor(long, char **);
+char* rrdgoodfor(long, const char **);
 
 char* rrdstrip(char *buf);
 char* scanargs(char *line, int *argc, char ***args);
 
 /* format at-time specified times using strftime */
-char* printstrftime(long, char**);
+char* printstrftime(long, const char**);
 
 /** HTTP protocol needs special format, and GMT time **/
 char *http_time(time_t *);
@@ -72,9 +72,9 @@ char *stralloc(const char *);
 
 
 /* rrd interface to the variable functions {put,get}var() */
-char* rrdgetvar(long argc, char **args);
-char* rrdsetvar(long argc, char **args);
-char* rrdsetvarconst(long argc, char **args);
+char* rrdgetvar(long argc, const char **args);
+char* rrdsetvar(long argc, const char **args);
+char* rrdsetvarconst(long argc, const char **args);
 
 
 /* variable store: put/get key-value pairs */
@@ -117,7 +117,7 @@ donevar()
 {
        int i;
        if (varheap) {
-               for (i=0; i<varheap_size; i++) {
+               for (i=0; i<(int)varheap_size; i++) {
                        if (varheap[i].name) {
                                free((char*)varheap[i].name);
                        }
@@ -135,7 +135,7 @@ static const char*
 getvar(const char* name)
 {
        int i;
-       for (i=0; i<varheap_size && varheap[i].name; i++) {
+       for (i=0; i<(int)varheap_size && varheap[i].name; i++) {
                if (0 == strcmp(name, varheap[i].name)) {
 #ifdef         DEBUG_VARS
                        printf("<!-- getvar(%s) -> %s -->\n", name, varheap[i].value);
@@ -157,7 +157,7 @@ static const char*
 putvar(const char* name, const char* value, int is_const)
 {
        int i;
-       for (i=0; i < varheap_size && varheap[i].name; i++) {
+       for (i=0; i < (int)varheap_size && varheap[i].name; i++) {
                if (0 == strcmp(name, varheap[i].name)) {
                        /* overwrite existing entry */
                        if (varheap[i].is_const) {
@@ -180,7 +180,7 @@ putvar(const char* name, const char* value, int is_const)
        }
 
        /* no existing variable found by that name, add it */
-       if (i == varheap_size) {
+       if (i == (int)varheap_size) {
                /* ran out of heap: resize heap to double size */
                size_t new_size = varheap_size * 2;
                varheap = (vardata*)(realloc(varheap, sizeof(vardata) * new_size));
@@ -220,6 +220,9 @@ rrd_expand_vars(char* buffer)
                parse(&buffer, i, "<RRD::CV::PATH", cgigetqp);
                parse(&buffer, i, "<RRD::GETENV", rrdgetenv);    
                parse(&buffer, i, "<RRD::GETVAR", rrdgetvar);    
+                parse(&buffer, i, "<RRD::TIME::LAST", printtimelast);
+                parse(&buffer, i, "<RRD::TIME::NOW", printtimenow);
+                parse(&buffer, i, "<RRD::TIME::STRFTIME", printstrftime);
        }
        return buffer;
 }
@@ -316,6 +319,12 @@ int main(int argc, char *argv[]) {
        /* initialize variable heap */
        initvar();
 
+#ifdef DEBUG_PARSER
+       /* some fake header for testing */
+       printf ("Content-Type: text/html\nContent-Length: 10000000\n\n\n");
+#endif
+
+
        /* expand rrd directives in buffer recursivly */
        for (i=0; buffer[i]; i++) {
                if (buffer[i] != '<')
@@ -372,7 +381,7 @@ int main(int argc, char *argv[]) {
 /* remove occurrences of .. this is a general measure to make
    paths which came in via cgi do not go UP ... */
 
-char* rrdsetenv(long argc, char **args) {
+char* rrdsetenv(long argc, const char **args) {
        if (argc >= 2) {
                char *xyz = malloc((strlen(args[0]) + strlen(args[1]) + 2));
                if (xyz == NULL) {
@@ -383,6 +392,7 @@ char* rrdsetenv(long argc, char **args) {
                        free(xyz);
                        return stralloc("[ERROR: failed to do putenv]");
                };
+               return stralloc("");
        }
        return stralloc("[ERROR: setenv failed because not enough "
                                        "arguments were defined]");
@@ -390,7 +400,7 @@ char* rrdsetenv(long argc, char **args) {
 
 /* rrd interface to the variable function putvar() */
 char*
-rrdsetvar(long argc, char **args)
+rrdsetvar(long argc, const char **args)
 {
        if (argc >= 2)
        {
@@ -407,7 +417,7 @@ rrdsetvar(long argc, char **args)
 
 /* rrd interface to the variable function putvar() */
 char*
-rrdsetvarconst(long argc, char **args)
+rrdsetvarconst(long argc, const char **args)
 {
        if (argc >= 2)
        {
@@ -422,7 +432,7 @@ rrdsetvarconst(long argc, char **args)
                                        "were defined]");
 }
 
-char* rrdgetenv(long argc, char **args) {
+char* rrdgetenv(long argc, const char **args) {
        char buf[128];
        const char* envvar;
        if (argc != 1) {
@@ -433,12 +443,16 @@ char* rrdgetenv(long argc, char **args) {
        if (envvar) {
                return stralloc(envvar);
        } else {
-               snprintf(buf, sizeof(buf), "[ERROR:_getenv_'%s'_failed", args[0]);
-               return stralloc(buf);
+#if defined(WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
+               _snprintf(buf, sizeof(buf), "[ERROR:_getenv_'%s'_failed", args[0]);
+#else
+                snprintf(buf, sizeof(buf), "[ERROR:_getenv_'%s'_failed", args[0]);
+#endif         
+                return stralloc(buf);
        }
 }
 
-char* rrdgetvar(long argc, char **args) {
+char* rrdgetvar(long argc, const char **args) {
        char buf[128];
        const char* value;
        if (argc != 1) {
@@ -449,12 +463,16 @@ char* rrdgetvar(long argc, char **args) {
        if (value) {
                return stralloc(value);
        } else {
-               snprintf(buf, sizeof(buf), "[ERROR:_getvar_'%s'_failed", args[0]);
+#if defined(WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
+               _snprintf(buf, sizeof(buf), "[ERROR:_getvar_'%s'_failed", args[0]);
+#else
+                snprintf(buf, sizeof(buf), "[ERROR:_getvar_'%s'_failed", args[0]);
+#endif
                return stralloc(buf);
        }
 }
 
-char* rrdgoodfor(long argc, char **args){
+char* rrdgoodfor(long argc, const char **args){
   if (argc == 1) {
       goodfor = atol(args[0]);
   } else {
@@ -472,7 +490,7 @@ char* rrdgoodfor(long argc, char **args){
  * start and end times, because, either might be relative to the other.
  * */
 #define MAX_STRFTIME_SIZE 256
-char* printstrftime(long argc, char **args){
+char* printstrftime(long argc, const char **args){
        struct  rrd_time_value start_tv, end_tv;
        char    *parsetime_error = NULL;
        char    formatted[MAX_STRFTIME_SIZE];
@@ -524,10 +542,10 @@ char* printstrftime(long argc, char **args){
        }
 }
 
-char* includefile(long argc, char **args){
+char* includefile(long argc, const char **args){
   char *buffer;
   if (argc >= 1) {
-         char* filename = args[0];
+      char* filename = args[0];
       readfile(filename, &buffer, 0);
       if (rrd_test_error()) {
                char *err = malloc((strlen(rrd_get_error())+DS_NAM_SIZE));
@@ -566,7 +584,7 @@ char* rrdstrip(char *buf) {
   return buf;
 }
 
-char* cgigetq(long argc, char **args){
+char* cgigetq(long argc, const char **args){
   if (argc>= 1){
     char *buf = rrdstrip(cgiGetValue(cgiArg,args[0]));
     char *buf2;
@@ -604,60 +622,63 @@ char* cgigetq(long argc, char **args){
 /* remove occurrences of .. this is a general measure to make
    paths which came in via cgi do not go UP ... */
 
-char* cgigetqp(long argc, char **args){
-  if (argc>= 1) {
-    char *buf = rrdstrip(cgiGetValue(cgiArg,args[0]));
-    char *buf2;
-    char *c,*d;
-    int  qc=0;
-
-    if (buf==NULL) 
-               return NULL;
-
-    for(c=buf;*c != '\0';c++) {
-       if (*c == '"') {
-                       qc++;
-               }
-       }
-
-    if ((buf2 = malloc((strlen(buf) + 4 * qc + 4))) == NULL) {
-               perror("Malloc Buffer");
-               exit(1);
+char* cgigetqp(long argc, const char **args){
+       char* buf;
+    char* buf2;
+    char* p;
+        char* d;
+
+        if (argc < 1)
+        {
+                return stralloc("[ERROR: not enough arguments for RRD::CV::PATH]");
+        }
+
+        buf = rrdstrip(cgiGetValue(cgiArg, args[0]));
+    if (!buf)
+        {
+                return NULL;
+        }
+
+        buf2 = malloc(strlen(buf)+1);
+    if (!buf2)
+        {
+                perror("cgigetqp(): Malloc Path Buffer");
+                exit(1);
     };
 
-    c=buf;
-    d=buf2;
-
-    *(d++) = '"';
-    while (*c != '\0') {
-               if (*c == '"') {
-                       *(d++) = '"';
-                       *(d++) = '\'';
-                       *(d++) = '"';
-                       *(d++) = '\'';
-               }
-               if(*c == '/') {
-                       *(d++) = '_';
-                       c++;
-               } else {
-                       if (*c=='.' && *(c+1) == '.') {
-                               c += 2;
-                               *(d++) = '_'; *(d++) ='_';      
-                       } else {
-                               *(d++) = *(c++);
-                       }
-               }
+    p = buf;
+    d = buf2;
+
+    while (*p)
+        {
+                /* prevent mallicious paths from entering the system */
+                if (p[0] == '.' && p[1] == '.')
+                {
+                        p += 2;
+                        *d++ = '_';
+                        *d++ = '_';     
+                }
+                else
+                {
+                        *d++ = *p++;
+                }
     }
-    *(d++) = '"';
-    *(d) = '\0';
+
+    *d = 0;
     free(buf);
+
+    /* Make sure the path is relative, e.g. does not start with '/' */
+    p = buf2;
+    while ('/' == *p)
+        {
+            *p++ = '_';
+    }
+
     return buf2;
-  }
-  return stralloc("[ERROR: not enough arguments for RRD::CV::PATH]");
 }
 
 
-char* cgiget(long argc, char **args){
+char* cgiget(long argc, const char **args){
   if (argc>= 1)
     return rrdstrip(cgiGetValue(cgiArg,args[0]));
   else
@@ -668,6 +689,7 @@ char* cgiget(long argc, char **args){
 
 char* drawgraph(long argc, char **args){
   int i,xsize, ysize;
+  double ymin,ymax;
   for(i=0;i<argc;i++)
     if(strcmp(args[i],"--imginfo")==0 || strcmp(args[i],"-g")==0) break;
   if(i==argc) {
@@ -677,7 +699,7 @@ char* drawgraph(long argc, char **args){
   optind=0; /* reset gnu getopt */
   opterr=0; /* reset gnu getopt */
   calfree();
-  if( rrd_graph(argc+1, args-1, &calcpr, &xsize, &ysize,NULL) != -1 ) {
+  if( rrd_graph(argc+1, args-1, &calcpr, &xsize, &ysize,NULL,&ymin,&ymax) != -1 ) {
     return stralloc(calcpr[0]);
   } else {
     if (rrd_test_error()) {
@@ -691,7 +713,7 @@ char* drawgraph(long argc, char **args){
   return NULL;
 }
 
-char* drawprint(long argc, char **args){
+char* drawprint(long argc, const char **args){
   if (argc==1 && calcpr){
     long i=0;
     while (calcpr[i] != NULL) i++; /*determine number lines in calcpr*/
@@ -701,7 +723,7 @@ char* drawprint(long argc, char **args){
   return stralloc("[ERROR: RRD::PRINT argument error]");
 }
 
-char* printtimelast(long argc, char **args) {
+char* printtimelast(long argc, const char **args) {
   time_t last;
   struct tm tm_last;
   char *buf;
@@ -727,7 +749,7 @@ char* printtimelast(long argc, char **args) {
   return stralloc("[ERROR: not enough arguments for RRD::TIME::LAST]");
 }
 
-char* printtimenow(long argc, char **args) {
+char* printtimenow(long argc, const char **args) {
   time_t now = time(NULL);
   struct tm tm_now;
   char *buf;
@@ -817,7 +839,7 @@ scanargs(char *line, int *argument_count, char ***arguments)
                {
                case ' ': 
                        if (Quote || tagcount) {
-                               /* copy quoted/tagged string */
+                               /* copy quoted/tagged (=RRD expanded) string */
                                *putP++ = c;
                        }
                        else if (in_arg)
@@ -843,7 +865,7 @@ scanargs(char *line, int *argument_count, char ***arguments)
                                }
                        } else {
                                if (!in_arg) {
-                                       /* reference argument string in argument array */
+                                       /* reference start of argument string in argument array */
                                        argv[argc++] = putP;
                                        in_arg=1;
                                }
@@ -852,7 +874,6 @@ scanargs(char *line, int *argument_count, char ***arguments)
                        break;
 
                default:
-                       if (!Quote) {
                                if (!in_arg) {
                                        /* start new argument */
                                        argv[argc++] = putP;
@@ -869,7 +890,6 @@ scanargs(char *line, int *argument_count, char ***arguments)
                                                curarg_contains_rrd_directives = 1;
                                        }
                                }
-                       }
                        *putP++ = c;
                        break;
                }
@@ -929,7 +949,7 @@ parse(
        char **buf,     /* buffer */
        long i,                 /* offset in buffer */
        char *tag,      /* tag to handle  */
-       char *(*func)(long argc, char **args) /* function to call for 'tag' */
+       char *(*func)(long , const char **) /* function to call for 'tag' */
        )
 {
        /* the name of the vairable ... */