#include #include #include #include #include #include #include #include #include #include "pump.h" static void parseError(int line, char * message) { fprintf(stderr, "error parsing config file at line %d: %s\n", line, message); } static int readStanza(char ** cfg, struct pumpOverrideInfo * overrideList, struct pumpOverrideInfo * override, int * lineNum) { struct pumpOverrideInfo * nextO = override + 1; char * start, * end, * next, * rest, * chptr; int line; int argc; const char ** argv; int num; if (!lineNum) { line = 1; lineNum = &line; } next = *cfg; while (next && *next) { start = next; while (isspace(*start) && *start != '\n') start++; if (*start == '\n') { next = start + 1; (*lineNum)++; continue; } else if (*start == '#') { next = strchr(start, '\n') + 1; (*lineNum)++; continue; } end = strchr(start, '\n'); *end = '\0'; next = end + 1; chptr = start; while (!isspace(*chptr) && *chptr) chptr++; rest = chptr; while (*rest && isspace(*rest)) rest++; *chptr = '\0'; if (!strcmp(start, "device")) { if (overrideList != override) { parseError(*lineNum, "device directive may not occur inside " "of device specification"); return 1; } if (!*rest || *rest == '{') { parseError(*lineNum, "device directive must be followed by a " "device name"); return 1; } end = rest + 1; while (!isspace(*end) && *end != '{' && *end) end++; chptr = end; while (isspace(*end) && *end) end++; if (*end != '{') { parseError(*lineNum, "device directive must end with a {"); return 1; } end++; *chptr = '\0'; while (*end && isspace(*end)) end++; if (*end) { parseError(*lineNum, "unexpected information after {"); return 1; } *nextO = *override; strcpy(nextO->intf.device, rest); nextO->script = override->script ? strdup(override->script) : NULL; (*lineNum)++; if (readStanza(&next, overrideList, nextO, lineNum)) return 1; (*lineNum)--; /* it'll get incremented again at the end of this while loop */ nextO++; } else if (!strcmp(start, "}")) { if (overrideList == override) { parseError(*lineNum,"} may only occur inside of a " "device directive"); return 1; } else if (*rest) { parseError(*lineNum, "unexpected information after }"); } *cfg = next; (*lineNum)++; return 0; } else if (!strcmp(start, "timeout")) { poptParseArgvString(rest, &argc, &argv); if (argc != 1) { parseError(*lineNum, "timeout directive expects a " "single argument"); return 1; } num = strtol(argv[0], &chptr, 0); if (*chptr) { parseError(*lineNum, "timeout requires a numeric argument"); return 1; } override->timeout = num; } else if (!strcmp(start, "retries")) { poptParseArgvString(rest, &argc, &argv); if (argc != 1) { parseError(*lineNum, "retries directive expects a " "single argument"); return 1; } num = strtol(argv[0], &chptr, 0); if (*chptr) { parseError(*lineNum, "retries requires a numeric argument"); return 1; } override->numRetries = num; } else if (!strcmp(start, "domainsearch")) { if (overrideList != override) { parseError(*lineNum, "domainsearch directive may not occur " "inside of device specification"); return 1; } poptParseArgvString(rest, &argc, &argv); if (argc != 1) { parseError(*lineNum, "domainsearch directive expects a " "single argument"); return 1; } /* We don't free this as other configurations may have inherited it. This could be the wrong decision, but leak would be tiny so why worry? */ override->searchPath = strdup(argv[0]); free(argv); } else if (!strcmp(start, "nodns")) { if (*rest) { parseError(*lineNum, "unexpected argument to nodns directive"); return 1; } override->flags |= OVERRIDE_FLAG_NODNS; } else if (!strcmp(start, "script")) { if (overrideList != override) { parseError(*lineNum, "script directive may not occur " "inside of device specification"); return 1; } poptParseArgvString(rest, &argc, &argv); if (argc != 1) { parseError(*lineNum, "script directive expects a " "single argument"); return 1; } override->script = strdup(argv[0]); free(argv); } else { char * error; error = malloc(strlen(start) + 50); sprintf(error, "unrecognized directive %s", start); parseError(*lineNum, error); free(error); return 1; } (*lineNum)++; } *cfg = next; return 0; } int readPumpConfig(char * configFile, struct pumpOverrideInfo ** overrides) { int fd; char * buf, * chptr; struct stat sb; int count; void * orig = *overrides; if ((fd = open(configFile, O_RDONLY)) < 0) { *overrides = calloc(sizeof(**overrides), 2); pumpInitOverride(*overrides); close(fd); return 0; } fstat(fd, &sb); buf = alloca(sb.st_size + 2); if (read(fd, buf, sb.st_size) != sb.st_size) { close(fd); return 1; } close(fd); buf[sb.st_size] = '\n'; buf[sb.st_size + 1] = '\0'; /* this will give us an upper limit anyway */ count = 1; chptr = buf; while ((chptr = strchr(chptr, '{'))) { chptr++; count++; } *overrides = calloc(sizeof(**overrides), count + 1); pumpInitOverride(*overrides); count = readStanza(&buf, *overrides, *overrides, NULL); if (count) { free(*overrides); *overrides = orig; } return count; };