1 /*****************************************************************************
2 * RRDtool 1.0.33 Copyright Tobias Oetiker, 1997 - 2000
3 *****************************************************************************
4 * rrd_cgi.c RRD Web Page Generator
5 *****************************************************************************/
14 /* global variable for libcgi */
17 /* in arg[0] find tags beginning with arg[1] call arg[2] on them
18 and replace by result of arg[2] call */
19 int parse(char **, long, char *, char *(*)(long , char **));
21 /**************************************************/
22 /* tag replacers ... they are called from parse */
23 /* through function pointers */
24 /**************************************************/
26 /* return cgi var named arg[0] */
27 char* cgiget(long , char **);
29 /* return a quoted cgi var named arg[0] */
30 char* cgigetq(long , char **);
32 /* return a quoted and sanitized cgi variable */
33 char* cgigetqp(long , char **);
35 /* call rrd_graph and insert apropriate image tag */
36 char* drawgraph(long, char **);
38 /* return PRINT functions from last rrd_graph call */
39 char* drawprint(long, char **);
41 /* pretty-print the <last></last> value for some.rrd via strftime() */
42 char* printtimelast(long, char **);
44 /* pretty-print current time */
45 char* printtimenow(long,char **);
47 /* set an evironment variable */
48 char* rrdsetenv(long, char **);
50 /* get an evironment variable */
51 char* rrdgetenv(long, char **);
53 /* include the named file at this point */
54 char* includefile(long, char **);
56 /* for how long is the output of the cgi valid ? */
57 char* rrdgoodfor(long, char **);
59 /** http protocol needs special format, and GMT time **/
60 char *http_time(time_t *);
62 /* return a pointer to newly alocated copy of this string */
63 char *stralloc(char *);
65 static long goodfor=0;
66 static char **calcpr=NULL;
67 static void calfree (void){
70 for(i=0;calcpr[i];i++){
81 /* create freeable version of the string */
82 char * stralloc(char *str){
83 char *nstr = malloc((strlen(str)+1)*sizeof(char));
88 int main(int argc, char *argv[]) {
91 char *server_url = NULL;
94 #ifdef MUST_DISABLE_SIGFPE
95 signal(SIGFPE,SIG_IGN);
97 #ifdef MUST_DISABLE_FPMASK
100 /* what do we get for cmdline arguments?
102 printf("%d-'%s'\n",i,argv[i]); */
104 static struct option long_options[] =
106 {"filter", no_argument, 0, 'f'},
109 int option_index = 0;
111 opt = getopt_long(argc, argv, "f",
112 long_options, &option_index);
120 printf("unknown commandline option '%s'\n",argv[optind-1]);
128 server_url = getenv("SERVER_URL");
131 if (optind != argc-1) {
132 fprintf(stderr, "ERROR: expected a filename\n");
135 length = readfile(argv[optind], &buffer, 1);
138 if(rrd_test_error()){
139 fprintf(stderr, "ERROR: %s\n",rrd_get_error());
145 /* pass 1 makes only sense in cgi mode */
146 for (i=0;buffer[i] != '\0'; i++){
147 i +=parse(&buffer,i,"<RRD::CV",cgiget);
148 i +=parse(&buffer,i,"<RRD::CV::QUOTE",cgigetq);
149 i +=parse(&buffer,i,"<RRD::CV::PATH",cgigetqp);
150 i +=parse(&buffer,i,"<RRD::GETENV",rrdgetenv);
155 for (i=0;buffer[i] != '\0'; i++){
156 i += parse(&buffer,i,"<RRD::GOODFOR",rrdgoodfor);
157 i += parse(&buffer,i,"<RRD::SETENV",rrdsetenv);
158 i += parse(&buffer,i,"<RRD::INCLUDE",includefile);
159 i += parse(&buffer,i,"<RRD::TIME::LAST",printtimelast);
160 i += parse(&buffer,i,"<RRD::TIME::NOW",printtimenow);
164 for (i=0;buffer[i] != '\0'; i++){
165 i += parse(&buffer,i,"<RRD::GRAPH",drawgraph);
166 i += parse(&buffer,i,"<RRD::PRINT",drawprint);
170 printf ("Content-Type: text/html\n"
171 "Content-Length: %d\n", strlen(buffer));
172 if (labs(goodfor) > 0){
175 printf ("Last-Modified: %s\n",http_time(&now));
176 now += labs(goodfor);
177 printf ("Expires: %s\n",http_time(&now));
179 printf("Refresh: %ld\n", labs(goodfor));
184 printf ("%s", buffer);
192 /* remove occurences of .. this is a general measure to make
193 paths which came in via cgi do not go UP ... */
195 char* rrdsetenv(long argc, char **args){
197 char *xyz=malloc((strlen(args[0])+strlen(args[1])+3)*sizeof(char));
199 return stralloc("[ERROR: allocating setenv buffer]");
201 sprintf(xyz,"%s=%s",args[0],args[1]);
202 if( putenv(xyz) == -1) {
203 return stralloc("[ERROR: faild to do putenv]");
206 return stralloc("[ERROR: setenv faild because not enough arguments were defined]");
211 char* rrdgetenv(long argc, char **args){
213 return stralloc("[ERROR: getenv faild because it did not get 1 argument only]");
215 return stralloc(getenv(args[0]));
218 char* rrdgoodfor(long argc, char **args){
220 goodfor = atol(args[0]);
222 return stralloc("[ERROR: goodfor expected 1 argument]");
226 return stralloc("[ERROR: goodfor value must not be 0]");
232 char* includefile(long argc, char **args){
235 readfile(args[0], &buffer, 0);
236 if (rrd_test_error()) {
237 char *err = malloc((strlen(rrd_get_error())+DS_NAM_SIZE)*sizeof(char));
238 sprintf(err, "[ERROR: %s]",rrd_get_error());
247 return stralloc("[ERROR: No Inclue file defined]");
251 char* rrdstrip(char *buf){
253 if (buf == NULL) return NULL;
254 buf = stralloc(buf); /* make a copy of the buffer */
255 if (buf == NULL) return NULL;
256 while ((start = strstr(buf,"<"))){
259 while ((start = strstr(buf,">"))){
265 char* cgigetq(long argc, char **args){
267 char *buf = rrdstrip(cgiGetValue(cgiArg,args[0]));
271 if (buf==NULL) return NULL;
273 for(c=buf;*c != '\0';c++)
275 if((buf2=malloc((strlen(buf) + qc*4 +4) * sizeof(char)))==NULL){
276 perror("Malloc Buffer");
297 return stralloc("[ERROR: not enough argument for RRD::CV::QUOTE]");
300 /* remove occurences of .. this is a general measure to make
301 paths which came in via cgi do not go UP ... */
303 char* cgigetqp(long argc, char **args){
305 char *buf = rrdstrip(cgiGetValue(cgiArg,args[0]));
309 if (buf==NULL) return NULL;
311 for(c=buf;*c != '\0';c++)
313 if((buf2=malloc((strlen(buf) + qc*4 +4) * sizeof(char)))==NULL){
314 perror("Malloc Buffer");
330 if (*c=='.' && *(c+1) == '.'){
332 *(d++) = '_'; *(d++) ='_';
345 return stralloc("[ERROR: not enough arguments for RRD::CV::PATH]");
350 char* cgiget(long argc, char **args){
352 return rrdstrip(cgiGetValue(cgiArg,args[0]));
354 return stralloc("[ERROR: not enough arguments for RRD::CV]");
359 char* drawgraph(long argc, char **args){
362 if(strcmp(args[i],"--imginfo")==0 || strcmp(args[i],"-g")==0) break;
364 args[argc++] = "--imginfo";
365 args[argc++] = "<IMG SRC=\"./%s\" WIDTH=\"%lu\" HEIGHT=\"%lu\">";
367 optind=0; /* reset gnu getopt */
368 opterr=0; /* reset gnu getopt */
370 if( rrd_graph(argc+1, args-1, &calcpr, &xsize, &ysize) != -1 ) {
371 return stralloc(calcpr[0]);
373 if (rrd_test_error()) {
374 char *err = malloc((strlen(rrd_get_error())+DS_NAM_SIZE)*sizeof(char));
375 sprintf(err, "[ERROR: %s]",rrd_get_error());
384 char* drawprint(long argc, char **args){
385 if (argc==1 && calcpr){
387 while (calcpr[i] != NULL) i++; /*determine number lines in calcpr*/
388 if (atol(args[0])<i-1)
389 return stralloc(calcpr[atol(args[0])+1]);
391 return stralloc("[ERROR: RRD::PRINT argument error]");
394 char* printtimelast(long argc, char **args) {
401 return stralloc("[ERROR: allocating strftime buffer]");
403 last = rrd_last(argc+1, args-1);
404 if (rrd_test_error()) {
405 char *err = malloc((strlen(rrd_get_error())+DS_NAM_SIZE)*sizeof(char));
406 sprintf(err, "[ERROR: %s]",rrd_get_error());
410 tm_last = *localtime(&last);
411 strftime(buf,254,args[1],&tm_last);
415 return stralloc("[ERROR: too few arguments for RRD::TIME::LAST]");
417 return stralloc("[ERROR: not enough arguments for RRD::TIME::LAST]");
420 char* printtimenow(long argc, char **args) {
421 time_t now = time(NULL);
427 return stralloc("[ERROR: allocating strftime buffer]");
429 tm_now = *localtime(&now);
430 strftime(buf,254,args[0],&tm_now);
434 return stralloc("[ERROR: too few arguments for RRD::TIME::NOW]");
436 return stralloc("[ERROR: not enough arguments for RRD::TIME::NOW]");
439 /* scan aLine until an unescaped '>' arives */
440 char* scanargs(char *aLine, long *argc, char ***args)
447 if (((*args) = (char **) malloc(MEMBLK*sizeof(char *))) == NULL) {
450 /* sikp leading blanks */
451 while (*aLine && *aLine <= ' ') aLine++;
456 while (*getP && !( !Quote && (braket == 0) && ((*getP) == '>'))){
457 if (*getP < ' ') *getP = ' '; /*remove all special chars*/
478 (*args)[++(*argc)] = putP;
485 if (Quote == 0 && (*getP) == '<') {
488 if (Quote == 0 && (*getP) == '>') {
493 (*args)[++(*argc)] = putP;
499 if ((*argc) >= argal-10 ) {
501 if (((*args)=rrd_realloc((*args),(argal)*sizeof(char *))) == NULL) {
513 return getP+1; /* pointer to next char after parameter */
518 int parse(char **buf, long i, char *tag,
519 char *(*func)(long argc, char **args)){
521 /* the name of the vairable ... */
528 /* do we like it ? */
529 if (strncmp((*buf)+i, tag, strlen(tag))!=0) return 0;
530 if (! isspace(*( (*buf) + i + strlen(tag) )) ) return 0;
531 /* scanargs puts \0 into *buf ... so after scanargs it is probably
532 not a good time to use strlen on buf */
533 end = scanargs((*buf)+i+strlen(tag),&argc,&args);
535 for (;argc>2;argc--){
536 *((args[argc-1])-1)=' ';
538 val = stralloc("[ERROR: Parsing Problem with the following text\n"
539 " Check original file. This may have been altered by parsing.]\n\n");
542 val = func(argc-1,args+1);
545 /* for (ii=0;ii<argc;ii++) printf("'%s'\n", args[ii]); */
550 /* make enough room for replacement */
551 end_offset = end - (*buf);
552 if(end-(*buf) < i + valln){ /* make sure we do not shrink the mallocd block */
553 /* calculating the new length of the buffer is simple. add current
554 buffer pos (i) to length of string after replaced tag to length
555 of replacement string and add 1 for the final zero ... */
556 if(((*buf) = rrd_realloc((*buf),
557 (i+strlen(end) + valln +1) * sizeof(char)))==NULL){
558 perror("Realoc buf:");
562 end = (*buf) + end_offset; /* make sure the 'end' pointer gets moved
563 along with the buf pointer when realoc
565 /* splice the variable */
566 memmove ((*buf)+i+valln,end,strlen(end)+1);
567 if (val != NULL ) memmove ((*buf)+i,val, valln);
568 if (val){ free(val);}
569 return valln > 0 ? valln-1: valln;
573 http_time(time_t *now) {
578 strftime(buf,sizeof(buf),"%a, %d %b %Y %H:%M:%S GMT",tmptime);