/* (C) 1998-2002 Red Hat, Inc. -- Licensing details are in the COPYING file accompanying popt source distributions, available from ftp://ftp.rpm.org/pub/rpm/dist. */ #include #include #include #include #include #include #include #include "../common/config-parser.h" static char* conf_directory = NULL; static char* work_directory = NULL; typedef struct _graph { const char* name; char* title; int width; int height; int interval; char* category; const char** options; const char** commands; struct _graph *next; } graph; static graph* allgraphs = NULL; /* ----------------------------------------------------------------------------- * CONFIG PARSING */ /* *argv should be freed with free() after use */ int parse_argv(const char* s, const char*** argvp) { #define GROW_DELTA 5 const char* src; char quote = '\0'; int alloced = GROW_DELTA; const char** argv = NULL; const char** argv2; const char** a; size_t nb; char* dst; int argc = 0; int buflen; char* buf; int i, r = 0; argv = malloc (sizeof (*argv) * alloced); if (!argv) { errno = ENOMEM; return -1; } buflen = strlen (s) + 1; buf = memset (alloca (buflen), 0, buflen); argv[argc] = buf; for (src = s; r == 0 && *src; src++) { if (quote == *src) { quote = '\0'; } else if (quote != '\0') { if (*src == '\\') { src++; if (!*src) { r = -1; errno = EINVAL; continue; } if (*src != quote) *buf++ = '\\'; } *buf++ = *src; } else if (isspace(*src)) { if (*argv[argc] != '\0') { buf++, argc++; if (argc == alloced) { alloced += GROW_DELTA; a = realloc (argv, sizeof(*argv) * alloced); if (!a) { r = -1; errno = ENOMEM; continue; } argv = a; } argv[argc] = buf; } } else { switch (*src) { case '"': case '\'': quote = *src; break; case '\\': src++; if (!*src) { r = -1; errno = EINVAL; continue; } default: *buf++ = *src; break; } } } /* Reallocate the whole thing as one block of memory */ if (r == 0) { if (strlen(argv[argc])) argc++; nb = (argc + 1) * sizeof(*argv); for (i = 0; i < argc; i++) { if (argv[i] != NULL) nb += strlen(argv[i]) + 1; } dst = malloc (nb); if (dst == NULL) { free(argv); errno = ENOMEM; return -1; } argv2 = (void *) dst; dst += (argc + 1) * sizeof(*argv); for (i = 0; i < argc; i++) { if (argv[i] == NULL) continue; argv2[i] = dst; dst += strlen(strcpy(dst, argv[i])) + 1; } argv2[argc] = NULL; if (argvp) { *argvp = argv2; } else { free(argv2); argv2 = NULL; } r = 0; } free(argv); return r; } int cfg_value(const char* filename, const char* header, const char* name, char* value, void* data) { static graph* gr = NULL; /* called like this after ever file */ if (!header) { /* add to the list */ gr->next = allgraphs; allgraphs = gr; gr = NULL; return 0; } if (gr == NULL) { gr = calloc(1, sizeof(graph)); if (!gr) err(1, "Out of memory"); gr->name = filename; gr->category = ""; } if (strcmp(header, "general") == 0) { if (strcmp(name, "title") == 0) gr->title = value; else if (strcmp(name, "category") == 0) gr->category = value; } else if (strcmp(header, "graph") == 0) { if (strcmp(name, "height") == 0) gr->height = atoi(value); else if (strcmp(name, "width") == 0) gr->width = atoi(value); else if (strcmp(name, "options") == 0) { if (parse_argv(value, &gr->options) != 0) errx(2, "Invalid 'options' option"); } else if (strcmp(name, "commands") == 0) { if (parse_argv(value, &gr->commands) != 0) errx(2, "Invalid 'commands' option"); } } else if (strcmp(header, "poll") == 0) { if (strcmp(name, "interval") == 0) gr->interval = atoi(value); } return 0; } int cfg_error(const char* filename, const char* errmsg, void* data) { /* todo skip the rest of this file on error */ warnx("%s", errmsg); return 0; } void freegraphs () { graph* l; graph* t; for (l = allgraphs; l != NULL; ) { t = l->next; if (l->options) free(l->options); if (l->commands) free(l->commands); free(l); l = t; } } /* ----------------------------------------------------------------------------- * METHODS */ static void listgraphs () { graph* l; printf("Content-Type: text/xml\n\n"); printf("\n"); printf("\n"); for (l = allgraphs; l != NULL; l = l->next) { printf(" name, l->category, l->title); if (l->width) printf(" width=\"%d\"", l->width); if (l->height) printf(" height=\"%d\"", l->height); if (l->interval) printf(" interval=\"%d\"", l->interval); printf(" />\n"); } printf("\n"); } #if 0 static void displaygraphs () { char* name = NULL; int width; int height; char* q; char* query = NULL; q = getenv("QUERY_STRING"); if (q) { query = q = strdup(q); while (q[0] && (q[0] == '?' || isspace(q[0]))) q++; while (q && q[0]) { nm = strsep(&q, "&"); vl = strchr(nm, '='); if (!vl) continue; vl[0] = 0; vl++; if (strcmp(nm, "name") == 0) name = vl; else if (strcmp(nm, "width") == 0) width = atoi(vl); else if (strcmp(nm, "height") == ) height = atoi(vl); } } } #endif /* ----------------------------------------------------------------------------- * MAIN */ static void usererror (const char* msg) { printf("Content-Type: text/plain\n\n"); printf("%s\n", msg); /* Custom error so webserver doesn't think it's a server error */ exit(0); } static int pathstarts (const char* path, const char* method) { int len = strlen(method); if (strncmp(path, method, len) != 0) return 0; if (path[len] == '/' || !path[len]) return 1; return 0; } int main (int argc, char* argv[]) { char* path; conf_directory = getenv("CONFDIR"); work_directory = getenv("WORKDIR"); if (!conf_directory || !work_directory) errx(2, "not setup properly. CONFDIR and WORKDIR env variables must be set"); /* * We always have this as our current directory. * It helps when constructing graphs and the like */ if (chdir(work_directory) < 0) err(1, "Couldn't change to work directory: %s", work_directory); path = getenv("PATH_INFO"); while (path && path[0] && (isspace(path[0]) || path[0] == '/')) path++; cfg_parse_dir(conf_directory, NULL); if (!path || !path[0] || pathstarts(path, "list")) listgraphs(); else if (pathstarts(path, "graph")) printf("graph\n"); else usererror("Invalid request"); freegraphs(); return 0; }