logrotate/logrotate-3.7.9-config.patch
Jan Kaluza 3ad5b60452 - fix #661181 - fixed SIGBUS when config file is empty or 4096 bytes
- fix #666677 - preserve ACLs when rotating files
2011-01-05 11:47:45 +01:00

2025 lines
54 KiB
Diff

Index: config.c
===================================================================
--- config.c (revision 290)
+++ config.c (working copy)
@@ -1,5 +1,9 @@
#include <sys/queue.h>
+#ifdef _ALLOCA_H
#include <alloca.h>
+#else
+#include <limits.h>
+#endif
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
@@ -30,13 +34,55 @@
#define REALLOC_STEP 10
-#if defined(SunOS)
-#include <syslimits.h>
+#if defined(SunOS)
+#include <limits.h>
#if !defined(isblank)
#define isblank(c) ( (c) == ' ' || (c) == '\t' ) ? 1 : 0
#endif
#endif
+#if !defined(asprintf)
+#include <stdarg.h>
+
+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;
}