[prev in list] [next in list] [prev in thread] [next in thread] 

List:       busybox
Subject:    [PATCH] syslogd: try to handle ENOSPC during writes
From:       Joshua Judson Rosen <jrosen () harvestai ! com>
Date:       2014-05-23 5:50:16
Message-ID: 1400824216-14483-1-git-send-email-jrosen () harvestai ! com
[Download RAW message or body]

Unlink the oldest rotated-out logfile
and then try writing the rest of the msg
if there's a chance that the retry will succeed.

Signed-off-by: Joshua Judson Rosen <jrosen@harvestai.com>
---
 sysklogd/Config.src |    9 +++++
 sysklogd/syslogd.c  |  112 ++++++++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 112 insertions(+), 9 deletions(-)

diff --git a/sysklogd/Config.src b/sysklogd/Config.src
index 7938f6f..eefd261 100644
--- a/sysklogd/Config.src
+++ b/sysklogd/Config.src
@@ -50,6 +50,15 @@ config FEATURE_LOGROTATE_CMD
 	  an external command to call in order to rotate
 	  logs when they pass the rotation-threshold.
 
+config FEATURE_LOGROTATE_ENOSPC
+	bool "Support emergency pruning on ENOSPC"
+	default n
+	depends on FEATURE_ROTATE_LOGFILE
+	help
+	  This makes the log-writing logic for each
+	  logfile try to handle ENOSPC errors by
+	  discarding the oldest already-rotated logfiles.
+
 config FEATURE_LOGROTATE_TIMESTAMPS
 	bool "Suffix rotated logfile names with timestamps"
 	default n
diff --git a/sysklogd/syslogd.c b/sysklogd/syslogd.c
index fc6b097..cde5748 100644
--- a/sysklogd/syslogd.c
+++ b/sysklogd/syslogd.c
@@ -603,6 +603,32 @@ static void kmsg_cleanup(void) {}
 static void log_to_kmsg(int pri UNUSED_PARAM, const char *msg UNUSED_PARAM) {}
 #endif /* FEATURE_KMSG_SYSLOG */
 
+#if ENABLE_FEATURE_LOGROTATE_TIMESTAMPS || ENABLE_FEATURE_LOGROTATE_ENOSPC
+/* malloc and format a glob-pattern to match rotated versions of a logfile */
+static char *mkglobpat(const logFile_t *log_file, int path_len)
+{
+#if ENABLE_FEATURE_LOGROTATE_TIMESTAMPS
+	char *globpat = malloc(path_len + 1   +   5*14   +  1);
+	                               /* . YYYYmmddHHMMSS */
+#elif ENABLE_FEATURE_LOGROTATE_ENOSPC
+	char *globpat = malloc(path_len + 1 + 1 + 5 + 1  +  10  +  1 + 1);
+	                               /* .   { [0-9] , [0-9][0-9] } */
+#endif
+	if (!globpat) {
+		return NULL;
+	}
+#if ENABLE_FEATURE_LOGROTATE_TIMESTAMPS
+	/* NOTE: this glob ignore any old series-stamped "*.[[:digit:]]" files: */
+	sprintf(globpat, "%s.[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]",
 +		log_file->path); /* .YYYYmmddHHMMSS */
+#elif ENABLE_FEATURE_LOGROTATE_ENOSPC
+	sprintf(globpat, "%s.{[0-9],[0-9][0-9]}", log_file->path);
+#endif
+
+	return globpat;
+}
+#endif
+
 /* Print a message to the log file. */
 static void log_locally(time_t now, char *msg, logFile_t *log_file)
 {
@@ -613,6 +639,10 @@ static void log_locally(time_t now, char *msg, logFile_t \
*log_file)  #if ENABLE_FEATURE_ROTATE_LOGFILE
 	int len_written;
 #endif
+#if ENABLE_FEATURE_LOGROTATE_TIMESTAMPS || ENABLE_FEATURE_LOGROTATE_ENOSPC
+	char *globpat = NULL;
+	glob_t globres;
+#endif
 
 	if (log_file->fd >= 0) {
 		/* Reopen log files every second. This allows admin
@@ -641,6 +671,9 @@ static void log_locally(time_t now, char *msg, logFile_t \
*log_file)  full_write(fd, msg, len);
 			if (fd != 2)
 				close(fd);
+			if (globpat) {
+				free(globpat);
+			}
 			return;
 		}
 #if ENABLE_FEATURE_ROTATE_LOGFILE
@@ -685,17 +718,12 @@ static void log_locally(time_t now, char *msg, logFile_t \
*log_file)  #endif
 			char newFile[i];
 #if ENABLE_FEATURE_LOGROTATE_TIMESTAMPS
-			char globpat[oldname_len + 1 + 5*14 + 1]; /* .YYYYmmddHHMMSS */
-			glob_t globres;
-
 			struct stat statbuf;
 			struct tm *ltmp;
 
-			/* FIXME: this glob doesn't DTRT for old series-stamped
-			   "^*.[[:digit:]]$" logfiles; may want to use scandir
-			   to control sorting:
-			*/
-			sprintf(globpat, \
"%s.[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]", \
log_file->path); +			if (!globpat) {
+				globpat = mkglobpat(log_file, oldname_len);
+			}
 			glob(globpat, 0, NULL, &globres);
 
 			i = 0;
@@ -742,15 +770,81 @@ static void log_locally(time_t now, char *msg, logFile_t \
*log_file)  close(log_file->fd);
 		goto reopen;
 	}
-
+#if ENABLE_FEATURE_LOGROTATE_ENOSPC
+continue_writing:
+#endif
 	len_written =
 #endif
 			full_write(log_file->fd, msg, len);
 #if ENABLE_FEATURE_ROTATE_LOGFILE
 	if (len_written >= 0) {
+		/* len_written may be -1 if the write fails *immediately*,
+		 * or any other value <= len if full_write needs
+		 * to break the write up into multiple chunks
+		 * and doesn't fail until one of the later chunks:
+		 */
 		log_file->size += len_written;
 	}
 #endif
+
+#if ENABLE_FEATURE_LOGROTATE_ENOSPC
+	if (len_written < len && errno == ENOSPC) {
+		int res = 0;
+
+		if (len_written > 0) {
+			len -= len_written;
+			msg += len_written;
+		}
+
+		if (!globpat) {
+			globpat = mkglobpat(log_file,
+					    strlen(log_file->path));
+		}
+
+#if ENABLE_FEATURE_LOGROTATE_TIMESTAMPS
+		glob(globpat, 0, NULL, &globres);
+#else
+		glob(globpat, GLOB_BRACE, NULL, &globres);
+#endif
+		if (globres.gl_pathc) {
+			res =
+#if ENABLE_FEATURE_LOGROTATE_TIMESTAMPS
+				/* older timestamps sort earlier;
+				 * remove the oldest=first one:
+				 */
+				unlink(globres.gl_pathv[0])
+#else
+				/* older logfiles have higher sequence-numbers
+				 * and sort later; remove the oldest=last one:
+				 */
+				unlink(globres.gl_pathv[globres.gl_pathc - 1])
+#endif
+				;
+		}
+		globfree(&globres);
+
+		if (res == 0 || res == ENOENT)
+		{
+			goto continue_writing;
+
+			/* ENOENT is the only failure-mode of unlink()
+			 * from which we're likely to be able to recover
+			 * (if someone else already unlinked the file, then
+			 * when we try again either the write will succeed* or
+			 * we'll move on to try unlinking the next-oldest file);
+			 * anything else is more bizarre and probably
+			 * needs manual intervention to resolve, so just
+			 * call it `done' rather than making syslogd
+			 * get stuck spinning in a loop....
+			 */
+		}
+	}
+#endif
+
+	if (globpat) {
+		free(globpat); globpat = NULL;
+	}
+
 #ifdef SYSLOGD_WRLOCK
 	fl.l_type = F_UNLCK;
 	fcntl(log_file->fd, F_SETLKW, &fl);
-- 
1.7.10.4

_______________________________________________
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic