Blame SOURCES/nfs-utils-2.3.3-nfsconf-inplace.patch

9d9876
diff -up nfs-utils-2.3.3/support/nfs/conffile.c.orig nfs-utils-2.3.3/support/nfs/conffile.c
9d9876
--- nfs-utils-2.3.3/support/nfs/conffile.c.orig	2018-09-06 14:09:08.000000000 -0400
9d9876
+++ nfs-utils-2.3.3/support/nfs/conffile.c	2019-04-25 10:58:27.199907596 -0400
9d9876
@@ -50,6 +50,7 @@
9d9876
 #include <err.h>
9d9876
 #include <syslog.h>
9d9876
 #include <libgen.h>
9d9876
+#include <sys/file.h>
9d9876
 
9d9876
 #include "conffile.h"
9d9876
 #include "xlog.h"
9d9876
@@ -509,6 +510,17 @@ conf_readfile(const char *path)
9d9876
 			return NULL;
9d9876
 		}
9d9876
 
9d9876
+		/* Grab a shared lock to ensure its not mid-rewrite */
9d9876
+		if (flock(fd, LOCK_SH)) {
9d9876
+			xlog_warn("conf_readfile: attempt to grab read lock failed: %s",
9d9876
+				strerror(errno));
9d9876
+			goto fail;
9d9876
+		}
9d9876
+
9d9876
+		/* only after we have the lock, check the file size ready to read it */
9d9876
+		sz = lseek(fd, 0, SEEK_END);
9d9876
+		lseek(fd, 0, SEEK_SET);
9d9876
+
9d9876
 		new_conf_addr = malloc(sz+1);
9d9876
 		if (!new_conf_addr) {
9d9876
 			xlog_warn("conf_readfile: malloc (%lu) failed", (unsigned long)sz);
9d9876
@@ -1588,6 +1600,17 @@ flush_outqueue(struct tailhead *queue, F
9d9876
 	return 0;
9d9876
 }
9d9876
 
9d9876
+/* append one queue to another */
9d9876
+static void
9d9876
+append_queue(struct tailhead *inq, struct tailhead *outq)
9d9876
+{
9d9876
+	while (inq->tqh_first != NULL) {
9d9876
+		struct outbuffer *ob = inq->tqh_first;
9d9876
+		TAILQ_REMOVE(inq, ob, link);
9d9876
+		TAILQ_INSERT_TAIL(outq, ob, link);
9d9876
+	}
9d9876
+}
9d9876
+
9d9876
 /* read one line of text from a file, growing the buffer as necessary */
9d9876
 static int
9d9876
 read_line(char **buff, int *buffsize, FILE *in)
9d9876
@@ -1728,6 +1751,16 @@ is_folded(const char *line)
9d9876
 	return false;
9d9876
 }
9d9876
 
9d9876
+static int
9d9876
+lock_file(FILE *f)
9d9876
+{
9d9876
+	int ret;
9d9876
+	ret = flock(fileno(f), LOCK_EX);
9d9876
+	if (ret) 
9d9876
+		xlog(L_ERROR, "Error could not lock the file");
9d9876
+	return ret;
9d9876
+}
9d9876
+
9d9876
 /***
9d9876
  * Write a value to an nfs.conf style filename
9d9876
  *
9d9876
@@ -1738,15 +1771,14 @@ int
9d9876
 conf_write(const char *filename, const char *section, const char *arg,
9d9876
 	   const char *tag, const char *value)
9d9876
 {
9d9876
-	int fdout = -1;
9d9876
-	char *outpath = NULL;
9d9876
-	FILE *outfile = NULL;
9d9876
 	FILE *infile = NULL;
9d9876
 	int ret = 1;
9d9876
 	struct tailhead outqueue;
9d9876
+	struct tailhead inqueue;
9d9876
 	char * buff = NULL;
9d9876
 	int buffsize = 0;
9d9876
 
9d9876
+	TAILQ_INIT(&inqueue);
9d9876
 	TAILQ_INIT(&outqueue);
9d9876
 
9d9876
 	if (!filename) {
9d9876
@@ -1759,26 +1791,7 @@ conf_write(const char *filename, const c
9d9876
 		return ret;
9d9876
 	}
9d9876
 
9d9876
-	if (asprintf(&outpath, "%s.XXXXXX", filename) == -1) {
9d9876
-		xlog(L_ERROR, "conf_write: error composing temp filename");
9d9876
-		return ret;
9d9876
-	}
9d9876
-
9d9876
-	fdout = mkstemp(outpath);
9d9876
-	if (fdout < 0) {
9d9876
-		xlog(L_ERROR, "conf_write: open temp file %s failed: %s",
9d9876
-			 outpath, strerror(errno));
9d9876
-		goto cleanup;
9d9876
-	}
9d9876
-
9d9876
-	outfile = fdopen(fdout, "w");
9d9876
-	if (!outfile) {
9d9876
-		xlog(L_ERROR, "conf_write: fdopen temp file failed: %s",
9d9876
-			 strerror(errno));
9d9876
-		goto cleanup;
9d9876
-	}
9d9876
-
9d9876
-	infile = fopen(filename, "r");
9d9876
+	infile = fopen(filename, "r+");
9d9876
 	if (!infile) {
9d9876
 		if (!value) {
9d9876
 			xlog_warn("conf_write: config file \"%s\" not found, nothing to do", filename);
9d9876
@@ -1787,18 +1800,29 @@ conf_write(const char *filename, const c
9d9876
 		}
9d9876
 
9d9876
 		xlog_warn("conf_write: config file \"%s\" not found, creating.", filename);
9d9876
-		if (append_line(&outqueue, NULL, make_section(section, arg)))
9d9876
+		infile = fopen(filename, "wx");
9d9876
+		if (!infile) {
9d9876
+			xlog(L_ERROR, "conf_write: Error creating config file \"%s\".", filename);
9d9876
+			goto cleanup;
9d9876
+		}
9d9876
+
9d9876
+		if (lock_file(infile))
9d9876
 			goto cleanup;
9d9876
 
9d9876
-		if (append_line(&outqueue, NULL, make_tagline(tag, value)))
9d9876
+		if (append_line(&inqueue, NULL, make_section(section, arg)))
9d9876
 			goto cleanup;
9d9876
 
9d9876
-		if (flush_outqueue(&outqueue, outfile))
9d9876
+		if (append_line(&inqueue, NULL, make_tagline(tag, value)))
9d9876
 			goto cleanup;
9d9876
+
9d9876
+		append_queue(&inqueue, &outqueue);
9d9876
 	} else {
9d9876
 		bool found = false;
9d9876
 		int err = 0;
9d9876
 
9d9876
+		if (lock_file(infile))
9d9876
+			goto cleanup;
9d9876
+
9d9876
 		buffsize = 4096;
9d9876
 		buff = calloc(1, buffsize);
9d9876
 		if (buff == NULL) {
9d9876
@@ -1813,7 +1837,7 @@ conf_write(const char *filename, const c
9d9876
 			/* read in one section worth of lines */
9d9876
 			do {
9d9876
 				if (*buff != '\0') {
9d9876
-					if (append_line(&outqueue, NULL, strdup(buff)))
9d9876
+					if (append_line(&inqueue, NULL, strdup(buff)))
9d9876
 						goto cleanup;
9d9876
 				}
9d9876
 
9d9876
@@ -1821,7 +1845,7 @@ conf_write(const char *filename, const c
9d9876
 			} while (err == 0 && buff[0] != '[');
9d9876
 
9d9876
 			/* find the section header */
9d9876
-			where = TAILQ_FIRST(&outqueue);
9d9876
+			where = TAILQ_FIRST(&inqueue);
9d9876
 			while (where != NULL) {
9d9876
 				if (where->text != NULL && where->text[0] == '[')
9d9876
 					break;
9d9876
@@ -1845,7 +1869,7 @@ conf_write(const char *filename, const c
9d9876
 					/* remove current tag */
9d9876
 					do {
9d9876
 						struct outbuffer *next = TAILQ_NEXT(where, link);
9d9876
-						TAILQ_REMOVE(&outqueue, where, link);
9d9876
+						TAILQ_REMOVE(&inqueue, where, link);
9d9876
 						if (is_folded(where->text))
9d9876
 							again = true;
9d9876
 						else
9d9876
@@ -1857,14 +1881,14 @@ conf_write(const char *filename, const c
9d9876
 
9d9876
 					/* insert new tag */
9d9876
 					if (value) {
9d9876
-						if (append_line(&outqueue, prev, make_tagline(tag, value)))
9d9876
+						if (append_line(&inqueue, prev, make_tagline(tag, value)))
9d9876
 							goto cleanup;
9d9876
 					}
9d9876
 				} else
9d9876
 				/* no existing assignment found and we need to add one */
9d9876
 				if (value) {
9d9876
 					/* rewind past blank lines and comments */
9d9876
-					struct outbuffer *tail = TAILQ_LAST(&outqueue, tailhead);
9d9876
+					struct outbuffer *tail = TAILQ_LAST(&inqueue, tailhead);
9d9876
 
9d9876
 					/* comments immediately before a section usually relate
9d9876
 					 * to the section below them */
9d9876
@@ -1876,7 +1900,7 @@ conf_write(const char *filename, const c
9d9876
 						tail = TAILQ_PREV(tail, tailhead, link);
9d9876
 
9d9876
 					/* now add the tag here */
9d9876
-					if (append_line(&outqueue, tail, make_tagline(tag, value)))
9d9876
+					if (append_line(&inqueue, tail, make_tagline(tag, value)))
9d9876
 						goto cleanup;
9d9876
 
9d9876
 					found = true;
9d9876
@@ -1886,49 +1910,45 @@ conf_write(const char *filename, const c
9d9876
 			/* EOF and correct section not found, so add one */
9d9876
 			if (err && !found && value) {
9d9876
 				/* did the last section end in a blank line */
9d9876
-				struct outbuffer *tail = TAILQ_LAST(&outqueue, tailhead);
9d9876
+				struct outbuffer *tail = TAILQ_LAST(&inqueue, tailhead);
9d9876
 				if (tail && !is_empty(tail->text)) {
9d9876
 					/* no, so add one for clarity */
9d9876
-					if (append_line(&outqueue, NULL, strdup("\n")))
9d9876
+					if (append_line(&inqueue, NULL, strdup("\n")))
9d9876
 						goto cleanup;
9d9876
 				}
9d9876
 
9d9876
 				/* add the new section header */
9d9876
-				if (append_line(&outqueue, NULL, make_section(section, arg)))
9d9876
+				if (append_line(&inqueue, NULL, make_section(section, arg)))
9d9876
 					goto cleanup;
9d9876
 
9d9876
 				/* now add the tag */
9d9876
-				if (append_line(&outqueue, NULL, make_tagline(tag, value)))
9d9876
+				if (append_line(&inqueue, NULL, make_tagline(tag, value)))
9d9876
 					goto cleanup;
9d9876
 			}
9d9876
 
9d9876
-			/* we are done with this section, write it out */
9d9876
-			if (flush_outqueue(&outqueue, outfile))
9d9876
-				goto cleanup;
9d9876
+			/* we are done with this section, move it to the out queue */
9d9876
+			append_queue(&inqueue, &outqueue);
9d9876
 		} while(err == 0);
9d9876
 	}
9d9876
 
9d9876
-	if (infile) {
9d9876
-		fclose(infile);
9d9876
-		infile = NULL;
9d9876
-	}
9d9876
+	/* now rewind and overwrite the file with the updated data */
9d9876
+	rewind(infile);
9d9876
 
9d9876
-	fdout = -1;
9d9876
-	if (fclose(outfile)) {
9d9876
-		xlog(L_ERROR, "Error writing config file: %s", strerror(errno));
9d9876
+	if (ftruncate(fileno(infile), 0)) {
9d9876
+		xlog(L_ERROR, "Error truncating config file");
9d9876
 		goto cleanup;
9d9876
 	}
9d9876
 
9d9876
-	/* now swap the old file for the new one */
9d9876
-	if (rename(outpath, filename)) {
9d9876
-		xlog(L_ERROR, "Error updating config file: %s: %s\n", filename, strerror(errno));
9d9876
-		ret = 1;
9d9876
-	} else {
9d9876
-		ret = 0;
9d9876
-		free(outpath);
9d9876
-		outpath = NULL;
9d9876
+	if (flush_outqueue(&outqueue, infile))
9d9876
+		goto cleanup;
9d9876
+
9d9876
+	if (infile) {
9d9876
+		fclose(infile);
9d9876
+		infile = NULL;
9d9876
 	}
9d9876
 
9d9876
+	ret = 0;
9d9876
+
9d9876
 cleanup:
9d9876
 	flush_outqueue(&outqueue, NULL);
9d9876
 
9d9876
@@ -1936,11 +1956,5 @@ cleanup:
9d9876
 		free(buff);
9d9876
 	if (infile)
9d9876
 		fclose(infile);
9d9876
-	if (fdout != -1)
9d9876
-		close(fdout);
9d9876
-	if (outpath) {
9d9876
-		unlink(outpath);
9d9876
-		free(outpath);
9d9876
-	}
9d9876
 	return ret;
9d9876
 }