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