xref: /freebsd/sys/contrib/openzfs/lib/libshare/nfs.c (revision 1603881667360c015f6685131f2f25474fa67a72)
1*16038816SMartin Matuska /*
2*16038816SMartin Matuska  * CDDL HEADER START
3*16038816SMartin Matuska  *
4*16038816SMartin Matuska  * The contents of this file are subject to the terms of the
5*16038816SMartin Matuska  * Common Development and Distribution License (the "License").
6*16038816SMartin Matuska  * You may not use this file except in compliance with the License.
7*16038816SMartin Matuska  *
8*16038816SMartin Matuska  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*16038816SMartin Matuska  * or http://www.opensolaris.org/os/licensing.
10*16038816SMartin Matuska  * See the License for the specific language governing permissions
11*16038816SMartin Matuska  * and limitations under the License.
12*16038816SMartin Matuska  *
13*16038816SMartin Matuska  * When distributing Covered Code, include this CDDL HEADER in each
14*16038816SMartin Matuska  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*16038816SMartin Matuska  * If applicable, add the following below this CDDL HEADER, with the
16*16038816SMartin Matuska  * fields enclosed by brackets "[]" replaced with your own identifying
17*16038816SMartin Matuska  * information: Portions Copyright [yyyy] [name of copyright owner]
18*16038816SMartin Matuska  *
19*16038816SMartin Matuska  * CDDL HEADER END
20*16038816SMartin Matuska  */
21*16038816SMartin Matuska 
22*16038816SMartin Matuska 
23*16038816SMartin Matuska #include <sys/types.h>
24*16038816SMartin Matuska #include <sys/stat.h>
25*16038816SMartin Matuska #include <sys/file.h>
26*16038816SMartin Matuska #include <fcntl.h>
27*16038816SMartin Matuska #include <stdio.h>
28*16038816SMartin Matuska #include <errno.h>
29*16038816SMartin Matuska #include <libshare.h>
30*16038816SMartin Matuska #include "nfs.h"
31*16038816SMartin Matuska 
32*16038816SMartin Matuska 
33*16038816SMartin Matuska static int nfs_lock_fd = -1;
34*16038816SMartin Matuska 
35*16038816SMartin Matuska 
36*16038816SMartin Matuska /*
37*16038816SMartin Matuska  * nfs_exports_[lock|unlock] are used to guard against conconcurrent
38*16038816SMartin Matuska  * updates to the exports file. Each protocol is responsible for
39*16038816SMartin Matuska  * providing the necessary locking to ensure consistency.
40*16038816SMartin Matuska  */
41*16038816SMartin Matuska static int
42*16038816SMartin Matuska nfs_exports_lock(const char *name)
43*16038816SMartin Matuska {
44*16038816SMartin Matuska 	int err;
45*16038816SMartin Matuska 
46*16038816SMartin Matuska 	nfs_lock_fd = open(name, O_RDWR | O_CREAT | O_CLOEXEC, 0600);
47*16038816SMartin Matuska 	if (nfs_lock_fd == -1) {
48*16038816SMartin Matuska 		err = errno;
49*16038816SMartin Matuska 		fprintf(stderr, "failed to lock %s: %s\n", name, strerror(err));
50*16038816SMartin Matuska 		return (err);
51*16038816SMartin Matuska 	}
52*16038816SMartin Matuska 
53*16038816SMartin Matuska 	if (flock(nfs_lock_fd, LOCK_EX) != 0) {
54*16038816SMartin Matuska 		err = errno;
55*16038816SMartin Matuska 		fprintf(stderr, "failed to lock %s: %s\n", name, strerror(err));
56*16038816SMartin Matuska 		(void) close(nfs_lock_fd);
57*16038816SMartin Matuska 		nfs_lock_fd = -1;
58*16038816SMartin Matuska 		return (err);
59*16038816SMartin Matuska 	}
60*16038816SMartin Matuska 
61*16038816SMartin Matuska 	return (0);
62*16038816SMartin Matuska }
63*16038816SMartin Matuska 
64*16038816SMartin Matuska static void
65*16038816SMartin Matuska nfs_exports_unlock(const char *name)
66*16038816SMartin Matuska {
67*16038816SMartin Matuska 	verify(nfs_lock_fd > 0);
68*16038816SMartin Matuska 
69*16038816SMartin Matuska 	if (flock(nfs_lock_fd, LOCK_UN) != 0) {
70*16038816SMartin Matuska 		fprintf(stderr, "failed to unlock %s: %s\n",
71*16038816SMartin Matuska 		    name, strerror(errno));
72*16038816SMartin Matuska 	}
73*16038816SMartin Matuska 
74*16038816SMartin Matuska 	(void) close(nfs_lock_fd);
75*16038816SMartin Matuska 	nfs_lock_fd = -1;
76*16038816SMartin Matuska }
77*16038816SMartin Matuska 
78*16038816SMartin Matuska static char *
79*16038816SMartin Matuska nfs_init_tmpfile(const char *prefix, const char *mdir)
80*16038816SMartin Matuska {
81*16038816SMartin Matuska 	char *tmpfile = NULL;
82*16038816SMartin Matuska 	struct stat sb;
83*16038816SMartin Matuska 
84*16038816SMartin Matuska 	if (mdir != NULL &&
85*16038816SMartin Matuska 	    stat(mdir, &sb) < 0 &&
86*16038816SMartin Matuska 	    mkdir(mdir, 0755) < 0) {
87*16038816SMartin Matuska 		fprintf(stderr, "failed to create %s: %s\n",
88*16038816SMartin Matuska 		    mdir, strerror(errno));
89*16038816SMartin Matuska 		return (NULL);
90*16038816SMartin Matuska 	}
91*16038816SMartin Matuska 
92*16038816SMartin Matuska 	if (asprintf(&tmpfile, "%s.XXXXXXXX", prefix) == -1) {
93*16038816SMartin Matuska 		fprintf(stderr, "Unable to allocate temporary file\n");
94*16038816SMartin Matuska 		return (NULL);
95*16038816SMartin Matuska 	}
96*16038816SMartin Matuska 
97*16038816SMartin Matuska 	int fd = mkostemp(tmpfile, O_CLOEXEC);
98*16038816SMartin Matuska 	if (fd == -1) {
99*16038816SMartin Matuska 		fprintf(stderr, "Unable to create temporary file: %s",
100*16038816SMartin Matuska 		    strerror(errno));
101*16038816SMartin Matuska 		free(tmpfile);
102*16038816SMartin Matuska 		return (NULL);
103*16038816SMartin Matuska 	}
104*16038816SMartin Matuska 	close(fd);
105*16038816SMartin Matuska 	return (tmpfile);
106*16038816SMartin Matuska }
107*16038816SMartin Matuska 
108*16038816SMartin Matuska static int
109*16038816SMartin Matuska nfs_fini_tmpfile(const char *exports, char *tmpfile)
110*16038816SMartin Matuska {
111*16038816SMartin Matuska 	if (rename(tmpfile, exports) == -1) {
112*16038816SMartin Matuska 		fprintf(stderr, "Unable to rename %s: %s\n", tmpfile,
113*16038816SMartin Matuska 		    strerror(errno));
114*16038816SMartin Matuska 		unlink(tmpfile);
115*16038816SMartin Matuska 		free(tmpfile);
116*16038816SMartin Matuska 		return (SA_SYSTEM_ERR);
117*16038816SMartin Matuska 	}
118*16038816SMartin Matuska 	free(tmpfile);
119*16038816SMartin Matuska 	return (SA_OK);
120*16038816SMartin Matuska }
121*16038816SMartin Matuska 
122*16038816SMartin Matuska __attribute__((visibility("hidden"))) int
123*16038816SMartin Matuska nfs_toggle_share(const char *lockfile, const char *exports,
124*16038816SMartin Matuska     const char *expdir, sa_share_impl_t impl_share,
125*16038816SMartin Matuska     int(*cbk)(sa_share_impl_t impl_share, char *filename))
126*16038816SMartin Matuska {
127*16038816SMartin Matuska 	int error;
128*16038816SMartin Matuska 	char *filename;
129*16038816SMartin Matuska 
130*16038816SMartin Matuska 	if ((filename = nfs_init_tmpfile(exports, expdir)) == NULL)
131*16038816SMartin Matuska 		return (SA_SYSTEM_ERR);
132*16038816SMartin Matuska 
133*16038816SMartin Matuska 	error = nfs_exports_lock(lockfile);
134*16038816SMartin Matuska 	if (error != 0) {
135*16038816SMartin Matuska 		unlink(filename);
136*16038816SMartin Matuska 		free(filename);
137*16038816SMartin Matuska 		return (error);
138*16038816SMartin Matuska 	}
139*16038816SMartin Matuska 
140*16038816SMartin Matuska 	error = nfs_copy_entries(filename, impl_share->sa_mountpoint);
141*16038816SMartin Matuska 	if (error != SA_OK)
142*16038816SMartin Matuska 		goto fullerr;
143*16038816SMartin Matuska 
144*16038816SMartin Matuska 	error = cbk(impl_share, filename);
145*16038816SMartin Matuska 	if (error != SA_OK)
146*16038816SMartin Matuska 		goto fullerr;
147*16038816SMartin Matuska 
148*16038816SMartin Matuska 	error = nfs_fini_tmpfile(exports, filename);
149*16038816SMartin Matuska 	nfs_exports_unlock(lockfile);
150*16038816SMartin Matuska 	return (error);
151*16038816SMartin Matuska 
152*16038816SMartin Matuska fullerr:
153*16038816SMartin Matuska 	unlink(filename);
154*16038816SMartin Matuska 	free(filename);
155*16038816SMartin Matuska 	nfs_exports_unlock(lockfile);
156*16038816SMartin Matuska 	return (error);
157*16038816SMartin Matuska }
158