From: Alice J Mitchell <ajmitchell@redhat.com>
To: linux-nfs@vger.kernel.org
Cc: Steve Dickson <steved@redhat.com>
Subject: [PATCH] nfs-utils: Enable adding of comments and date modified to nfs.conf files
Date: Fri, 03 May 2019 11:57:01 +0100 [thread overview]
Message-ID: <1556881021.20707.9.camel@redhat.com> (raw)
Extend the nfs.conf editing code to support the inserting of comment
lines, as well as file modified information so that automated setting
adjustments and imports can be appropriately flagged.
Signed-off-by: Alice J Mitchell <ajmitchell@redhat.com>
---
support/include/conffile.h | 2 +
support/nfs/conffile.c | 195 ++++++++++++++++++++++++++++++++++++++++++++-
tools/nfsconf/nfsconf.man | 7 +-
tools/nfsconf/nfsconfcli.c | 12 ++-
4 files changed, 211 insertions(+), 5 deletions(-)
diff --git a/support/include/conffile.h b/support/include/conffile.h
index a3340f9..7d974fe 100644
--- a/support/include/conffile.h
+++ b/support/include/conffile.h
@@ -69,6 +69,8 @@ extern int conf_remove_section(int, const char *);
extern void conf_report(FILE *);
extern int conf_write(const char *, const char *, const char *, const char *, const char *);
+extern const char *modified_by;
+
/*
* Convert letter from upper case to lower case
*/
diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c
index d8f2e8e..66d4215 100644
--- a/support/nfs/conffile.c
+++ b/support/nfs/conffile.c
@@ -51,6 +51,7 @@
#include <syslog.h>
#include <libgen.h>
#include <sys/file.h>
+#include <time.h>
#include "conffile.h"
#include "xlog.h"
@@ -113,6 +114,8 @@ struct conf_binding {
LIST_HEAD (conf_bindings, conf_binding) conf_bindings[256];
+const char *modified_by = NULL;
+
static __inline__ uint8_t
conf_hash(const char *s)
{
@@ -1397,6 +1400,52 @@ make_section(const char *section, const char *arg)
return line;
}
+/* compose a comment line (with or without tag) */
+static char *
+make_comment(const char *tag, const char *comment)
+{
+ char *line;
+ int ret;
+
+ if (tag == NULL || *tag == '\0') {
+ ret = asprintf(&line, "# %s\n", comment);
+ } else {
+ ret = asprintf(&line, "# %s: %s\n", tag, comment);
+ }
+
+ if (ret == -1) {
+ xlog(L_ERROR, "malloc error composing header");
+ return NULL;
+ }
+
+ return line;
+}
+
+/* compose a 'file modified' comment */
+static char *
+make_timestamp(const char *tag, time_t when)
+{
+ struct tm *tstamp;
+ char datestr[80];
+ char *result = NULL;
+
+ tstamp = localtime(&when);
+ if (strftime(datestr, sizeof(datestr), "%b %d %Y %H:%M:%S", tstamp) == 0) {
+ xlog(L_ERROR, "error composing date");
+ datestr[0] = '\0';
+ }
+
+ if (modified_by) {
+ char *tmpstr = NULL;
+ asprintf(&tmpstr, "%s on %s", modified_by, datestr);
+ result = make_comment(tag, tmpstr);
+ free(tmpstr);
+ } else {
+ result = make_comment(tag, datestr);
+ }
+ return result;
+}
+
/* does the supplied line contain the named section header */
static bool
is_section(const char *line, const char *section, const char *arg)
@@ -1406,6 +1455,10 @@ is_section(const char *line, const char *section, const char *arg)
char *sub;
bool found = false;
+ /* Not a valid section name */
+ if (strcmp(section, "#") == 0)
+ return false;
+
/* skip leading white space */
while (*line == '[' || isspace(*line))
line++;
@@ -1569,6 +1622,54 @@ is_comment(const char *line)
return false;
}
+/* check that line contains the specified comment header */
+static bool
+is_taggedcomment(const char *line, const char *field)
+{
+ char *end;
+ char *name;
+ bool found = false;
+
+ if (line == NULL)
+ return false;
+
+ while (isblank(*line))
+ line++;
+
+ if (*line != '#')
+ return false;
+
+ line++;
+
+ /* quick check, is this even a likely formatted line */
+ end = strchr(line, ':');
+ if (end == NULL)
+ return false;
+
+ /* skip leading white space before field name */
+ while (isblank(*line))
+ line++;
+
+ name = strdup(line);
+ if (name == NULL) {
+ xlog_warn("conf_write: malloc failed");
+ return false;
+ }
+
+ /* strip trailing spaces from the name */
+ end = strchr(name, ':');
+ if (end) *(end--) = 0;
+ while (end && end > name && isblank(*end))
+ *(end--)=0;
+
+ if (strcasecmp(name, field)==0)
+ found = true;
+
+ free(name);
+ return found;
+}
+
+
/* delete a buffer queue whilst optionally outputting to file */
static int
flush_outqueue(struct tailhead *queue, FILE *fout)
@@ -1772,6 +1873,7 @@ conf_write(const char *filename, const char *section, const char *arg,
struct tailhead inqueue;
char * buff = NULL;
int buffsize = 0;
+ time_t now = time(NULL);
TAILQ_INIT(&inqueue);
TAILQ_INIT(&outqueue);
@@ -1804,12 +1906,81 @@ conf_write(const char *filename, const char *section, const char *arg,
if (lock_file(infile))
goto cleanup;
- if (append_line(&inqueue, NULL, make_section(section, arg)))
+ if (strcmp(section, "#") == 0) {
+ if (append_line(&inqueue, NULL, make_comment(tag, value)))
+ goto cleanup;
+ } else {
+ if (append_line(&inqueue, NULL, make_section(section, arg)))
+ goto cleanup;
+
+ if (append_line(&inqueue, NULL, make_tagline(tag, value)))
+ goto cleanup;
+ }
+
+ append_queue(&inqueue, &outqueue);
+ } else
+ if (strcmp(section, "#") == 0) {
+ /* Adding a comment line */
+ struct outbuffer *where = NULL;
+ struct outbuffer *next = NULL;
+ bool found = false;
+ int err = 0;
+
+ if (lock_file(infile))
goto cleanup;
- if (append_line(&inqueue, NULL, make_tagline(tag, value)))
+ buffsize = 4096;
+ buff = calloc(1, buffsize);
+ if (buff == NULL) {
+ xlog(L_ERROR, "malloc error for read buffer");
goto cleanup;
+ }
+ buff[0] = '\0';
+ /* read in the file */
+ do {
+ if (*buff != '\0'
+ && !is_taggedcomment(buff, "Modified")) {
+ if (append_line(&inqueue, NULL, strdup(buff)))
+ goto cleanup;
+ }
+
+ err = read_line(&buff, &buffsize, infile);
+ } while (err == 0);
+
+ /* if a tagged comment, look for an existing instance */
+ if (tag && *tag != '\0') {
+ where = TAILQ_FIRST(&inqueue);
+ while (where != NULL) {
+ next = TAILQ_NEXT(where, link);
+ struct outbuffer *prev = TAILQ_PREV(where, tailhead, link);
+ if (is_taggedcomment(where->text, tag)) {
+ TAILQ_REMOVE(&inqueue, where, link);
+ free(where->text);
+ free(where);
+ found = true;
+ if (append_line(&inqueue, prev, make_comment(tag, value)))
+ goto cleanup;
+ }
+ where = next;
+ }
+ }
+ /* it wasn't tagged or we didn't find it */
+ if (!found) {
+ /* does the file end in a blank line or a comment */
+ if (!TAILQ_EMPTY(&inqueue)) {
+ struct outbuffer *tail = TAILQ_LAST(&inqueue, tailhead);
+ if (tail && !is_empty(tail->text) && !is_comment(tail->text)) {
+ /* no, so add one for clarity */
+ if (append_line(&inqueue, NULL, strdup("\n")))
+ goto cleanup;
+ }
+ }
+ /* add the new comment line */
+ if (append_line(&inqueue, NULL, make_comment(tag, value)))
+ goto cleanup;
+ }
+ /* move everything over to the outqueue for writing */
append_queue(&inqueue, &outqueue);
} else {
bool found = false;
@@ -1831,7 +2002,8 @@ conf_write(const char *filename, const char *section, const char *arg,
/* read in one section worth of lines */
do {
- if (*buff != '\0') {
+ if (*buff != '\0'
+ && !is_taggedcomment(buff, "Modified")) {
if (append_line(&inqueue, NULL, strdup(buff)))
goto cleanup;
}
@@ -1950,6 +2122,23 @@ conf_write(const char *filename, const char *section, const char *arg,
} while(err == 0);
}
+ if (modified_by) {
+ /* check for and update the Modified header */
+ /* does the file end in a blank line or a comment */
+ if (!TAILQ_EMPTY(&outqueue)) {
+ struct outbuffer *tail = TAILQ_LAST(&outqueue, tailhead);
+ if (tail && !is_empty(tail->text) && !is_comment(tail->text)) {
+ /* no, so add one for clarity */
+ if (append_line(&outqueue, NULL, strdup("\n")))
+ goto cleanup;
+ }
+ }
+
+ /* now append the modified date comment */
+ if (append_line(&outqueue, NULL, make_timestamp("Modified", now)))
+ goto cleanup;
+ }
+
/* now rewind and overwrite the file with the updated data */
rewind(infile);
diff --git a/tools/nfsconf/nfsconf.man b/tools/nfsconf/nfsconf.man
index 1ae8543..3079198 100644
--- a/tools/nfsconf/nfsconf.man
+++ b/tools/nfsconf/nfsconf.man
@@ -31,6 +31,8 @@ nfsconf \- Query various NFS configuration settings
.P
.B nfsconf \-\-set
.RB [ \-v | \-\-verbose ]
+.RB [ \-m | \-\-modified
+.IR "Modified by text" ]
.RB [ \-f | \-\-file
.IR infile.conf ]
.RB [ \-a | \-\-arg
@@ -61,7 +63,7 @@ Test if a specific tag has a value set.
.IP "\fB\-g, \-\-get\fP"
Output the current value of the specified tag.
.IP "\fB\-s, \-\-set\fP"
-Update or Add a tag and value to the config file, creating the file if necessary.
+Update or Add a tag and value to the config file in a specified section, creating the tag, section, and file if necessary. If the section is defined as '#' then a comment is appended to the file. If a comment is set with a tag name then any exiting tagged comment with a matching name is replaced.
.IP "\fB\-u, \-\-unset\fP"
Remove the specified tag and its value from the config file.
.SH OPTIONS
@@ -77,6 +79,9 @@ Select a different config file to operate upon, default is
.TP
.B \-a, \-\-arg \fIsubsection\fR
Select a specific sub-section
+.SS Options only valid in \fB\-\-set\fR mode.
+.B \-m, \-\-modified \fI"Modified by nfsconf"\fR
+Set the text on the Modified date comment in the file. Set to empty to remove.
.SH EXIT STATUS
.SS \fB\-\-isset\fR mode
In this mode the command will return success (0) if the selected tag has a value, any other exit code indicates the value is not set, or some other error has occurred.
diff --git a/tools/nfsconf/nfsconfcli.c b/tools/nfsconf/nfsconfcli.c
index f98d0d1..361d386 100644
--- a/tools/nfsconf/nfsconfcli.c
+++ b/tools/nfsconf/nfsconfcli.c
@@ -24,6 +24,7 @@ static void usage(const char *name)
fprintf(stderr, " -v Increase Verbosity\n");
fprintf(stderr, " --file filename.conf Load this config file\n");
fprintf(stderr, " (Default config file: " NFS_CONFFILE "\n");
+ fprintf(stderr, " --modified \"info\" Use \"info\" in file modified header\n");
fprintf(stderr, "Modes:\n");
fprintf(stderr, " --dump [outputfile]\n");
fprintf(stderr, " Outputs the configuration to the named file\n");
@@ -47,6 +48,8 @@ int main(int argc, char **argv)
confmode_t mode = MODE_NONE;
+ modified_by = "Modified by nfsconf";
+
while (1) {
int c;
int index = 0;
@@ -59,10 +62,11 @@ int main(int argc, char **argv)
{"dump", optional_argument, 0, 'd' },
{"file", required_argument, 0, 'f' },
{"verbose", no_argument, 0, 'v' },
+ {"modified", required_argument, 0, 'm' },
{NULL, 0, 0, 0 }
};
- c = getopt_long(argc, argv, "gsua:id::f:v", long_options, &index);
+ c = getopt_long(argc, argv, "gsua:id::f:vm:", long_options, &index);
if (c == -1) break;
switch (c) {
@@ -99,6 +103,12 @@ int main(int argc, char **argv)
mode = MODE_DUMP;
dumpfile = optarg;
break;
+ case 'm':
+ if (optarg == NULL || *optarg == 0)
+ modified_by = NULL;
+ else
+ modified_by = optarg;
+ break;
default:
usage(argv[0]);
return 1;
--
1.8.3.1
next reply other threads:[~2019-05-03 10:57 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-05-03 10:57 Alice J Mitchell [this message]
2019-05-08 12:34 ` [PATCH] nfs-utils: Enable adding of comments and date modified to nfs.conf files Steve Dickson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1556881021.20707.9.camel@redhat.com \
--to=ajmitchell@redhat.com \
--cc=linux-nfs@vger.kernel.org \
--cc=steved@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).