[PATCH] syslogd: try to handle ENOSPC during writes

Joshua Judson Rosen jrosen at harvestai.com
Tue May 20 05:09:36 UTC 2014


Unlink the oldest rotated-out logfile
and then try writing the rest of the msg.

Signed-off-by: Joshua Judson Rosen <jrosen at harvestai.com>
---
 sysklogd/Config.src |    9 ++++++
 sysklogd/syslogd.c  |   79 ++++++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 78 insertions(+), 10 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 689b036..43c08cd 100644
--- a/sysklogd/syslogd.c
+++ b/sysklogd/syslogd.c
@@ -609,6 +609,32 @@ static void log_locally(time_t now, char *msg, logFile_t *log_file)
 	struct flock fl;
 #endif
 	int len = strlen(msg);
+#if ENABLE_FEATURE_ROTATE_LOGFILE
+	int oldname_len = strlen(log_file->path);
+#endif
+#if ENABLE_FEATURE_LOGROTATE_TIMESTAMPS
+	char globpat[oldname_len + 1   +   5*14   +  1];
+	                        /* . YYYYmmddHHMMSS */
+#elif ENABLE_FEATURE_LOGROTATE_ENOSPC
+	char globpat[oldname_len + 1 + 1 + 5 + 1  +  10  +  1 + 1];
+	                        /* .   { [0-9] , [0-9][0-9] } */
+#endif
+#if ENABLE_FEATURE_LOGROTATE_TIMESTAMPS || ENABLE_FEATURE_LOGROTATE_ENOSPC
+	glob_t globres;
+#endif
+#if ENABLE_FEATURE_LOGROTATE_TIMESTAMPS
+	/* 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);
+#elif ENABLE_FEATURE_LOGROTATE_ENOSPC
+	sprintf(globpat, "%s.{[0-9],[0-9][0-9]}"); /* 0..9 or 10..99 */
+#endif
+
+#if ENABLE_FEATURE_LOGROTATE_ENOSPC
+	int len_written;
+#endif
 
 	if (log_file->fd >= 0) {
 		/* Reopen log file every second. This allows admin
@@ -670,7 +696,6 @@ static void log_locally(time_t now, char *msg, logFile_t *log_file)
 			 * the new file).
 			 */
 		} else) if (G.logFileRotate) { /* always 0..99 */
-			int oldname_len = strlen(log_file->path);
 #if ENABLE_FEATURE_LOGROTATE_TIMESTAMPS
 			int i = oldname_len + 1 + 4 + 2 + 2 + 2 + 2 + 2    + 1;
 			                   /* .   Y   m   d   H   M   S */
@@ -680,17 +705,9 @@ 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);
 			glob(globpat, 0, NULL, &globres);
 
 			i = 0;
@@ -737,9 +754,51 @@ static void log_locally(time_t now, char *msg, logFile_t *log_file)
 		close(log_file->fd);
 		goto reopen;
 	}
+#if ENABLE_FEATURE_LOGROTATE_ENOSPC
+	len_written = 0;
+#endif
+continue_writing:
 	log_file->size +=
 #endif
-			full_write(log_file->fd, msg, len);
+#if ENABLE_FEATURE_LOGROTATE_ENOSPC
+	    /* this 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:
+	     */
+		(len_written =
+#endif
+			full_write(log_file->fd, msg
+#if ENABLE_FEATURE_LOGROTATE_ENOSPC
+				   + (len_written < 0 ? 0 : len_written)
+#endif
+				   , len - (len_written < 0 ? 0 : len_written))
+#if ENABLE_FEATURE_LOGROTATE_ENOSPC
+		)
+#endif
+		;
+#if ENABLE_FEATURE_LOGROTATE_ENOSPC
+	if (len_written < len && errno == ENOSPC) {
+	    glob(globpat, GLOB_BRACE, NULL, &globres);
+	    if (globres.gl_pathc) {
+#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);
+	    goto continue_writing;
+	}
+#endif
+
 #ifdef SYSLOGD_WRLOCK
 	fl.l_type = F_UNLCK;
 	fcntl(log_file->fd, F_SETLKW, &fl);
-- 
1.7.10.4



More information about the busybox mailing list