xref: /freebsd/sys/contrib/openzfs/lib/libshare/nfs.c (revision 3ff01b231dfa83d518854c63e7c9cd1debd1139e)
116038816SMartin Matuska /*
216038816SMartin Matuska  * CDDL HEADER START
316038816SMartin Matuska  *
416038816SMartin Matuska  * The contents of this file are subject to the terms of the
516038816SMartin Matuska  * Common Development and Distribution License (the "License").
616038816SMartin Matuska  * You may not use this file except in compliance with the License.
716038816SMartin Matuska  *
816038816SMartin Matuska  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
916038816SMartin Matuska  * or http://www.opensolaris.org/os/licensing.
1016038816SMartin Matuska  * See the License for the specific language governing permissions
1116038816SMartin Matuska  * and limitations under the License.
1216038816SMartin Matuska  *
1316038816SMartin Matuska  * When distributing Covered Code, include this CDDL HEADER in each
1416038816SMartin Matuska  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1516038816SMartin Matuska  * If applicable, add the following below this CDDL HEADER, with the
1616038816SMartin Matuska  * fields enclosed by brackets "[]" replaced with your own identifying
1716038816SMartin Matuska  * information: Portions Copyright [yyyy] [name of copyright owner]
1816038816SMartin Matuska  *
1916038816SMartin Matuska  * CDDL HEADER END
2016038816SMartin Matuska  */
2116038816SMartin Matuska 
2216038816SMartin Matuska 
2316038816SMartin Matuska #include <sys/types.h>
2416038816SMartin Matuska #include <sys/stat.h>
2516038816SMartin Matuska #include <sys/file.h>
2616038816SMartin Matuska #include <fcntl.h>
2716038816SMartin Matuska #include <stdio.h>
2816038816SMartin Matuska #include <errno.h>
2916038816SMartin Matuska #include <libshare.h>
3016038816SMartin Matuska #include "nfs.h"
3116038816SMartin Matuska 
3216038816SMartin Matuska 
3316038816SMartin Matuska static int nfs_lock_fd = -1;
3416038816SMartin Matuska 
3516038816SMartin Matuska 
3616038816SMartin Matuska /*
3716038816SMartin Matuska  * nfs_exports_[lock|unlock] are used to guard against conconcurrent
3816038816SMartin Matuska  * updates to the exports file. Each protocol is responsible for
3916038816SMartin Matuska  * providing the necessary locking to ensure consistency.
4016038816SMartin Matuska  */
4116038816SMartin Matuska static int
4216038816SMartin Matuska nfs_exports_lock(const char *name)
4316038816SMartin Matuska {
4416038816SMartin Matuska 	int err;
4516038816SMartin Matuska 
4616038816SMartin Matuska 	nfs_lock_fd = open(name, O_RDWR | O_CREAT | O_CLOEXEC, 0600);
4716038816SMartin Matuska 	if (nfs_lock_fd == -1) {
4816038816SMartin Matuska 		err = errno;
4916038816SMartin Matuska 		fprintf(stderr, "failed to lock %s: %s\n", name, strerror(err));
5016038816SMartin Matuska 		return (err);
5116038816SMartin Matuska 	}
5216038816SMartin Matuska 
5316038816SMartin Matuska 	if (flock(nfs_lock_fd, LOCK_EX) != 0) {
5416038816SMartin Matuska 		err = errno;
5516038816SMartin Matuska 		fprintf(stderr, "failed to lock %s: %s\n", name, strerror(err));
5616038816SMartin Matuska 		(void) close(nfs_lock_fd);
5716038816SMartin Matuska 		nfs_lock_fd = -1;
5816038816SMartin Matuska 		return (err);
5916038816SMartin Matuska 	}
6016038816SMartin Matuska 
6116038816SMartin Matuska 	return (0);
6216038816SMartin Matuska }
6316038816SMartin Matuska 
6416038816SMartin Matuska static void
6516038816SMartin Matuska nfs_exports_unlock(const char *name)
6616038816SMartin Matuska {
6716038816SMartin Matuska 	verify(nfs_lock_fd > 0);
6816038816SMartin Matuska 
6916038816SMartin Matuska 	if (flock(nfs_lock_fd, LOCK_UN) != 0) {
7016038816SMartin Matuska 		fprintf(stderr, "failed to unlock %s: %s\n",
7116038816SMartin Matuska 		    name, strerror(errno));
7216038816SMartin Matuska 	}
7316038816SMartin Matuska 
7416038816SMartin Matuska 	(void) close(nfs_lock_fd);
7516038816SMartin Matuska 	nfs_lock_fd = -1;
7616038816SMartin Matuska }
7716038816SMartin Matuska 
7816038816SMartin Matuska static char *
7916038816SMartin Matuska nfs_init_tmpfile(const char *prefix, const char *mdir)
8016038816SMartin Matuska {
8116038816SMartin Matuska 	char *tmpfile = NULL;
8216038816SMartin Matuska 	struct stat sb;
8316038816SMartin Matuska 
8416038816SMartin Matuska 	if (mdir != NULL &&
8516038816SMartin Matuska 	    stat(mdir, &sb) < 0 &&
8616038816SMartin Matuska 	    mkdir(mdir, 0755) < 0) {
8716038816SMartin Matuska 		fprintf(stderr, "failed to create %s: %s\n",
8816038816SMartin Matuska 		    mdir, strerror(errno));
8916038816SMartin Matuska 		return (NULL);
9016038816SMartin Matuska 	}
9116038816SMartin Matuska 
9216038816SMartin Matuska 	if (asprintf(&tmpfile, "%s.XXXXXXXX", prefix) == -1) {
9316038816SMartin Matuska 		fprintf(stderr, "Unable to allocate temporary file\n");
9416038816SMartin Matuska 		return (NULL);
9516038816SMartin Matuska 	}
9616038816SMartin Matuska 
9716038816SMartin Matuska 	int fd = mkostemp(tmpfile, O_CLOEXEC);
9816038816SMartin Matuska 	if (fd == -1) {
9916038816SMartin Matuska 		fprintf(stderr, "Unable to create temporary file: %s",
10016038816SMartin Matuska 		    strerror(errno));
10116038816SMartin Matuska 		free(tmpfile);
10216038816SMartin Matuska 		return (NULL);
10316038816SMartin Matuska 	}
10416038816SMartin Matuska 	close(fd);
10516038816SMartin Matuska 	return (tmpfile);
10616038816SMartin Matuska }
10716038816SMartin Matuska 
10816038816SMartin Matuska static int
10916038816SMartin Matuska nfs_fini_tmpfile(const char *exports, char *tmpfile)
11016038816SMartin Matuska {
11116038816SMartin Matuska 	if (rename(tmpfile, exports) == -1) {
11216038816SMartin Matuska 		fprintf(stderr, "Unable to rename %s: %s\n", tmpfile,
11316038816SMartin Matuska 		    strerror(errno));
11416038816SMartin Matuska 		unlink(tmpfile);
11516038816SMartin Matuska 		free(tmpfile);
11616038816SMartin Matuska 		return (SA_SYSTEM_ERR);
11716038816SMartin Matuska 	}
11816038816SMartin Matuska 	free(tmpfile);
11916038816SMartin Matuska 	return (SA_OK);
12016038816SMartin Matuska }
12116038816SMartin Matuska 
122*3ff01b23SMartin Matuska int
12316038816SMartin Matuska nfs_toggle_share(const char *lockfile, const char *exports,
12416038816SMartin Matuska     const char *expdir, sa_share_impl_t impl_share,
12516038816SMartin Matuska     int(*cbk)(sa_share_impl_t impl_share, char *filename))
12616038816SMartin Matuska {
12716038816SMartin Matuska 	int error;
12816038816SMartin Matuska 	char *filename;
12916038816SMartin Matuska 
13016038816SMartin Matuska 	if ((filename = nfs_init_tmpfile(exports, expdir)) == NULL)
13116038816SMartin Matuska 		return (SA_SYSTEM_ERR);
13216038816SMartin Matuska 
13316038816SMartin Matuska 	error = nfs_exports_lock(lockfile);
13416038816SMartin Matuska 	if (error != 0) {
13516038816SMartin Matuska 		unlink(filename);
13616038816SMartin Matuska 		free(filename);
13716038816SMartin Matuska 		return (error);
13816038816SMartin Matuska 	}
13916038816SMartin Matuska 
14016038816SMartin Matuska 	error = nfs_copy_entries(filename, impl_share->sa_mountpoint);
14116038816SMartin Matuska 	if (error != SA_OK)
14216038816SMartin Matuska 		goto fullerr;
14316038816SMartin Matuska 
14416038816SMartin Matuska 	error = cbk(impl_share, filename);
14516038816SMartin Matuska 	if (error != SA_OK)
14616038816SMartin Matuska 		goto fullerr;
14716038816SMartin Matuska 
14816038816SMartin Matuska 	error = nfs_fini_tmpfile(exports, filename);
14916038816SMartin Matuska 	nfs_exports_unlock(lockfile);
15016038816SMartin Matuska 	return (error);
15116038816SMartin Matuska 
15216038816SMartin Matuska fullerr:
15316038816SMartin Matuska 	unlink(filename);
15416038816SMartin Matuska 	free(filename);
15516038816SMartin Matuska 	nfs_exports_unlock(lockfile);
15616038816SMartin Matuska 	return (error);
15716038816SMartin Matuska }
158