22898a
diff --git a/config.c b/config.c
22898a
index e6b6a53..e9992e3 100644
22898a
--- a/config.c
22898a
+++ b/config.c
22898a
@@ -220,6 +220,61 @@ static char *readPath(const char *configFile, int lineNum, char *key,
22898a
 	return NULL;
22898a
 }
22898a
 
22898a
+static int readModeUidGid(const char *configFile, int lineNum, char *key,
22898a
+							const char *directive, mode_t *mode, uid_t *uid,
22898a
+							gid_t *gid) {
22898a
+	char u[200], g[200];
22898a
+	int m;
22898a
+	char tmp;
22898a
+	int rc;
22898a
+	struct group *group;
22898a
+	struct passwd *pw = NULL;
22898a
+
22898a
+	rc = sscanf(key, "%o %199s %199s%c", &m, u, g, &tmp);
22898a
+	/* We support 'key <owner> <group> notation now */
22898a
+	if (rc == 0) {
22898a
+		rc = sscanf(key, "%199s %199s%c", u, g, &tmp);
22898a
+		/* Simulate that we have read mode and keep the default value. */
22898a
+		if (rc > 0) {
22898a
+			m = *mode;
22898a
+			rc += 1;
22898a
+		}
22898a
+	}
22898a
+
22898a
+	if (rc == 4) {
22898a
+		message(MESS_ERROR, "%s:%d extra arguments for "
22898a
+			"%s\n", configFile, lineNum, directive);
22898a
+		return -1;
22898a
+	}
22898a
+
22898a
+	if (rc > 0) {
22898a
+		*mode = m;
22898a
+	}
22898a
+
22898a
+	if (rc > 1) {
22898a
+		pw = getpwnam(u);
22898a
+		if (!pw) {
22898a
+			message(MESS_ERROR, "%s:%d unknown user '%s'\n",
22898a
+				configFile, lineNum, u);
22898a
+			return -1;
22898a
+		}
22898a
+		*uid = pw->pw_uid;
22898a
+		endpwent();
22898a
+	}
22898a
+	if (rc > 2) {
22898a
+		group = getgrnam(g);
22898a
+		if (!group) {
22898a
+			message(MESS_ERROR, "%s:%d unknown group '%s'\n",
22898a
+				configFile, lineNum, g);
22898a
+			return -1;
22898a
+		}
22898a
+		*gid = group->gr_gid;
22898a
+		endgrent();
22898a
+	}
22898a
+
22898a
+	return 0;
22898a
+}
22898a
+
22898a
 static char *readAddress(const char *configFile, int lineNum, char *key,
22898a
 			 char **startPtr, char **buf, size_t length)
22898a
 {
22898a
@@ -249,6 +304,55 @@ static char *readAddress(const char *configFile, int lineNum, char *key,
22898a
 	return NULL;
22898a
 }
22898a
 
22898a
+static int do_mkdir(const char *path, mode_t mode, uid_t uid, gid_t gid) {
22898a
+	struct stat sb;
22898a
+
22898a
+	if (stat(path, &sb) != 0) {
22898a
+		if (mkdir(path, mode) != 0 && errno != EEXIST) {
22898a
+			message(MESS_ERROR, "error creating %s: %s\n",
22898a
+				path, strerror(errno));
22898a
+			return -1;
22898a
+		}
22898a
+		if ((uid != sb.st_uid || gid != sb.st_gid) && 
22898a
+			chown(path, uid, gid)) {
22898a
+			message(MESS_ERROR, "error setting owner of %s to uid %d and gid %d: %s\n",
22898a
+				path, uid, gid, strerror(errno));
22898a
+			return -1;
22898a
+		}
22898a
+    }
22898a
+	else if (!S_ISDIR(sb.st_mode)) {
22898a
+		message(MESS_ERROR, "path %s already exists, but it is not a directory\n",
22898a
+			path);
22898a
+		errno = ENOTDIR;
22898a
+		return -1;
22898a
+	}
22898a
+
22898a
+	return 0;
22898a
+}
22898a
+
22898a
+static int mkpath(const char *path, mode_t mode, uid_t uid, gid_t gid) {
22898a
+	char *pp;
22898a
+	char *sp;
22898a
+	int rv;
22898a
+	char *copypath = strdup(path);
22898a
+
22898a
+	rv = 0;
22898a
+	pp = copypath;
22898a
+	while (rv == 0 && (sp = strchr(pp, '/')) != 0) {
22898a
+		if (sp != pp) {
22898a
+			*sp = '\0';
22898a
+			rv = do_mkdir(copypath, mode, uid, gid);
22898a
+			*sp = '/';
22898a
+		}
22898a
+		pp = sp + 1;
22898a
+	}
22898a
+	if (rv == 0) {
22898a
+		rv = do_mkdir(path, mode, uid, gid);
22898a
+	}
22898a
+	free(copypath);
22898a
+	return rv;
22898a
+}
22898a
+
22898a
 static int checkFile(const char *fname)
22898a
 {
22898a
 	int i;
22898a
@@ -330,6 +434,9 @@ static void copyLogInfo(struct logInfo *to, struct logInfo *from)
22898a
     to->createGid = from->createGid;
22898a
     to->suUid = from->suUid;
22898a
     to->suGid = from->suGid;
22898a
+    to->olddirMode = from->olddirMode;
22898a
+    to->olddirUid = from->olddirUid;
22898a
+    to->olddirGid = from->olddirGid;
22898a
     if (from->compress_options_count) {
22898a
         poptDupArgv(from->compress_options_count, from->compress_options_list, 
22898a
                     &to->compress_options_count,  &to->compress_options_list);
22898a
@@ -539,6 +646,11 @@ int readAllConfigPaths(const char **paths)
22898a
 		.createMode = NO_MODE,
22898a
 		.createUid = NO_UID,
22898a
 		.createGid = NO_GID,
22898a
+		.olddirMode = NO_MODE,
22898a
+		.olddirUid = NO_UID,
22898a
+		.olddirGid = NO_GID,
22898a
+		.suUid = NO_UID,
22898a
+		.suGid = NO_GID,
22898a
 		.compress_options_list = NULL,
22898a
 		.compress_options_count = 0
22898a
     };
22898a
@@ -579,13 +691,19 @@ static int globerr(const char *pathname, int theerr)
22898a
 		free(newlog->what); \
22898a
 		newlog->what = NULL; \
22898a
 	} while (0);
22898a
+#define RAISE_ERROR() \
22898a
+	if (newlog != defConfig) { \
22898a
+		state = STATE_ERROR; \
22898a
+		continue; \
22898a
+	} else { \
22898a
+		goto error; \
22898a
+	}
22898a
 #define MAX_NESTING 16U
22898a
 
22898a
 static int readConfigFile(const char *configFile, struct logInfo *defConfig)
22898a
 {
22898a
     int fd;
22898a
     char *buf, *endtag, *key = NULL;
22898a
-    char foo;
22898a
     off_t length;
22898a
     int lineNum = 1;
22898a
     unsigned long long multiplier;
22898a
@@ -595,11 +713,8 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig)
22898a
     struct logInfo *newlog = defConfig;
22898a
     char *start, *chptr;
22898a
     char *dirName;
22898a
-    struct group *group;
22898a
     struct passwd *pw = NULL;
22898a
     int rc;
22898a
-    char createOwner[200], createGroup[200];
22898a
-    int createMode;
22898a
     struct stat sb, sb2;
22898a
     glob_t globResult;
22898a
     const char **argv;
22898a
@@ -611,6 +726,7 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig)
22898a
 	static unsigned recursion_depth = 0U;
22898a
 	char *globerr_msg = NULL;
22898a
 	int in_config = 0;
22898a
+	int rv;
22898a
 	struct flock fd_lock = {
22898a
 		.l_start = 0,
22898a
 		.l_len = 0,
22898a
@@ -807,53 +923,22 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig)
22898a
 				} else if (!strcmp(key, "maillast")) {
22898a
 					newlog->flags &= ~LOG_FLAG_MAILFIRST;
22898a
 				} else if (!strcmp(key, "su")) {
22898a
+					mode_t tmp_mode = NO_MODE;
22898a
 					free(key);
22898a
 					key = isolateLine(&start, &buf, length);
22898a
 					if (key == NULL)
22898a
 						continue;
22898a
 
22898a
-					rc = sscanf(key, "%199s %199s%c", createOwner,
22898a
-								createGroup, &foo;;
22898a
-					if (rc == 3) {
22898a
-						message(MESS_ERROR, "%s:%d extra arguments for "
22898a
-							"su\n", configFile, lineNum);
22898a
-						if (newlog != defConfig) {
22898a
-							state = STATE_ERROR;
22898a
-							continue;
22898a
-						} else {
22898a
-							goto error;
22898a
-						}
22898a
+					rv = readModeUidGid(configFile, lineNum, key, "su", 
22898a
+								   &tmp_mode, &newlog->suUid,
22898a
+								   &newlog->suGid);
22898a
+					if (rv == -1) {
22898a
+						RAISE_ERROR();
22898a
 					}
22898a
-
22898a
-					if (rc > 0) {
22898a
-						pw = getpwnam(createOwner);
22898a
-						if (!pw) {
22898a
-							message(MESS_ERROR, "%s:%d unknown user '%s'\n",
22898a
-								configFile, lineNum, createOwner);
22898a
-							if (newlog != defConfig) {
22898a
-								state = STATE_ERROR;
22898a
-								continue;
22898a
-							} else {
22898a
-								goto error;
22898a
-							}
22898a
-						}
22898a
-						newlog->suUid = pw->pw_uid;
22898a
-						endpwent();
22898a
-					}
22898a
-					if (rc > 1) {
22898a
-						group = getgrnam(createGroup);
22898a
-						if (!group) {
22898a
-							message(MESS_ERROR, "%s:%d unknown group '%s'\n",
22898a
-								configFile, lineNum, createGroup);
22898a
-							if (newlog != defConfig) {
22898a
-								state = STATE_ERROR;
22898a
-								continue;
22898a
-							} else {
22898a
-								goto error;
22898a
-							}
22898a
-						}
22898a
-						newlog->suGid = group->gr_gid;
22898a
-						endgrent();
22898a
+					else if (tmp_mode != NO_MODE) {
22898a
+						message(MESS_ERROR, "%s:%d extra arguments for "
22898a
+								"su\n", configFile, lineNum);
22898a
+						RAISE_ERROR();
22898a
 					}
22898a
 
22898a
 					newlog->flags |= LOG_FLAG_SU;
22898a
@@ -863,65 +948,30 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig)
22898a
 					if (key == NULL)
22898a
 						continue;
22898a
 
22898a
-					rc = sscanf(key, "%o %199s %199s%c", &createMode,
22898a
-							createOwner, createGroup, &foo;;
22898a
-					/* We support 'create <owner> <group> notation now */
22898a
-					if (rc == 0) {
22898a
-						rc = sscanf(key, "%199s %199s%c",
22898a
-								createOwner, createGroup, &foo;;
22898a
-						/* Simulate that we have read createMode and se it
22898a
-						 * to NO_MODE. */
22898a
-						if (rc > 0) {
22898a
-							createMode = NO_MODE;
22898a
-							rc += 1;
22898a
-						}
22898a
-					}
22898a
-					if (rc == 4) {
22898a
-						message(MESS_ERROR, "%s:%d extra arguments for "
22898a
-							"create\n", configFile, lineNum);
22898a
-						if (newlog != defConfig) {
22898a
-							state = STATE_ERROR;
22898a
-							continue;
22898a
-						} else {
22898a
-							goto error;
22898a
-						}
22898a
+					rv = readModeUidGid(configFile, lineNum, key, "create",
22898a
+								   &newlog->createMode, &newlog->createUid,
22898a
+								   &newlog->createGid);
22898a
+					if (rv == -1) {
22898a
+						RAISE_ERROR();
22898a
 					}
22898a
 
22898a
-					if (rc > 0)
22898a
-						newlog->createMode = createMode;
22898a
-
22898a
-					if (rc > 1) {
22898a
-						pw = getpwnam(createOwner);
22898a
-						if (!pw) {
22898a
-							message(MESS_ERROR, "%s:%d unknown user '%s'\n",
22898a
-								configFile, lineNum, createOwner);
22898a
-							if (newlog != defConfig) {
22898a
-								state = STATE_ERROR;
22898a
-								continue;
22898a
-							} else {
22898a
-								goto error;
22898a
-							}
22898a
-						}
22898a
-						newlog->createUid = pw->pw_uid;
22898a
-						endpwent();
22898a
-					}
22898a
-					if (rc > 2) {
22898a
-						group = getgrnam(createGroup);
22898a
-						if (!group) {
22898a
-							message(MESS_ERROR, "%s:%d unknown group '%s'\n",
22898a
-								configFile, lineNum, createGroup);
22898a
-							if (newlog != defConfig) {
22898a
-								state = STATE_ERROR;
22898a
-								continue;
22898a
-							} else {
22898a
-								goto error;
22898a
-							}
22898a
-						}
22898a
-						newlog->createGid = group->gr_gid;
22898a
-						endgrent();
22898a
+					newlog->flags |= LOG_FLAG_CREATE;
22898a
+				} else if (!strcmp(key, "createolddir")) {
22898a
+					free(key);
22898a
+					key = isolateLine(&start, &buf, length);
22898a
+					if (key == NULL)
22898a
+						continue;
22898a
+
22898a
+					rv = readModeUidGid(configFile, lineNum, key, "createolddir",
22898a
+								   &newlog->olddirMode, &newlog->olddirUid,
22898a
+								   &newlog->olddirGid);
22898a
+					if (rv == -1) {
22898a
+						RAISE_ERROR();
22898a
 					}
22898a
 
22898a
-					newlog->flags |= LOG_FLAG_CREATE;
22898a
+					newlog->flags |= LOG_FLAG_OLDDIRCREATE;
22898a
+				} else if (!strcmp(key, "nocreateolddir")) {
22898a
+					newlog->flags &= ~LOG_FLAG_OLDDIRCREATE;
22898a
 				} else if (!strcmp(key, "nocreate")) {
22898a
 					newlog->flags &= ~LOG_FLAG_CREATE;
22898a
 				} else if (!strcmp(key, "size") || !strcmp(key, "minsize") ||
22898a
@@ -945,12 +995,7 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig)
22898a
 							free(opt);
22898a
 							message(MESS_ERROR, "%s:%d unknown unit '%c'\n",
22898a
 								configFile, lineNum, key[l]);
22898a
-							if (newlog != defConfig) {
22898a
-								state = STATE_ERROR;
22898a
-								continue;
22898a
-							} else {
22898a
-								goto error;
22898a
-							}
22898a
+							RAISE_ERROR();
22898a
 						} else {
22898a
 							multiplier = 1;
22898a
 						}
22898a
@@ -960,12 +1005,7 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig)
22898a
 							message(MESS_ERROR, "%s:%d bad size '%s'\n",
22898a
 								configFile, lineNum, key);
22898a
 							free(opt);
22898a
-							if (newlog != defConfig) {
22898a
-								state = STATE_ERROR;
22898a
-								continue;
22898a
-							} else {
22898a
-								goto error;
22898a
-							}
22898a
+							RAISE_ERROR();
22898a
 						}
22898a
 						if (!strncmp(opt, "size", 4)) {
22898a
 						  newlog->criterium = ROT_SIZE;
22898a
@@ -1015,12 +1055,7 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig)
22898a
 							message(MESS_ERROR,
22898a
 								"%s:%d bad rotation count '%s'\n",
22898a
 								configFile, lineNum, key);
22898a
-							if (newlog != defConfig) {
22898a
-								state = STATE_ERROR;
22898a
-								continue;
22898a
-							} else {
22898a
-								goto error;
22898a
-							}
22898a
+							RAISE_ERROR();
22898a
 						}
22898a
 					}
22898a
 					else continue;
22898a
@@ -1034,12 +1069,7 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig)
22898a
 						if (*chptr || newlog->logStart < 0) {
22898a
 							message(MESS_ERROR, "%s:%d bad start count '%s'\n",
22898a
 								configFile, lineNum, key);
22898a
-							if (newlog != defConfig) {
22898a
-								state = STATE_ERROR;
22898a
-								continue;
22898a
-							} else {
22898a
-								goto error;
22898a
-							}
22898a
+							RAISE_ERROR();
22898a
 						}
22898a
 					}
22898a
 					else continue;
22898a
@@ -1052,12 +1082,7 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig)
22898a
 						if (*chptr || newlog->rotateAge < 0) {
22898a
 							message(MESS_ERROR, "%s:%d bad maximum age '%s'\n",
22898a
 								configFile, lineNum, start);
22898a
-							if (newlog != defConfig) {
22898a
-								state = STATE_ERROR;
22898a
-								continue;
22898a
-							} else {
22898a
-								goto error;
22898a
-							}
22898a
+							RAISE_ERROR();
22898a
 						}
22898a
 					}
22898a
 					else continue;
22898a
@@ -1069,12 +1094,7 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig)
22898a
 					freeLogItem(logAddress);
22898a
 					if (!(newlog->logAddress = readAddress(configFile, lineNum,
22898a
 										"mail", &start, &buf, length))) {
22898a
-						if (newlog != defConfig) {
22898a
-						state = STATE_ERROR;
22898a
-						continue;
22898a
-						} else {
22898a
-						goto error;
22898a
-						}
22898a
+						RAISE_ERROR();
22898a
 					}
22898a
 					else continue;
22898a
 				} else if (!strcmp(key, "nomail")) {
22898a
@@ -1177,31 +1197,8 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig)
22898a
 
22898a
 					if (!(newlog->oldDir = readPath(configFile, lineNum,
22898a
 									"olddir", &start, &buf, length))) {
22898a
-						if (newlog != defConfig) {
22898a
-							state = STATE_ERROR;
22898a
-							continue;
22898a
-						} else {
22898a
-							goto error;
22898a
-						}
22898a
-					}
22898a
-
22898a
-#if 0
22898a
-					if (stat(newlog->oldDir, &sb)) {
22898a
-						message(MESS_ERROR, "%s:%d error verifying olddir "
22898a
-							"path %s: %s\n", configFile, lineNum,
22898a
-							newlog->oldDir, strerror(errno));
22898a
-						free(newlog->oldDir);
22898a
-						goto error;
22898a
+						RAISE_ERROR();
22898a
 					}
22898a
-
22898a
-					if (!S_ISDIR(sb.st_mode)) {
22898a
-						message(MESS_ERROR, "%s:%d olddir path %s is not a "
22898a
-							"directory\n", configFile, lineNum,
22898a
-							newlog->oldDir);
22898a
-						free(newlog->oldDir);
22898a
-						goto error;
22898a
-					}
22898a
-#endif
22898a
 					message(MESS_DEBUG, "olddir is now %s\n", newlog->oldDir);
22898a
 				} else if (!strcmp(key, "extension")) {
22898a
 					if ((key = isolateValue
22898a
@@ -1222,24 +1219,14 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig)
22898a
 					if (!
22898a
 						(newlog->compress_prog =
22898a
 							readPath(configFile, lineNum, "compress", &start, &buf, length))) {
22898a
-						if (newlog != defConfig) {
22898a
-							state = STATE_ERROR;
22898a
-							continue;
22898a
-						} else {
22898a
-							goto error;
22898a
-						}
22898a
+						RAISE_ERROR();
22898a
 					}
22898a
 
22898a
 					if (access(newlog->compress_prog, X_OK)) {
22898a
 						message(MESS_ERROR,
22898a
 							"%s:%d compression program %s is not an executable file\n",
22898a
 							configFile, lineNum, newlog->compress_prog);
22898a
-						if (newlog != defConfig) {
22898a
-							state = STATE_ERROR;
22898a
-							continue;
22898a
-						} else {
22898a
-							goto error;
22898a
-						}
22898a
+						RAISE_ERROR();
22898a
 					}
22898a
 
22898a
 					message(MESS_DEBUG, "compress_prog is now %s\n",
22898a
@@ -1252,24 +1239,14 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig)
22898a
 						(newlog->uncompress_prog =
22898a
 							readPath(configFile, lineNum, "uncompress",
22898a
 								&start, &buf, length))) {
22898a
-						if (newlog != defConfig) {
22898a
-							state = STATE_ERROR;
22898a
-							continue;
22898a
-						} else {
22898a
-							goto error;
22898a
-						}
22898a
+						RAISE_ERROR();
22898a
 					}
22898a
 
22898a
 					if (access(newlog->uncompress_prog, X_OK)) {
22898a
 						message(MESS_ERROR,
22898a
 							"%s:%d uncompression program %s is not an executable file\n",
22898a
 							configFile, lineNum, newlog->uncompress_prog);
22898a
-						if (newlog != defConfig) {
22898a
-							state = STATE_ERROR;
22898a
-							continue;
22898a
-						} else {
22898a
-							goto error;
22898a
-						}
22898a
+						RAISE_ERROR();
22898a
 					}
22898a
 
22898a
 					message(MESS_DEBUG, "uncompress_prog is now %s\n",
22898a
@@ -1285,12 +1262,7 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig)
22898a
 					}
22898a
 
22898a
 					if (!(options = isolateLine(&start, &buf, length))) {
22898a
-						if (newlog != defConfig) {
22898a
-							state = STATE_ERROR;
22898a
-							continue;
22898a
-						} else {
22898a
-							goto error;
22898a
-						}
22898a
+						RAISE_ERROR();
22898a
 					}
22898a
 
22898a
 					if (poptParseArgvString(options,
22898a
@@ -1300,12 +1272,7 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig)
22898a
 							"%s:%d invalid compression options\n",
22898a
 							configFile, lineNum);
22898a
 						free(options);
22898a
-						if (newlog != defConfig) {
22898a
-							state = STATE_ERROR;
22898a
-							continue;
22898a
-						} else {
22898a
-							goto error;
22898a
-						}
22898a
+						RAISE_ERROR();
22898a
 					}
22898a
 
22898a
 					message(MESS_DEBUG, "compress_options is now %s\n",
22898a
@@ -1318,12 +1285,7 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig)
22898a
 						(newlog->compress_ext =
22898a
 							readPath(configFile, lineNum, "compress-ext",
22898a
 								&start, &buf, length))) {
22898a
-						if (newlog != defConfig) {
22898a
-							state = STATE_ERROR;
22898a
-							continue;
22898a
-						} else {
22898a
-							goto error;
22898a
-						}
22898a
+						RAISE_ERROR();
22898a
 					}
22898a
 
22898a
 					message(MESS_DEBUG, "compress_ext is now %s\n",
22898a
@@ -1484,45 +1446,57 @@ static int readConfigFile(const char *configFile, struct logInfo *defConfig)
22898a
 				globerr_msg = NULL;
22898a
 				if (!(newlog->flags & LOG_FLAG_MISSINGOK))
22898a
 					goto error;
22898a
-				}
22898a
+			}
22898a
 
22898a
-				if (newlog->oldDir) {
22898a
+			if (newlog->oldDir) {
22898a
 				for (i = 0; i < newlog->numFiles; i++) {
22898a
 					char *ld;
22898a
+					int rv;
22898a
 					dirName = ourDirName(newlog->files[i]);
22898a
 					if (stat(dirName, &sb2)) {
22898a
-					message(MESS_ERROR,
22898a
-						"%s:%d error verifying log file "
22898a
-						"path %s: %s\n", configFile, lineNum,
22898a
-						dirName, strerror(errno));
22898a
-					free(dirName);
22898a
-					goto error;
22898a
+						message(MESS_ERROR,
22898a
+							"%s:%d error verifying log file "
22898a
+							"path %s: %s\n", configFile, lineNum,
22898a
+							dirName, strerror(errno));
22898a
+						free(dirName);
22898a
+						goto error;
22898a
 					}
22898a
-					ld = alloca(strlen(dirName) + strlen(newlog->oldDir) +
22898a
-						2);
22898a
+					ld = alloca(strlen(dirName) + strlen(newlog->oldDir) + 2);
22898a
 					sprintf(ld, "%s/%s", dirName, newlog->oldDir);
22898a
 					free(dirName);
22898a
 
22898a
-					if (newlog->oldDir[0] != '/')
22898a
-					dirName = ld;
22898a
-					else
22898a
-					dirName = newlog->oldDir;
22898a
-					if (stat(dirName, &sb)) {
22898a
-					message(MESS_ERROR, "%s:%d error verifying olddir "
22898a
-						"path %s: %s\n", configFile, lineNum,
22898a
-						dirName, strerror(errno));
22898a
-					goto error;
22898a
+					if (newlog->oldDir[0] != '/') {
22898a
+						dirName = ld;
22898a
+					}
22898a
+					else {
22898a
+						dirName = newlog->oldDir;
22898a
+					}
22898a
+
22898a
+					rv = stat(dirName, &sb);
22898a
+					if (rv) {
22898a
+						if (errno == ENOENT && newlog->flags & LOG_FLAG_OLDDIRCREATE) {
22898a
+							if (mkpath(dirName, newlog->olddirMode,
22898a
+								newlog->olddirUid, newlog->olddirGid)) {
22898a
+								goto error;
22898a
+							}
22898a
+						}
22898a
+						else {
22898a
+							message(MESS_ERROR, "%s:%d error verifying olddir "
22898a
+								"path %s: %s\n", configFile, lineNum,
22898a
+								dirName, strerror(errno));
22898a
+							goto error;
22898a
+						}
22898a
 					}
22898a
 
22898a
 					if (sb.st_dev != sb2.st_dev) {
22898a
-					message(MESS_ERROR,
22898a
-						"%s:%d olddir %s and log file %s "
22898a
-						"are on different devices\n", configFile,
22898a
-						lineNum, newlog->oldDir, newlog->files[i]);
22898a
-					goto error;
22898a
+						message(MESS_ERROR,
22898a
+							"%s:%d olddir %s and log file %s "
22898a
+							"are on different devices\n", configFile,
22898a
+							lineNum, newlog->oldDir, newlog->files[i]);
22898a
+						goto error;
22898a
 					}
22898a
 				}
22898a
-				}
22898a
+			}
22898a
 
22898a
 				newlog = defConfig;
22898a
 				state = STATE_DEFINITION_END;
22898a
diff --git a/logrotate.8 b/logrotate.8
22898a
index 8cb9c2f..2cd2370 100644
22898a
--- a/logrotate.8
22898a
+++ b/logrotate.8
22898a
@@ -216,6 +216,16 @@ file for the omitted attributes. This option can be disabled using the
22898a
 \fBnocreate\fR option.
22898a
 
22898a
 .TP
22898a
+\fBcreateolddir \fImode\fR \fIowner\fR \fIgroup\fR
22898a
+If the directory specified by \fBolddir\fR directive does not exist, it is
22898a
+created. \fImode\fR specifies the mode for the \fBolddir\fR directory
22898a
+in octal (the same as \fBchmod\fR(2)), \fIowner\fR specifies the user name
22898a
+who will own the \fBolddir\fR directory, and \fIgroup\fR specifies the group
22898a
+the \fBolddir\fR directory will belong to. This option can be disabled using the
22898a
+\fBnocreateolddir\fR option.
22898a
+
22898a
+
22898a
+.TP
22898a
 \fBdaily\fR
22898a
 Log files are rotated every day.
22898a
 
22898a
@@ -350,6 +360,10 @@ Do not truncate the original log file in place after creating a copy
22898a
 New log files are not created (this overrides the \fBcreate\fR option).
22898a
 
22898a
 .TP
22898a
+\fBnocreateolddir\fR
22898a
+\fBolddir\fR directory is not created by logrotate when it does not exist.
22898a
+
22898a
+.TP
22898a
 \fBnodelaycompress\fR
22898a
 Do not postpone compression of the previous log file to the next rotation cycle
22898a
 (this overrides the \fBdelaycompress\fR option).
22898a
diff --git a/logrotate.h b/logrotate.h
22898a
index 813418e..cf42703 100644
22898a
--- a/logrotate.h
22898a
+++ b/logrotate.h
22898a
@@ -20,6 +20,7 @@
22898a
 #define LOG_FLAG_SHRED		(1 << 10)
22898a
 #define LOG_FLAG_SU			(1 << 11)
22898a
 #define LOG_FLAG_DATEYESTERDAY	(1 << 12)
22898a
+#define LOG_FLAG_OLDDIRCREATE	(1 << 13)
22898a
 
22898a
 #define NO_MODE ((mode_t) -1)
22898a
 #define NO_UID  ((uid_t) -1)
22898a
@@ -55,6 +56,9 @@ struct logInfo {
22898a
     gid_t createGid;
22898a
     uid_t suUid;			/* switch user to this uid and group to this gid */
22898a
     gid_t suGid;
22898a
+    mode_t olddirMode;
22898a
+    uid_t olddirUid;
22898a
+    uid_t olddirGid;
22898a
     /* these are at the end so they end up nil */
22898a
     const char **compress_options_list;
22898a
     int compress_options_count;
22898a
diff --git a/test/test b/test/test
22898a
index 25b76a6..e9ce46f 100755
22898a
--- a/test/test
22898a
+++ b/test/test
22898a
@@ -453,9 +453,15 @@ cleanup 13
22898a
 # ------------------------------- Test 13 ------------------------------------
22898a
 preptest test.log 13 1 0
22898a
 rm -rf testdir
22898a
-mkdir testdir
22898a
 $RLR test-config.13 --force
22898a
 
22898a
+ls -l|grep testdir|grep "drwx------." 2>/dev/null >/dev/null
22898a
+if [ $? != 0 ]; then
22898a
+	echo "testdir should have mode 2700, but it has:"
22898a
+	ls -l|grep testdir
22898a
+	exit 3
22898a
+fi
22898a
+
22898a
 checkoutput <
22898a
 test.log 0
22898a
 testdir/test.log.1 0 zero
22898a
@@ -888,13 +894,15 @@ $RLR test-config.35 --force
22898a
 
22898a
 getfacl test.log|grep "user:nobody:rwx" >/dev/null
22898a
 if [ $? != 0 ]; then
22898a
-	echo "test.log must not contain user:nobody:rwx"
22898a
+	echo "test.log must contain user:nobody:rwx"
22898a
+	getfacl test.log
22898a
 	exit 3
22898a
 fi
22898a
 
22898a
 getfacl test.log.1|grep "user:nobody:rwx" >/dev/null
22898a
 if [ $? != 0 ]; then
22898a
 	echo "test.log.1 must contain user:nobody:rwx"
22898a
+	getfacl test.log.1
22898a
 	exit 3
22898a
 fi
22898a
 
22898a
diff --git a/test/test-config.13.in b/test/test-config.13.in
22898a
index 31a29ef..dc2efd5 100644
22898a
--- a/test/test-config.13.in
22898a
+++ b/test/test-config.13.in
22898a
@@ -4,4 +4,5 @@ create
22898a
     monthly
22898a
     rotate 1
22898a
     olddir &DIR&/testdir
22898a
+    createolddir 700 &USER& &GROUP&
22898a
 }