Index: config.c =================================================================== --- config.c (revision 290) +++ config.c (working copy) @@ -1,5 +1,9 @@ #include +#ifdef _ALLOCA_H #include +#else +#include +#endif #include #include #include @@ -30,13 +34,55 @@ #define REALLOC_STEP 10 -#if defined(SunOS) -#include +#if defined(SunOS) +#include #if !defined(isblank) #define isblank(c) ( (c) == ' ' || (c) == '\t' ) ? 1 : 0 #endif #endif +#if !defined(asprintf) +#include + +int asprintf(char **string_ptr, const char *format, ...) +{ + va_list arg; + char *str; + int size; + int rv; + + va_start(arg, format); + size = vsnprintf(NULL, 0, format, arg); + size++; + va_start(arg, format); + str = malloc(size); + if (str == NULL) { + va_end(arg); + /* + * Strictly speaking, GNU asprintf doesn't do this, + * but the caller isn't checking the return value. + */ + fprintf(stderr, "failed to allocate memory\\n"); + exit(1); + } + rv = vsnprintf(str, size, format, arg); + va_end(arg); + + *string_ptr = str; + return (rv); +} + +#endif + +enum { + STATE_DEFAULT = 2, + STATE_SKIP_LINE = 4, + STATE_DEFINITION_END = 8, + STATE_SKIP_CONFIG = 16, + STATE_LOAD_SCRIPT = 32, + STATE_ERROR = 64, +}; + static char *defTabooExts[] = { ".rpmsave", ".rpmorig", "~", ",v", ".disabled", ".dpkg-old", ".dpkg-dist", ".dpkg-new", ".cfsaved", ".ucf-old", ".ucf-dist", ".ucf-new", @@ -52,51 +98,71 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig); static int globerr(const char *pathname, int theerr); -static int isolateValue(const char *fileName, int lineNum, char *key, - char **startPtr, char **endPtr) +static char *isolateLine(char **strt, char **buf, size_t length) { + char *endtag, *start, *tmp; + start = *strt; + endtag = start; + while (endtag - *buf < length && *endtag != '\n') { + endtag++;} + if (endtag - *buf > length) + return NULL; + tmp = endtag - 1; + while (isspace(*endtag)) + endtag--; + char *key = strndup(start, endtag - start + 1); + *strt = tmp; + return key; +} + +static char *isolateValue(const char *fileName, int lineNum, char *key, + char **startPtr, char **buf, size_t length) { char *chptr = *startPtr; - while (isblank(*chptr)) + while (chptr - *buf < length && isblank(*chptr)) chptr++; - if (*chptr == '=') { + if (chptr - *buf < length && *chptr == '=') { chptr++; - while (*chptr && isblank(*chptr)) + while ( chptr - *buf < length && isblank(*chptr)) chptr++; } - if (*chptr == '\n') { - message(MESS_ERROR, "%s:%d argument expected after %s\n", - fileName, lineNum, key); - return 1; + if (chptr - *buf < length && *chptr == '\n') { + message(MESS_ERROR, "%s:%d argument expected after %s\n", + fileName, lineNum, key); + return NULL; } - *startPtr = chptr; + *startPtr = chptr; + return isolateLine(startPtr, buf, length); +} - while (*chptr != '\n') - chptr++; - - while (isspace(*chptr)) - chptr--; - - *endPtr = chptr + 1; - - return 0; +static char *isolateWord(char **strt, char **buf, size_t length) { + char *endtag, *start; + start = *strt; + while (start - *buf < length && isblank(*start)) + start++; + endtag = start; + while (endtag - *buf < length && isalpha(*endtag)) { + endtag++;} + if (endtag - *buf > length) + return NULL; + char *key = strndup(start, endtag - start); + *strt = endtag; + return key; } static char *readPath(const char *configFile, int lineNum, char *key, - char **startPtr) + char **startPtr, char **buf, size_t length) { - char oldchar; - char *endtag, *chptr; + char *chptr; char *start = *startPtr; char *path; wchar_t pwc; size_t len; - if (!isolateValue(configFile, lineNum, key, &start, &endtag)) { - oldchar = *endtag, *endtag = '\0'; + if ((start = isolateValue(configFile, lineNum, key, startPtr, buf, length)) != NULL) { chptr = start; @@ -120,29 +186,23 @@ */ path = strdup(start); + free(start); - - *endtag = oldchar, start = endtag; - - *startPtr = start; - return path; } else return NULL; } static char *readAddress(const char *configFile, int lineNum, char *key, - char **startPtr) + char **startPtr, char **buf, size_t length) { - char oldchar; char *endtag, *chptr; char *start = *startPtr; char *address; - if (!isolateValue(configFile, lineNum, key, &start, &endtag)) { - oldchar = *endtag, *endtag = '\0'; + if ((endtag = isolateValue(configFile, lineNum, key, startPtr, buf, length)) != NULL) { - chptr = start; + chptr = endtag; while (*chptr && isprint(*chptr) && *chptr != ' ') chptr++; if (*chptr) { @@ -151,12 +211,9 @@ return NULL; } - address = strdup(start); + address = strdup(chptr); + free(endtag); - *endtag = oldchar, start = endtag; - - *startPtr = start; - return address; } else return NULL; @@ -484,8 +541,8 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig) { int fd; - char *buf, *endtag; - char oldchar, foo; + char *buf, *endtag, *key = NULL; + char foo; off_t length; int lineNum = 1; int multiplier; @@ -504,6 +561,8 @@ glob_t globResult; const char **argv; int argc, argNum; + int flags; + int state = STATE_DEFAULT; int logerror = 0; struct logInfo *log; static unsigned recursion_depth = 0U; @@ -519,17 +578,28 @@ length arrays -- of course, if we aren't run setuid it doesn't matter much */ - fd = open(configFile, O_RDONLY | O_CLOEXEC); - if (fd < 0) { - message(MESS_ERROR, "failed to open config file %s: %s\n", - configFile, strerror(errno)); - return 1; - } + fd = open(configFile, O_RDONLY); + if (fd < 0) { + message(MESS_ERROR, "failed to open config file %s: %s\n", + configFile, strerror(errno)); + return 1; + } + if ((flags = fcntl(fd, F_GETFD)) == -1) { + message(MESS_ERROR, "Could not retrieve flags from file %s\n", + configFile); + return 1; + } + flags |= FD_CLOEXEC; + if (fcntl(fd, F_SETFD, flags) == -1) { + message(MESS_ERROR, "Could not set flags on file %s\n", + configFile); + return 1; + } /* We don't want anybody to change the file while we parse it, * let's try to lock it for reading. */ if (fcntl(fd, F_SETLK, &fd_lock) == -1) { - message(MESS_ERROR, "Could not lock file %s for reading\n", - configFile); + message(MESS_ERROR, "Could not lock file %s for reading\n", + configFile); } if (fstat(fd, &sb)) { message(MESS_ERROR, "fstat of %s failed: %s\n", configFile, @@ -546,8 +616,24 @@ } length = sb.st_size; - buf = mmap(NULL, (size_t)(length + 2), PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_POPULATE, fd, (off_t) 0); + + /* We can't mmap empty file... */ + if (length == 0) { + message(MESS_DEBUG, + "Ignoring %s because it's empty.\n", + configFile); + close(fd); + return 0; + } + +#ifdef MAP_POPULATE + buf = mmap(NULL, (size_t) length, PROT_READ, + MAP_PRIVATE | MAP_POPULATE, fd, (off_t) 0); +#else /* MAP_POPULATE */ + buf = mmap(NULL, (size_t) length, PROT_READ, + MAP_PRIVATE, fd, (off_t) 0); +#endif /* MAP_POPULATE */ + if (buf == MAP_FAILED) { message(MESS_ERROR, "Error mapping config file %s: %s\n", configFile, strerror(errno)); @@ -555,964 +641,812 @@ return 1; } - /* knowing the buffer ends with a newline makes things (a bit) cleaner */ - buf[length + 1] = '\0'; - buf[length] = '\n'; +#ifdef MADV_DONTFORK madvise(buf, (size_t)(length + 2), MADV_SEQUENTIAL | MADV_WILLNEED | MADV_DONTFORK); +#else /* MADV_DONTFORK */ + madvise(buf, (size_t)(length + 2), + MADV_SEQUENTIAL | MADV_WILLNEED); +#endif /* MADV_DONTFORK */ message(MESS_DEBUG, "reading config file %s\n", configFile); - start = buf; - while (*start) { - if (logerror) { - assert(newlog != defConfig); - - message(MESS_ERROR, "found error in %s, skipping\n", - newlog->pattern ? newlog->pattern : "log config"); - - while (*start != '}') { - if (*start == 0) { - message(MESS_ERROR, "%s:%d } expected \n", - configFile, lineNum); - goto error; - } else if (*start == '\n') { - while (isspace(*start) && (*start)) { - if (*start == '\n') - lineNum++; - start++; - } - } else if ( - (strncmp(start, "postrotate", 10) == 0) || - (strncmp(start, "prerotate", 9) == 0) || - (strncmp(start, "firstrotate", 11) == 0) || - (strncmp(start, "lastrotate", 10) == 0) - ) - { - while (*start) { - while ((*start != '\n') && (*start)) - start++; - while (isspace(*start) && (*start)) { - if (*start == '\n') - lineNum++; - start++; + start = buf; + for (start = buf; start - buf < length; start++) { + if (key) { + free(key); + key = NULL; + } + switch (state) { + case STATE_DEFAULT: + if (isblank(*start)) + continue; + /* Skip comment */ + if (*start == '#') { + state = STATE_SKIP_LINE; + continue; } - if (strncmp(start, "endscript", 9) == 0) { - start += 9; - break; - } - } - } else { - start++; - } - } - start++; + + if (isalpha(*start)) { + if ((key = isolateWord(&start, &buf, length)) == NULL) + continue; + if (!strcmp(key, "compress")) { + newlog->flags |= LOG_FLAG_COMPRESS; + } else if (!strcmp(key, "nocompress")) { + newlog->flags &= ~LOG_FLAG_COMPRESS; + } else if (!strcmp(key, "compress")) { + newlog->flags |= LOG_FLAG_COMPRESS; + } else if (!strcmp(key, "nocompress")) { + newlog->flags &= ~LOG_FLAG_COMPRESS; + } else if (!strcmp(key, "delaycompress")) { + newlog->flags |= LOG_FLAG_DELAYCOMPRESS; + } else if (!strcmp(key, "nodelaycompress")) { + newlog->flags &= ~LOG_FLAG_DELAYCOMPRESS; + } else if (!strcmp(key, "shred")) { + newlog->flags |= LOG_FLAG_SHRED; + } else if (!strcmp(key, "noshred")) { + newlog->flags &= ~LOG_FLAG_SHRED; + } else if (!strcmp(key, "sharedscripts")) { + newlog->flags |= LOG_FLAG_SHAREDSCRIPTS; + } else if (!strcmp(key, "nosharedscripts")) { + newlog->flags &= ~LOG_FLAG_SHAREDSCRIPTS; + } else if (!strcmp(key, "copytruncate")) { + newlog->flags |= LOG_FLAG_COPYTRUNCATE; + } else if (!strcmp(key, "nocopytruncate")) { + newlog->flags &= ~LOG_FLAG_COPYTRUNCATE; + } else if (!strcmp(key, "copy")) { + newlog->flags |= LOG_FLAG_COPY; + } else if (!strcmp(key, "nocopy")) { + newlog->flags &= ~LOG_FLAG_COPY; + } else if (!strcmp(key, "ifempty")) { + newlog->flags |= LOG_FLAG_IFEMPTY; + } else if (!strcmp(key, "notifempty")) { + newlog->flags &= ~LOG_FLAG_IFEMPTY; + } else if (!strcmp(key, "dateext")) { + newlog->flags |= LOG_FLAG_DATEEXT; + } else if (!strcmp(key, "nodateext")) { + newlog->flags &= ~LOG_FLAG_DATEEXT; + } else if (!strcmp(key, "dateformat")) { + freeLogItem(dateformat); + newlog->dateformat = isolateLine(&start, &buf, length); + if (newlog->dateformat == NULL) + continue; + } else if (!strcmp(key, "noolddir")) { + newlog->oldDir = NULL; + } else if (!strcmp(key, "mailfirst")) { + newlog->flags |= LOG_FLAG_MAILFIRST; + } else if (!strcmp(key, "maillast")) { + newlog->flags &= ~LOG_FLAG_MAILFIRST; + } else if (!strcmp(key, "create")) { + free(key); + key = isolateLine(&start, &buf, length); + if (key == NULL) + continue; - freeTailLogs(1); - newlog = defConfig; - logerror = 0; - } - while (isblank(*start) && (*start)) - start++; - if (*start == '#') { - while (*start != '\n') - start++; - } + rc = sscanf(key, "%o %s %s%c", &createMode, + createOwner, createGroup, &foo); + if (rc == 4) { + message(MESS_ERROR, "%s:%d extra arguments for " + "create\n", configFile, lineNum); + if (newlog != defConfig) { + state = STATE_ERROR; + continue; + } else { + goto error; + } + } - if (*start == '\n') { - start++; - lineNum++; - continue; - } + if (rc > 0) + newlog->createMode = createMode; - if (scriptStart) { - if (!strncmp(start, "endscript", 9)) { - chptr = start + 9; - while (isblank(*chptr)) - chptr++; - if (*chptr == '\n') { - endtag = start; - while (*endtag != '\n') - endtag--; - endtag++; - *scriptDest = malloc(endtag - scriptStart + 1); - strncpy(*scriptDest, scriptStart, - endtag - scriptStart); - (*scriptDest)[endtag - scriptStart] = '\0'; - start = chptr + 1; - lineNum++; + if (rc > 1) { + pw = getpwnam(createOwner); + if (!pw) { + message(MESS_ERROR, "%s:%d unknown user '%s'\n", + configFile, lineNum, createOwner); + if (newlog != defConfig) { + state = STATE_ERROR; + continue; + } else { + goto error; + } + } + newlog->createUid = pw->pw_uid; + endpwent(); + } + if (rc > 2) { + group = getgrnam(createGroup); + if (!group) { + message(MESS_ERROR, "%s:%d unknown group '%s'\n", + configFile, lineNum, createGroup); + if (newlog != defConfig) { + state = STATE_ERROR; + continue; + } else { + goto error; + } + } + newlog->createGid = group->gr_gid; + endgrent(); + } - scriptDest = NULL; - scriptStart = NULL; - } - } + newlog->flags |= LOG_FLAG_CREATE; + } else if (!strcmp(key, "nocreate")) { + newlog->flags &= ~LOG_FLAG_CREATE; + } else if (!strcmp(key, "size") || !strcmp(key, "minsize")) { + unsigned long long size = 0; + char *opt = key; + + if ((key = isolateValue(configFile, lineNum, opt, &start, + &buf, length)) != NULL) { + free(opt); + int l = strlen(key) - 1; + if (key[l] == 'k') { + key[l] = '\0'; + multiplier = 1024; + } else if (key[l] == 'M') { + key[l] = '\0'; + multiplier = 1024 * 1024; + } else if (key[l] == 'G') { + key[l] = '\0'; + multiplier = 1024 * 1024 * 1024; + } else if (!isdigit(key[l])) { + message(MESS_ERROR, "%s:%d unknown unit '%c'\n", + configFile, lineNum, key[l]); + if (newlog != defConfig) { + state = STATE_ERROR; + continue; + } else { + goto error; + } + } else { + multiplier = 1; + } - if (scriptStart) { - while (*start != '\n') - start++; - lineNum++; - start++; - } - } else if (isalpha(*start)) { - endtag = start; - while (isalpha(*endtag)) - endtag++; - oldchar = *endtag; - *endtag = '\0'; + size = multiplier * strtoul(key, &chptr, 0); + if (*chptr) { + message(MESS_ERROR, "%s:%d bad size '%s'\n", + configFile, lineNum, key); + if (newlog != defConfig) { + state = STATE_ERROR; + continue; + } else { + goto error; + } + } + if (!strncmp(key, "size", 4)) { + newlog->criterium = ROT_SIZE; + newlog->threshhold = size; + } else + newlog->minsize = size; + } + else { + free(opt); + continue; + } + } else if (!strcmp(key, "shredcycles")) { + free(key); + if ((key = isolateValue(configFile, lineNum, "shred cycles", + &start, &buf, length)) != NULL) { + newlog->shred_cycles = strtoul(key, &chptr, 0); + if (*chptr || newlog->shred_cycles < 0) { + message(MESS_ERROR, "%s:%d bad shred cycles '%s'\n", + configFile, lineNum, key); + goto error; + } + } + else continue; + } else if (!strcmp(key, "daily")) { + newlog->criterium = ROT_DAYS; + newlog->threshhold = 1; + } else if (!strcmp(key, "monthly")) { + newlog->criterium = ROT_MONTHLY; + } else if (!strcmp(key, "weekly")) { + newlog->criterium = ROT_WEEKLY; + } else if (!strcmp(key, "yearly")) { + newlog->criterium = ROT_YEARLY; + } else if (!strcmp(key, "rotate")) { + free(key); + if ((key = isolateValue + (configFile, lineNum, "rotate count", &start, + &buf, length)) != NULL) { - if (!strcmp(start, "compress")) { - newlog->flags |= LOG_FLAG_COMPRESS; + newlog->rotateCount = strtoul(key, &chptr, 0); + if (*chptr || newlog->rotateCount < 0) { + message(MESS_ERROR, + "%s:%d bad rotation count '%s'\n", + configFile, lineNum, key); + if (newlog != defConfig) { + state = STATE_ERROR; + continue; + } else { + goto error; + } + } + } + else continue; + } else if (!strcmp(key, "start")) { + free(key); + if ((key = isolateValue + (configFile, lineNum, "start count", &start, + &buf, length)) != NULL) { - *endtag = oldchar, start = endtag; - } else if (!strcmp(start, "nocompress")) { - newlog->flags &= ~LOG_FLAG_COMPRESS; + newlog->logStart = strtoul(start, &chptr, 0); + if (*chptr || newlog->logStart < 0) { + message(MESS_ERROR, "%s:%d bad start count '%s'\n", + configFile, lineNum, key); + if (newlog != defConfig) { + state = STATE_ERROR; + continue; + } else { + goto error; + } + } + } + else continue; + } else if (!strcmp(key, "maxage")) { + free(key); + if ((key = isolateValue + (configFile, lineNum, "maxage count", &start, + &buf, length)) != NULL) { + newlog->rotateAge = strtoul(start, &chptr, 0); + if (*chptr || newlog->rotateAge < 0) { + message(MESS_ERROR, "%s:%d bad maximum age '%s'\n", + configFile, lineNum, start); + if (newlog != defConfig) { + state = STATE_ERROR; + continue; + } else { + goto error; + } + } + } + else continue; + } else if (!strcmp(key, "errors")) { + message(MESS_DEBUG, + "%s: %d: the errors directive is deprecated and no longer used.\n", + configFile, lineNum); + } else if (!strcmp(key, "mail")) { + freeLogItem(logAddress); + if (!(newlog->logAddress = readAddress(configFile, lineNum, + "mail", &start, &buf, length))) { + if (newlog != defConfig) { + state = STATE_ERROR; + continue; + } else { + goto error; + } + } + else continue; + } else if (!strcmp(key, "nomail")) { + freeLogItem(logAddress); + } else if (!strcmp(key, "missingok")) { + newlog->flags |= LOG_FLAG_MISSINGOK; + } else if (!strcmp(key, "nomissingok")) { + newlog->flags &= ~LOG_FLAG_MISSINGOK; + } else if (!strcmp(key, "prerotate")) { + freeLogItem (pre); + scriptStart = start; + scriptDest = &newlog->pre; + state = STATE_LOAD_SCRIPT; + } else if (!strcmp(key, "firstaction")) { + freeLogItem (first); + scriptStart = start; + scriptDest = &newlog->first; + state = STATE_LOAD_SCRIPT; + } else if (!strcmp(key, "postrotate")) { + freeLogItem (post); + scriptStart = start; + scriptDest = &newlog->post; + state = STATE_LOAD_SCRIPT; + } else if (!strcmp(key, "lastaction")) { + freeLogItem (last); + scriptStart = start; + scriptDest = &newlog->last; + state = STATE_LOAD_SCRIPT; + } else if (!strcmp(key, "tabooext")) { + if (newlog != defConfig) { + message(MESS_ERROR, + "%s:%d tabooext may not appear inside " + "of log file definition\n", configFile, + lineNum); + state = STATE_ERROR; + continue; + } + free(key); + if ((key = isolateValue(configFile, lineNum, "tabooext", &start, + &buf, length)) != NULL) { - *endtag = oldchar, start = endtag; - } else if (!strcmp(start, "delaycompress")) { - newlog->flags |= LOG_FLAG_DELAYCOMPRESS; + if (*key == '+') { + key++; + while (isspace(*key) && *key) + key++; + } else { + free_2d_array(tabooExts, tabooCount); + tabooCount = 0; + tabooExts = malloc(1); + } - *endtag = oldchar, start = endtag; - } else if (!strcmp(start, "nodelaycompress")) { - newlog->flags &= ~LOG_FLAG_DELAYCOMPRESS; + endtag = key; + while (*endtag) { + chptr = endtag; + while (!isspace(*chptr) && *chptr != ',' && *chptr) + chptr++; - *endtag = oldchar, start = endtag; - } else if (!strcmp(start, "shred")) { - newlog->flags |= LOG_FLAG_SHRED; + tabooExts = realloc(tabooExts, sizeof(*tabooExts) * + (tabooCount + 1)); + tabooExts[tabooCount] = malloc(chptr - endtag + 1); + strncpy(tabooExts[tabooCount], endtag, + chptr - endtag); + tabooExts[tabooCount][chptr - endtag] = '\0'; + tabooCount++; - *endtag = oldchar, start = endtag; - } else if (!strcmp(start, "noshred")) { - newlog->flags &= ~LOG_FLAG_SHRED; + endtag = chptr; + if (*endtag == ',') + start++; + while (isspace(*endtag) && *endtag) + endtag++; + } + } + else continue; + } else if (!strcmp(key, "include")) { + free(key); + if ((key = isolateValue(configFile, lineNum, "include", &start, + &buf, length)) != NULL) { - *endtag = oldchar, start = endtag; - } else if (!strcmp(start, "sharedscripts")) { - newlog->flags |= LOG_FLAG_SHAREDSCRIPTS; + message(MESS_DEBUG, "including %s\n", key); + if (++recursion_depth > MAX_NESTING) { + message(MESS_ERROR, "%s:%d include nesting too deep\n", + configFile, lineNum); + --recursion_depth; + goto error; + } + if (readConfigPath(key, newlog)) { + --recursion_depth; + goto error; + } + --recursion_depth; + } + else continue; + } else if (!strcmp(key, "olddir")) { + freeLogItem (oldDir); - *endtag = oldchar, start = endtag; - } else if (!strcmp(start, "nosharedscripts")) { - newlog->flags &= ~LOG_FLAG_SHAREDSCRIPTS; + if (!(newlog->oldDir = readPath(configFile, lineNum, + "olddir", &start, &buf, length))) { + if (newlog != defConfig) { + state = STATE_ERROR; + continue; + } else { + goto error; + } + } + else continue; +#if 0 + if (stat(newlog->oldDir, &sb)) { + message(MESS_ERROR, "%s:%d error verifying olddir " + "path %s: %s\n", configFile, lineNum, + newlog->oldDir, strerror(errno)); + free(newlog->oldDir); + goto error; + } - *endtag = oldchar, start = endtag; - } else if (!strcmp(start, "copytruncate")) { - newlog->flags |= LOG_FLAG_COPYTRUNCATE; + if (!S_ISDIR(sb.st_mode)) { + message(MESS_ERROR, "%s:%d olddir path %s is not a " + "directory\n", configFile, lineNum, + newlog->oldDir); + free(newlog->oldDir); + goto error; + } +#endif + message(MESS_DEBUG, "olddir is now %s\n", newlog->oldDir); + } else if (!strcmp(key, "extension")) { + if ((key = isolateValue + (configFile, lineNum, "extension name", &start, + &buf, length)) != NULL) { + freeLogItem (extension); + newlog->extension = key; + key = NULL; + } + else continue; - *endtag = oldchar, start = endtag; - } else if (!strcmp(start, "nocopytruncate")) { - newlog->flags &= ~LOG_FLAG_COPYTRUNCATE; + message(MESS_DEBUG, "extension is now %s\n", + newlog->extension); - *endtag = oldchar, start = endtag; - } else if (!strcmp(start, "copy")) { - newlog->flags |= LOG_FLAG_COPY; + } else if (!strcmp(key, "compresscmd")) { + freeLogItem (compress_prog); - *endtag = oldchar, start = endtag; - } else if (!strcmp(start, "nocopy")) { - newlog->flags &= ~LOG_FLAG_COPY; + if (! + (newlog->compress_prog = + readPath(configFile, lineNum, "compress", &start, &buf, length))) { + if (newlog != defConfig) { + state = STATE_ERROR; + continue; + } else { + goto error; + } + } + else continue; - *endtag = oldchar, start = endtag; - } else if (!strcmp(start, "ifempty")) { - newlog->flags |= LOG_FLAG_IFEMPTY; + if (access(newlog->compress_prog, X_OK)) { + message(MESS_ERROR, + "%s:%d compression program %s is not an executable file\n", + configFile, lineNum, newlog->compress_prog); + if (newlog != defConfig) { + state = STATE_ERROR; + continue; + } else { + goto error; + } + } - *endtag = oldchar, start = endtag; - } else if (!strcmp(start, "notifempty")) { - newlog->flags &= ~LOG_FLAG_IFEMPTY; + message(MESS_DEBUG, "compress_prog is now %s\n", + newlog->compress_prog); - *endtag = oldchar, start = endtag; - } else if (!strcmp(start, "dateext")) { - newlog->flags |= LOG_FLAG_DATEEXT; + } else if (!strcmp(key, "uncompresscmd")) { + freeLogItem (uncompress_prog); - *endtag = oldchar, start = endtag; - } else if (!strcmp(start, "nodateext")) { - newlog->flags &= ~LOG_FLAG_DATEEXT; - - *endtag = oldchar, start = endtag; - } else if (!strcmp(start, "dateformat")) { - *endtag = oldchar, start = endtag; - - endtag = start; - while (*endtag != '\n') - endtag++; - while (isspace(*endtag)) - endtag--; - endtag++; - oldchar = *endtag, *endtag = '\0'; + if (! + (newlog->uncompress_prog = + readPath(configFile, lineNum, "uncompress", + &start, &buf, length))) { + if (newlog != defConfig) { + state = STATE_ERROR; + continue; + } else { + goto error; + } + } + else continue; - freeLogItem(dateformat); - newlog->dateformat = strdup(start); + if (access(newlog->uncompress_prog, X_OK)) { + message(MESS_ERROR, + "%s:%d uncompression program %s is not an executable file\n", + configFile, lineNum, newlog->uncompress_prog); + if (newlog != defConfig) { + state = STATE_ERROR; + continue; + } else { + goto error; + } + } - *endtag = oldchar, start = endtag; - } else if (!strcmp(start, "noolddir")) { - newlog->oldDir = NULL; + message(MESS_DEBUG, "uncompress_prog is now %s\n", + newlog->uncompress_prog); - *endtag = oldchar, start = endtag; - } else if (!strcmp(start, "mailfirst")) { - newlog->flags |= LOG_FLAG_MAILFIRST; + } else if (!strcmp(key, "compressoptions")) { + char *options; - *endtag = oldchar, start = endtag; - } else if (!strcmp(start, "maillast")) { - newlog->flags &= ~LOG_FLAG_MAILFIRST; + if (newlog->compress_options_list) { + free(newlog->compress_options_list); + newlog->compress_options_list = NULL; + newlog->compress_options_count = 0; + } - *endtag = oldchar, start = endtag; - } else if (!strcmp(start, "create")) { - *endtag = oldchar, start = endtag; + if (! + (options = + readPath(configFile, lineNum, "compressoptions", + &start, &buf, length))) { + if (newlog != defConfig) { + state = STATE_ERROR; + continue; + } else { + goto error; + } + } else continue; - endtag = start; - while (*endtag != '\n') - endtag++; - while (isspace(*endtag)) - endtag--; - endtag++; - oldchar = *endtag, *endtag = '\0'; + if (poptParseArgvString(options, + &newlog->compress_options_count, + &newlog->compress_options_list)) { + message(MESS_ERROR, + "%s:%d invalid compression options\n", + configFile, lineNum); + free(options); + if (newlog != defConfig) { + state = STATE_ERROR; + continue; + } else { + goto error; + } + } - rc = sscanf(start, "%o %s %s%c", &createMode, - createOwner, createGroup, &foo); - if (rc == 4) { - message(MESS_ERROR, "%s:%d extra arguments for " - "create\n", configFile, lineNum); - if (newlog != defConfig) { - *endtag = oldchar, start = endtag; - logerror = 1; - continue; - } else { - goto error; - } - } + message(MESS_DEBUG, "compress_options is now %s\n", + options); + free(options); + } else if (!strcmp(key, "compressext")) { + freeLogItem (compress_ext); - if (rc > 0) - newlog->createMode = createMode; + if (! + (newlog->compress_ext = + readPath(configFile, lineNum, "compress-ext", + &start, &buf, length))) { + if (newlog != defConfig) { + state = STATE_ERROR; + continue; + } else { + goto error; + } + } else continue; - if (rc > 1) { - pw = getpwnam(createOwner); - if (!pw) { - message(MESS_ERROR, "%s:%d unknown user '%s'\n", - configFile, lineNum, createOwner); - if (newlog != defConfig) { - *endtag = oldchar, start = endtag; - logerror = 1; - continue; - } else { - goto error; - } - } - newlog->createUid = pw->pw_uid; - endpwent(); - } - if (rc > 2) { - group = getgrnam(createGroup); - if (!group) { - message(MESS_ERROR, "%s:%d unknown group '%s'\n", - configFile, lineNum, createGroup); - if (newlog != defConfig) { - *endtag = oldchar, start = endtag; - logerror = 1; - continue; - } else { - goto error; - } - } - newlog->createGid = group->gr_gid; - endgrent(); - } + message(MESS_DEBUG, "compress_ext is now %s\n", + newlog->compress_ext); + } else { + message(MESS_ERROR, "%s:%d unknown option '%s' " + "-- ignoring line\n", configFile, lineNum, key); + if (*start != '\n') + state = STATE_SKIP_LINE; + } + free(key); + key = NULL; + } else if (*start == '/' || *start == '"' || *start == '\'') { + if (newlog != defConfig) { + message(MESS_ERROR, "%s:%d unexpected log filename\n", + configFile, lineNum); + state = STATE_ERROR; + continue; + } - newlog->flags |= LOG_FLAG_CREATE; + /* If no compression options were found in config file, set + default values */ + if (!newlog->compress_prog) + newlog->compress_prog = strdup(COMPRESS_COMMAND); + if (!newlog->uncompress_prog) + newlog->uncompress_prog = strdup(UNCOMPRESS_COMMAND); + if (!newlog->compress_ext) + newlog->compress_ext = strdup(COMPRESS_EXT); - *endtag = oldchar, start = endtag; - } else if (!strcmp(start, "nocreate")) { - newlog->flags &= ~LOG_FLAG_CREATE; + /* Allocate a new logInfo structure and insert it into the logs + queue, copying the actual values from defConfig */ + if ((newlog = newLogInfo(defConfig)) == NULL) + goto error; - *endtag = oldchar, start = endtag; - } else if (!strcmp(start, "size") || !strcmp(start, "minsize")) { - unsigned long long size = 0; - char *opt = start; - *endtag = oldchar, start = endtag; + endtag = start; + while (endtag - buf < length && *endtag != '{' && *endtag != '\0') { + endtag++;} + if (endtag - buf > length) + continue; + char *key = strndup(start, endtag - start); + start = endtag; - if (!isolateValue(configFile, lineNum, opt, &start, - &endtag)) { - oldchar = *endtag, *endtag = '\0'; + if (poptParseArgvString(key, &argc, &argv)) { + message(MESS_ERROR, "%s:%d error parsing filename\n", + configFile, lineNum); + free(key); + goto error; + } else if (argc < 1) { + message(MESS_ERROR, + "%s:%d { expected after log file name(s)\n", + configFile, lineNum); + free(key); + goto error; + } - length = strlen(start) - 1; - if (start[length] == 'k') { - start[length] = '\0'; - multiplier = 1024; - } else if (start[length] == 'M') { - start[length] = '\0'; - multiplier = 1024 * 1024; - } else if (start[length] == 'G') { - start[length] = '\0'; - multiplier = 1024 * 1024 * 1024; - } else if (!isdigit(start[length])) { - message(MESS_ERROR, "%s:%d unknown unit '%c'\n", - configFile, lineNum, start[length]); - if (newlog != defConfig) { - *endtag = oldchar, start = endtag; - logerror = 1; - continue; - } else { - goto error; - } - } else { - multiplier = 1; - } + newlog->files = NULL; + newlog->numFiles = 0; + for (argNum = 0; argNum < argc && logerror != 1; argNum++) { + if (globerr_msg) { + free(globerr_msg); + globerr_msg = NULL; + } + + rc = glob(argv[argNum], GLOB_NOCHECK, globerr, + &globResult); + if (rc == GLOB_ABORTED) { + if (newlog->flags & LOG_FLAG_MISSINGOK) { + continue; + } - size = multiplier * strtoul(start, &chptr, 0); - if (*chptr) { - message(MESS_ERROR, "%s:%d bad size '%s'\n", - configFile, lineNum, start); - if (newlog != defConfig) { - *endtag = oldchar, start = endtag; - logerror = 1; - continue; - } else { - goto error; - } - } + /* We don't yet know whether this stanza has "missingok" + * set, so store the error message for later. */ + rc = asprintf(&globerr_msg, "%s:%d glob failed for %s: %s\n", + configFile, lineNum, argv[argNum], strerror(glob_errno)); + if (rc == -1) + globerr_msg = NULL; + + globResult.gl_pathc = 0; + } - if (!strncmp(opt, "size", 4)) { - newlog->criterium = ROT_SIZE; - newlog->threshhold = size; - } else - newlog->minsize = size; + newlog->files = + realloc(newlog->files, + sizeof(*newlog->files) * (newlog->numFiles + + globResult. + gl_pathc)); - *endtag = oldchar, start = endtag; - } -#if 0 /* this seems like such a good idea :-( */ - } else if (!strcmp(start, "days")) { - *endtag = oldchar, start = endtag; + for (i = 0; i < globResult.gl_pathc; i++) { + /* if we glob directories we can get false matches */ + if (!lstat(globResult.gl_pathv[i], &sb) && + S_ISDIR(sb.st_mode)) { + continue; + } - if (!isolateValue(configFile, lineNum, "size", &start, - &endtag)) { - oldchar = *endtag, *endtag = '\0'; + for (log = logs.tqh_first; log != NULL; + log = log->list.tqe_next) { + for (k = 0; k < log->numFiles; k++) { + if (!strcmp(log->files[k], + globResult.gl_pathv[i])) { + message(MESS_ERROR, + "%s:%d duplicate log entry for %s\n", + configFile, lineNum, + globResult.gl_pathv[i]); + logerror = 1; + goto duperror; + } + } + } - newlog->threshhold = strtoul(start, &chptr, 0); - if (*chptr) { - message(MESS_ERROR, - "%s:%d bad number of days'%s'\n", - configFile, lineNum, start); - goto error; - } + newlog->files[newlog->numFiles] = + strdup(globResult.gl_pathv[i]); + newlog->numFiles++; + } + duperror: + globfree(&globResult); + } - newlog->criterium = ROT_DAYS; + newlog->pattern = key; - *endtag = oldchar, start = endtag; - } -#endif - } else if (!strcmp(start, "shredcycles")) { - *endtag = oldchar, start = endtag; +// if (!logerror) +// message(MESS_DEBUG, "reading config info for %s\n", start); - if (!isolateValue(configFile, lineNum, "shred cycles", - &start, &endtag)) { - oldchar = *endtag, *endtag = '\0'; + free(argv); - newlog->shred_cycles = strtoul(start, &chptr, 0); - if (*chptr || newlog->shred_cycles < 0) { - message(MESS_ERROR, "%s:%d bad shred cycles '%s'\n", - configFile, lineNum, start); - goto error; - } - *endtag = oldchar, start = endtag; - } - } else if (!strcmp(start, "daily")) { - *endtag = oldchar, start = endtag; +// start = endtag + 1; + } else if (*start == '}') { + if (newlog == defConfig) { + message(MESS_ERROR, "%s:%d unexpected }\n", configFile, + lineNum); + goto error; + } + if (globerr_msg) { + if (!(newlog->flags & LOG_FLAG_MISSINGOK)) + message(MESS_ERROR, globerr_msg); + free(globerr_msg); + globerr_msg = NULL; + if (!(newlog->flags & LOG_FLAG_MISSINGOK)) + return 1; + } - newlog->criterium = ROT_DAYS; - newlog->threshhold = 1; - } else if (!strcmp(start, "monthly")) { - *endtag = oldchar, start = endtag; + if (newlog->oldDir) { + for (i = 0; i < newlog->numFiles; i++) { + char *ld; + dirName = ourDirName(newlog->files[i]); + if (stat(dirName, &sb2)) { + message(MESS_ERROR, + "%s:%d error verifying log file " + "path %s: %s\n", configFile, lineNum, + dirName, strerror(errno)); + free(dirName); + goto error; + } + ld = alloca(strlen(dirName) + strlen(newlog->oldDir) + + 2); + sprintf(ld, "%s/%s", dirName, newlog->oldDir); + free(dirName); - newlog->criterium = ROT_MONTHLY; - } else if (!strcmp(start, "weekly")) { - *endtag = oldchar, start = endtag; + if (newlog->oldDir[0] != '/') + dirName = ld; + else + dirName = newlog->oldDir; + if (stat(dirName, &sb)) { + message(MESS_ERROR, "%s:%d error verifying olddir " + "path %s: %s\n", configFile, lineNum, + dirName, strerror(errno)); + goto error; + } - newlog->criterium = ROT_WEEKLY; - } else if (!strcmp(start, "yearly")) { - *endtag = oldchar, start = endtag; + if (sb.st_dev != sb2.st_dev) { + message(MESS_ERROR, + "%s:%d olddir %s and log file %s " + "are on different devices\n", configFile, + lineNum, newlog->oldDir, newlog->files[i]); + goto error; + } + } + } - newlog->criterium = ROT_YEARLY; - } else if (!strcmp(start, "rotate")) { - *endtag = oldchar, start = endtag; - - if (!isolateValue - (configFile, lineNum, "rotate count", &start, - &endtag)) { - oldchar = *endtag, *endtag = '\0'; - - newlog->rotateCount = strtoul(start, &chptr, 0); - if (*chptr || newlog->rotateCount < 0) { - message(MESS_ERROR, - "%s:%d bad rotation count '%s'\n", - configFile, lineNum, start); - if (newlog != defConfig) { - *endtag = oldchar, start = endtag; - logerror = 1; - continue; - } else { - goto error; + newlog = defConfig; + state = STATE_DEFINITION_END; + } else if (*start != '\n') { + message(MESS_ERROR, "%s:%d lines must begin with a keyword " + "or a filename (possibly in double quotes)\n", + configFile, lineNum); + state = STATE_SKIP_LINE; } - } - *endtag = oldchar, start = endtag; - } - } else if (!strcmp(start, "start")) { - *endtag = oldchar, start = endtag; - - if (!isolateValue - (configFile, lineNum, "start count", &start, - &endtag)) { - oldchar = *endtag, *endtag = '\0'; - - newlog->logStart = strtoul(start, &chptr, 0); - if (*chptr || newlog->logStart < 0) { - message(MESS_ERROR, "%s:%d bad start count '%s'\n", - configFile, lineNum, start); - if (newlog != defConfig) { - *endtag = oldchar, start = endtag; - logerror = 1; - continue; - } else { - goto error; + break; + case STATE_SKIP_LINE: + case STATE_SKIP_LINE | STATE_SKIP_CONFIG: + if (*start == '\n') + state = state & STATE_SKIP_CONFIG ? STATE_SKIP_CONFIG : STATE_DEFAULT; + break; + case STATE_SKIP_LINE | STATE_LOAD_SCRIPT: + if (*start == '\n') + state = STATE_LOAD_SCRIPT; + break; + case STATE_SKIP_LINE | STATE_LOAD_SCRIPT | STATE_SKIP_CONFIG: + if (*start == '\n') + state = STATE_LOAD_SCRIPT | STATE_SKIP_CONFIG; + break; + case STATE_DEFINITION_END: + case STATE_DEFINITION_END | STATE_SKIP_CONFIG: + if (isblank(*start)) + continue; + if (*start != '\n') { + message(MESS_ERROR, "%s:%d, unexpected text after }\n", + configFile, lineNum); + state = STATE_SKIP_LINE | (state & STATE_SKIP_CONFIG ? STATE_SKIP_CONFIG : 0); } - } - *endtag = oldchar, start = endtag; - } - } else if (!strcmp(start, "maxage")) { - *endtag = oldchar, start = endtag; + else + state = state & STATE_SKIP_CONFIG ? STATE_SKIP_CONFIG : STATE_DEFAULT; + break; + case STATE_ERROR: + assert(newlog != defConfig); - if (!isolateValue - (configFile, lineNum, "maxage count", &start, - &endtag)) { - oldchar = *endtag, *endtag = '\0'; + message(MESS_ERROR, "found error in %s, skipping\n", + newlog->pattern ? newlog->pattern : "log config"); - newlog->rotateAge = strtoul(start, &chptr, 0); - if (*chptr || newlog->rotateAge < 0) { - message(MESS_ERROR, "%s:%d bad maximum age '%s'\n", - configFile, lineNum, start); - if (newlog != defConfig) { - *endtag = oldchar, start = endtag; - logerror = 1; - continue; - } else { - goto error; - } - } - *endtag = oldchar, start = endtag; - } - } else if (!strcmp(start, "errors")) { - message(MESS_DEBUG, - "%s: %d: the errors directive is deprecated and no longer used.\n", - configFile, lineNum); - } else if (!strcmp(start, "mail")) { - *endtag = oldchar, start = endtag; - freeLogItem(logAddress); - if (!(newlog->logAddress = readAddress(configFile, lineNum, - "mail", &start))) { - if (newlog != defConfig) { - logerror = 1; - continue; - } else { - goto error; - } - } - } else if (!strcmp(start, "nomail")) { - freeLogItem(logAddress); + state = STATE_SKIP_CONFIG; + break; + case STATE_LOAD_SCRIPT: + case STATE_LOAD_SCRIPT | STATE_SKIP_CONFIG: + if ((key = isolateWord(&start, &buf, length)) == NULL) + continue; - *endtag = oldchar, start = endtag; - } else if (!strcmp(start, "missingok")) { - newlog->flags |= LOG_FLAG_MISSINGOK; + if (strcmp(key, "endscript") == 0) { + if (state & STATE_SKIP_CONFIG) { + state = STATE_SKIP_CONFIG; + } + else { + endtag = start - 9; + while (*endtag != '\n') + endtag--; + endtag++; + *scriptDest = malloc(endtag - scriptStart + 1); + strncpy(*scriptDest, scriptStart, + endtag - scriptStart); + (*scriptDest)[endtag - scriptStart] = '\0'; - *endtag = oldchar, start = endtag; - } else if (!strcmp(start, "nomissingok")) { - newlog->flags &= ~LOG_FLAG_MISSINGOK; - - *endtag = oldchar, start = endtag; - } else if (!strcmp(start, "prerotate")) { - *endtag = oldchar, start = endtag; - - freeLogItem (pre); - - scriptStart = start; - scriptDest = &newlog->pre; - - while (*start != '\n') - start++; - } else if (!strcmp(start, "firstaction")) { - *endtag = oldchar, start = endtag; - - freeLogItem (first); - - scriptStart = start; - scriptDest = &newlog->first; - - while (*start != '\n') - start++; - } else if (!strcmp(start, "postrotate")) { - *endtag = oldchar, start = endtag; - - freeLogItem (post); - - scriptStart = start; - scriptDest = &newlog->post; - - while (*start != '\n') - start++; - } else if (!strcmp(start, "lastaction")) { - *endtag = oldchar, start = endtag; - - freeLogItem (last); - - scriptStart = start; - scriptDest = &newlog->last; - - while (*start != '\n') - start++; - } else if (!strcmp(start, "tabooext")) { - if (newlog != defConfig) { - message(MESS_ERROR, - "%s:%d tabooext may not appear inside " - "of log file definition\n", configFile, - lineNum); - *endtag = oldchar, start = endtag; - logerror = 1; - continue; - } - - *endtag = oldchar, start = endtag; - if (!isolateValue(configFile, lineNum, "tabooext", &start, - &endtag)) { - oldchar = *endtag, *endtag = '\0'; - - if (*start == '+') { - start++; - while (isspace(*start) && *start) - start++; - } else { - free_2d_array(tabooExts, tabooCount); - tabooCount = 0; - tabooExts = malloc(1); - } - - while (*start) { - chptr = start; - while (!isspace(*chptr) && *chptr != ',' && *chptr) - chptr++; - - tabooExts = realloc(tabooExts, sizeof(*tabooExts) * - (tabooCount + 1)); - tabooExts[tabooCount] = malloc(chptr - start + 1); - strncpy(tabooExts[tabooCount], start, - chptr - start); - tabooExts[tabooCount][chptr - start] = '\0'; - tabooCount++; - - start = chptr; - if (*start == ',') - start++; - while (isspace(*start) && *start) - start++; - } - - *endtag = oldchar, start = endtag; - } - } else if (!strcmp(start, "include")) { -// if (newlog != defConfig) { -// message(MESS_ERROR, -// "%s:%d include may not appear inside " -// "of log file definition\n", configFile, -// lineNum); -// *endtag = oldchar, start = endtag; -// logerror = 1; -// continue; -// } - - *endtag = oldchar, start = endtag; - if (!isolateValue(configFile, lineNum, "include", &start, - &endtag)) { - oldchar = *endtag, *endtag = '\0'; - - message(MESS_DEBUG, "including %s\n", start); - if (++recursion_depth > MAX_NESTING) { - message(MESS_ERROR, "%s:%d include nesting too deep\n", - configFile, lineNum); - --recursion_depth; - goto error; + scriptDest = NULL; + scriptStart = NULL; + } + state = state & STATE_SKIP_CONFIG ? STATE_SKIP_CONFIG : STATE_DEFAULT; } - if (readConfigPath(start, newlog)) { - --recursion_depth; - goto error; + else { + state = (*start == '\n' ? 0 : STATE_SKIP_LINE) | + STATE_LOAD_SCRIPT | + (state & STATE_SKIP_CONFIG ? STATE_SKIP_CONFIG : 0); } - --recursion_depth; - - *endtag = oldchar, start = endtag; - } - } else if (!strcmp(start, "olddir")) { - *endtag = oldchar, start = endtag; - - freeLogItem (oldDir); - - if (!(newlog->oldDir = readPath(configFile, lineNum, - "olddir", &start))) { - if (newlog != defConfig) { - logerror = 1; - continue; - } else { - goto error; - } - } -#if 0 - if (stat(newlog->oldDir, &sb)) { - message(MESS_ERROR, "%s:%d error verifying olddir " - "path %s: %s\n", configFile, lineNum, - newlog->oldDir, strerror(errno)); - free(newlog->oldDir); - goto error; - } - - if (!S_ISDIR(sb.st_mode)) { - message(MESS_ERROR, "%s:%d olddir path %s is not a " - "directory\n", configFile, lineNum, - newlog->oldDir); - free(newlog->oldDir); - goto error; - } -#endif - - message(MESS_DEBUG, "olddir is now %s\n", newlog->oldDir); - } else if (!strcmp(start, "extension")) { - *endtag = oldchar, start = endtag; - - if (!isolateValue - (configFile, lineNum, "extension name", &start, - &endtag)) { - oldchar = *endtag, *endtag = '\0'; - - freeLogItem (extension); - newlog->extension = strdup(start); - - *endtag = oldchar, start = endtag; - } - - message(MESS_DEBUG, "extension is now %s\n", - newlog->extension); - - } else if (!strcmp(start, "compresscmd")) { - *endtag = oldchar, start = endtag; - - freeLogItem (compress_prog); - - if (! - (newlog->compress_prog = - readPath(configFile, lineNum, "compress", &start))) { - if (newlog != defConfig) { - logerror = 1; - continue; - } else { - goto error; - } - } - - if (access(newlog->compress_prog, X_OK)) { - message(MESS_ERROR, - "%s:%d compression program %s is not an executable file\n", - configFile, lineNum, newlog->compress_prog); - if (newlog != defConfig) { - logerror = 1; - continue; - } else { - goto error; - } - } - - message(MESS_DEBUG, "compress_prog is now %s\n", - newlog->compress_prog); - - } else if (!strcmp(start, "uncompresscmd")) { - *endtag = oldchar, start = endtag; - - freeLogItem (uncompress_prog); - - if (! - (newlog->uncompress_prog = - readPath(configFile, lineNum, "uncompress", - &start))) { - if (newlog != defConfig) { - logerror = 1; - continue; - } else { - goto error; - } - } - - if (access(newlog->uncompress_prog, X_OK)) { - message(MESS_ERROR, - "%s:%d uncompression program %s is not an executable file\n", - configFile, lineNum, newlog->uncompress_prog); - if (newlog != defConfig) { - logerror = 1; - continue; - } else { - goto error; - } - } - - message(MESS_DEBUG, "uncompress_prog is now %s\n", - newlog->uncompress_prog); - - } else if (!strcmp(start, "compressoptions")) { - char *options; - - if (newlog->compress_options_list) { - free(newlog->compress_options_list); - newlog->compress_options_list = NULL; - newlog->compress_options_count = 0; - } - - *endtag = oldchar, start = endtag; - if (! - (options = - readPath(configFile, lineNum, "compressoptions", - &start))) { - if (newlog != defConfig) { - logerror = 1; - continue; - } else { - goto error; - } - } - - if (poptParseArgvString(options, - &newlog->compress_options_count, - &newlog->compress_options_list)) { - message(MESS_ERROR, - "%s:%d invalid compression options\n", - configFile, lineNum); - free(options); - if (newlog != defConfig) { - logerror = 1; - continue; - } else { - goto error; - } - } - - message(MESS_DEBUG, "compress_options is now %s\n", - options); - free(options); - } else if (!strcmp(start, "compressext")) { - *endtag = oldchar, start = endtag; - - freeLogItem (compress_ext); - - if (! - (newlog->compress_ext = - readPath(configFile, lineNum, "compress-ext", - &start))) { - if (newlog != defConfig) { - logerror = 1; - continue; - } else { - goto error; - } - } - - message(MESS_DEBUG, "compress_ext is now %s\n", - newlog->compress_ext); - } else { - message(MESS_ERROR, "%s:%d unknown option '%s' " - "-- ignoring line\n", configFile, lineNum, start); - - *endtag = oldchar, start = endtag; - } - - while (isblank(*start)) - start++; - - if (*start != '\n') { - message(MESS_ERROR, "%s:%d unexpected text\n", configFile, - lineNum); - while (*start != '\n') - start++; - } - - lineNum++; - start++; - } else if (*start == '/' || *start == '"' || *start == '\'') { - if (newlog != defConfig) { - message(MESS_ERROR, "%s:%d unexpected log filename\n", - configFile, lineNum); - logerror = 1; - continue; - } - - /* If no compression options were found in config file, set - default values */ - if (!newlog->compress_prog) - newlog->compress_prog = strdup(COMPRESS_COMMAND); - if (!newlog->uncompress_prog) - newlog->uncompress_prog = strdup(UNCOMPRESS_COMMAND); - if (!newlog->compress_ext) - newlog->compress_ext = strdup(COMPRESS_EXT); - - /* Allocate a new logInfo structure and insert it into the logs - queue, copying the actual values from defConfig */ - if ((newlog = newLogInfo(defConfig)) == NULL) - goto error; - - endtag = start; - while (*endtag != '{' && *endtag != '\0') - endtag++; - if (*endtag != '{') { - message(MESS_ERROR, "%s:%d missing end of line\n", - configFile, lineNum); - } - *endtag = '\0'; - - if (poptParseArgvString(start, &argc, &argv)) { - message(MESS_ERROR, "%s:%d error parsing filename\n", - configFile, lineNum); - goto error; - } else if (argc < 1) { - message(MESS_ERROR, - "%s:%d { expected after log file name(s)\n", - configFile, lineNum); - goto error; - } - - newlog->files = NULL; - newlog->numFiles = 0; - for (argNum = 0; argNum < argc && logerror != 1; argNum++) { - if (globerr_msg) { - free(globerr_msg); - globerr_msg = NULL; - } - - rc = glob(argv[argNum], GLOB_NOCHECK, globerr, - &globResult); - if (rc == GLOB_ABORTED) { - if (newlog->flags & LOG_FLAG_MISSINGOK) - continue; - - /* We don't yet know whether this stanza has "missingok" - * set, so store the error message for later. */ - rc = asprintf(&globerr_msg, "%s:%d glob failed for %s: %s\n", - configFile, lineNum, argv[argNum], strerror(glob_errno)); - if (rc == -1) - globerr_msg = NULL; - - globResult.gl_pathc = 0; - } - - newlog->files = - realloc(newlog->files, - sizeof(*newlog->files) * (newlog->numFiles + - globResult. - gl_pathc)); - - for (i = 0; i < globResult.gl_pathc; i++) { - /* if we glob directories we can get false matches */ - if (!lstat(globResult.gl_pathv[i], &sb) && - S_ISDIR(sb.st_mode)) - continue; - - for (log = logs.tqh_first; log != NULL; - log = log->list.tqe_next) { - for (k = 0; k < log->numFiles; k++) { - if (!strcmp(log->files[k], - globResult.gl_pathv[i])) { - message(MESS_ERROR, - "%s:%d duplicate log entry for %s\n", - configFile, lineNum, - globResult.gl_pathv[i]); - logerror = 1; - goto duperror; - } + break; + case STATE_SKIP_CONFIG: + if (*start == '}') { + state = STATE_DEFAULT; + freeTailLogs(1); + newlog = defConfig; } - } - - newlog->files[newlog->numFiles] = - strdup(globResult.gl_pathv[i]); - newlog->numFiles++; - } -duperror: - globfree(&globResult); - } - - newlog->pattern = strdup(start); - - if (!logerror) - message(MESS_DEBUG, "reading config info for %s\n", start); - - free(argv); - - start = endtag + 1; - } else if (*start == '}') { - if (newlog == defConfig) { - message(MESS_ERROR, "%s:%d unexpected }\n", configFile, - lineNum); - goto error; - } - if (globerr_msg) { - if (!(newlog->flags & LOG_FLAG_MISSINGOK)) - message(MESS_ERROR, globerr_msg); - free(globerr_msg); - globerr_msg = NULL; - if (!(newlog->flags & LOG_FLAG_MISSINGOK)) - return 1; - } - - if (newlog->oldDir) { - for (i = 0; i < newlog->numFiles; i++) { - char *ld; - dirName = ourDirName(newlog->files[i]); - if (stat(dirName, &sb2)) { - message(MESS_ERROR, - "%s:%d error verifying log file " - "path %s: %s\n", configFile, lineNum, - dirName, strerror(errno)); - free(dirName); - goto error; - } - ld = alloca(strlen(dirName) + strlen(newlog->oldDir) + - 2); - sprintf(ld, "%s/%s", dirName, newlog->oldDir); - free(dirName); - - if (newlog->oldDir[0] != '/') - dirName = ld; - else - dirName = newlog->oldDir; - if (stat(dirName, &sb)) { - message(MESS_ERROR, "%s:%d error verifying olddir " - "path %s: %s\n", configFile, lineNum, - dirName, strerror(errno)); - goto error; - } - - if (sb.st_dev != sb2.st_dev) { - message(MESS_ERROR, - "%s:%d olddir %s and log file %s " - "are on different devices\n", configFile, - lineNum, newlog->oldDir, newlog->files[i]); - goto error; - } - } - } - - newlog = defConfig; - - start++; - while (isblank(*start)) - start++; - - if (*start != '\n') { - message(MESS_ERROR, "%s:%d, unexpected text after {\n", - configFile, lineNum); - } - } else { - message(MESS_ERROR, "%s:%d lines must begin with a keyword " - "or a filename (possibly in double quotes)\n", - configFile, lineNum); - - while (*start != '\n') - start++; + else { + if ((key = isolateWord(&start, &buf, length)) == NULL) + continue; + if ( + (strcmp(key, "postrotate") == 0) || + (strcmp(key, "prerotate") == 0) || + (strcmp(key, "firstrotate") == 0) || + (strcmp(key, "lastrotate") == 0) + ) { + state = STATE_LOAD_SCRIPT | STATE_SKIP_CONFIG; + } + else { + state = STATE_SKIP_LINE | STATE_SKIP_CONFIG; + } + free(key); + key = NULL; + } + break; + } + if (key) { + free(key); + key = NULL; + } + if (*start == '\n') { lineNum++; - start++; } + } if (scriptStart) { @@ -1521,11 +1455,14 @@ configFile); goto error; } - munmap(buf, (size_t)(length + 2)); + + munmap(buf, (size_t) length); close(fd); return 0; error: - munmap(buf, (size_t)(length + 2)); + if (key) + free(key); + munmap(buf, (size_t) length); close(fd); return 1; }