aboutsummaryrefslogtreecommitdiffstats
path: root/lib/libshare/nfs.c
diff options
context:
space:
mode:
authorнаб <[email protected]>2021-05-17 18:13:18 +0200
committerBrian Behlendorf <[email protected]>2021-12-17 12:53:54 -0800
commitc53f2e9b5086051a9aede27254a109983443e557 (patch)
tree1f2b7b583070e83317c675befb0bc4a450c3fb1e /lib/libshare/nfs.c
parentf50697f95b1601d40e7c33249ab1b5d8163d9f64 (diff)
libshare: nfs: open temporary file once
Reviewed-by: Don Brady <[email protected]> Reviewed-by: Brian Behlendorf <[email protected]> Reviewed-by: John Kennedy <[email protected]> Signed-off-by: Ahelenia Ziemiańska <[email protected]> Closes #12067
Diffstat (limited to 'lib/libshare/nfs.c')
-rw-r--r--lib/libshare/nfs.c83
1 files changed, 54 insertions, 29 deletions
diff --git a/lib/libshare/nfs.c b/lib/libshare/nfs.c
index 2b0c70001..e7037b104 100644
--- a/lib/libshare/nfs.c
+++ b/lib/libshare/nfs.c
@@ -77,10 +77,18 @@ nfs_exports_unlock(const char *name)
nfs_lock_fd = -1;
}
-static char *
-nfs_init_tmpfile(const char *prefix, const char *mdir)
+struct tmpfile {
+ /*
+ * This only needs to be as wide as ZFS_EXPORTS_FILE and mktemp suffix,
+ * 64 is more than enough.
+ */
+ char name[64];
+ FILE *fp;
+};
+
+static boolean_t
+nfs_init_tmpfile(const char *prefix, const char *mdir, struct tmpfile *tmpf)
{
- char *tmpfile = NULL;
struct stat sb;
if (mdir != NULL &&
@@ -88,72 +96,89 @@ nfs_init_tmpfile(const char *prefix, const char *mdir)
mkdir(mdir, 0755) < 0) {
fprintf(stderr, "failed to create %s: %s\n",
mdir, strerror(errno));
- return (NULL);
+ return (B_FALSE);
}
- if (asprintf(&tmpfile, "%s.XXXXXXXX", prefix) == -1) {
- fprintf(stderr, "Unable to allocate temporary file\n");
- return (NULL);
- }
+ strcpy(tmpf->name, prefix);
+ strcat(tmpf->name, ".XXXXXXXX");
- int fd = mkostemp(tmpfile, O_CLOEXEC);
+ int fd = mkostemp(tmpf->name, O_CLOEXEC);
if (fd == -1) {
fprintf(stderr, "Unable to create temporary file: %s",
strerror(errno));
- free(tmpfile);
- return (NULL);
+ return (B_FALSE);
+ }
+
+ tmpf->fp = fdopen(fd, "w+");
+ if (tmpf->fp == NULL) {
+ fprintf(stderr, "Unable to reopen temporary file: %s",
+ strerror(errno));
+ close(fd);
+ return (B_FALSE);
}
- close(fd);
- return (tmpfile);
+
+ return (B_TRUE);
+}
+
+static void
+nfs_abort_tmpfile(struct tmpfile *tmpf)
+{
+ unlink(tmpf->name);
+ fclose(tmpf->fp);
}
static int
-nfs_fini_tmpfile(const char *exports, char *tmpfile)
+nfs_fini_tmpfile(const char *exports, struct tmpfile *tmpf)
{
- if (rename(tmpfile, exports) == -1) {
- fprintf(stderr, "Unable to rename %s: %s\n", tmpfile,
+ if (fflush(tmpf->fp) != 0) {
+ fprintf(stderr, "Failed to write to temporary file: %s\n",
strerror(errno));
- unlink(tmpfile);
- free(tmpfile);
+ nfs_abort_tmpfile(tmpf);
+ return (SA_SYSTEM_ERR);
+ }
+
+ if (rename(tmpf->name, exports) == -1) {
+ fprintf(stderr, "Unable to rename %s -> %s: %s\n",
+ tmpf->name, exports, strerror(errno));
+ nfs_abort_tmpfile(tmpf);
return (SA_SYSTEM_ERR);
}
- free(tmpfile);
+
+ fclose(tmpf->fp);
return (SA_OK);
}
int
nfs_toggle_share(const char *lockfile, const char *exports,
const char *expdir, sa_share_impl_t impl_share,
- int(*cbk)(sa_share_impl_t impl_share, char *filename))
+ int(*cbk)(sa_share_impl_t impl_share, FILE *tmpfile))
{
int error;
- char *filename;
+ struct tmpfile tmpf;
- if ((filename = nfs_init_tmpfile(exports, expdir)) == NULL)
+ if (!nfs_init_tmpfile(exports, expdir, &tmpf))
return (SA_SYSTEM_ERR);
error = nfs_exports_lock(lockfile);
if (error != 0) {
- unlink(filename);
- free(filename);
+ nfs_abort_tmpfile(&tmpf);
return (error);
}
- error = nfs_copy_entries(filename, impl_share->sa_mountpoint);
+ error = nfs_copy_entries(tmpf.fp, impl_share->sa_mountpoint);
if (error != SA_OK)
goto fullerr;
- error = cbk(impl_share, filename);
+ error = cbk(impl_share, tmpf.fp);
if (error != SA_OK)
goto fullerr;
- error = nfs_fini_tmpfile(exports, filename);
+ error = nfs_fini_tmpfile(exports, &tmpf);
nfs_exports_unlock(lockfile);
return (error);
fullerr:
- unlink(filename);
- free(filename);
+ nfs_abort_tmpfile(&tmpf);
nfs_exports_unlock(lockfile);
return (error);
}