4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 #include <sys/types.h>
33 static int nfs_lock_fd = -1;
37 * nfs_exports_[lock|unlock] are used to guard against conconcurrent
38 * updates to the exports file. Each protocol is responsible for
39 * providing the necessary locking to ensure consistency.
42 nfs_exports_lock(const char *name)
46 nfs_lock_fd = open(name, O_RDWR | O_CREAT | O_CLOEXEC, 0600);
47 if (nfs_lock_fd == -1) {
49 fprintf(stderr, "failed to lock %s: %s\n", name, strerror(err));
53 while ((err = flock(nfs_lock_fd, LOCK_EX)) != 0 && errno == EINTR)
57 fprintf(stderr, "failed to lock %s: %s\n", name, strerror(err));
58 (void) close(nfs_lock_fd);
67 nfs_exports_unlock(const char *name)
69 verify(nfs_lock_fd > 0);
71 if (flock(nfs_lock_fd, LOCK_UN) != 0) {
72 fprintf(stderr, "failed to unlock %s: %s\n",
73 name, strerror(errno));
76 (void) close(nfs_lock_fd);
82 * This only needs to be as wide as ZFS_EXPORTS_FILE and mktemp suffix,
83 * 64 is more than enough.
90 nfs_init_tmpfile(const char *prefix, const char *mdir, struct tmpfile *tmpf)
95 stat(mdir, &sb) < 0 &&
96 mkdir(mdir, 0755) < 0) {
97 fprintf(stderr, "failed to create %s: %s\n",
98 mdir, strerror(errno));
102 strcpy(tmpf->name, prefix);
103 strcat(tmpf->name, ".XXXXXXXX");
105 int fd = mkostemp(tmpf->name, O_CLOEXEC);
107 fprintf(stderr, "Unable to create temporary file: %s",
112 tmpf->fp = fdopen(fd, "w+");
113 if (tmpf->fp == NULL) {
114 fprintf(stderr, "Unable to reopen temporary file: %s",
124 nfs_abort_tmpfile(struct tmpfile *tmpf)
131 nfs_fini_tmpfile(const char *exports, struct tmpfile *tmpf)
133 if (fflush(tmpf->fp) != 0) {
134 fprintf(stderr, "Failed to write to temporary file: %s\n",
136 nfs_abort_tmpfile(tmpf);
137 return (SA_SYSTEM_ERR);
140 if (rename(tmpf->name, exports) == -1) {
141 fprintf(stderr, "Unable to rename %s -> %s: %s\n",
142 tmpf->name, exports, strerror(errno));
143 nfs_abort_tmpfile(tmpf);
144 return (SA_SYSTEM_ERR);
147 (void) fchmod(fileno(tmpf->fp), 0644);
153 nfs_process_exports(const char *exports, const char *mountpoint,
154 boolean_t (*cbk)(void *userdata, char *line, boolean_t found_mountpoint),
158 boolean_t cont = B_TRUE;
160 FILE *oldfp = fopen(exports, "re");
162 char *buf = NULL, *sep;
163 size_t buflen = 0, mplen = strlen(mountpoint);
165 while (cont && getline(&buf, &buflen, oldfp) != -1) {
166 if (buf[0] == '\n' || buf[0] == '#')
169 cont = cbk(userdata, buf,
170 (sep = strpbrk(buf, "\t \n")) != NULL &&
171 sep - buf == mplen &&
172 strncmp(buf, mountpoint, mplen) == 0);
176 if (ferror(oldfp) != 0)
177 error = ferror(oldfp);
179 if (fclose(oldfp) != 0) {
180 fprintf(stderr, "Unable to close file %s: %s\n",
181 exports, strerror(errno));
182 error = error != SA_OK ? error : SA_SYSTEM_ERR;
190 nfs_copy_entries_cb(void *userdata, char *line, boolean_t found_mountpoint)
192 FILE *newfp = userdata;
193 if (!found_mountpoint)
199 * Copy all entries from the exports file (if it exists) to newfp,
200 * omitting any entries for the specified mountpoint.
203 nfs_copy_entries(FILE *newfp, const char *exports, const char *mountpoint)
205 fputs(FILE_HEADER, newfp);
207 int error = nfs_process_exports(
208 exports, mountpoint, nfs_copy_entries_cb, newfp);
210 if (error == SA_OK && ferror(newfp) != 0)
211 error = ferror(newfp);
217 nfs_toggle_share(const char *lockfile, const char *exports,
218 const char *expdir, sa_share_impl_t impl_share,
219 int(*cbk)(sa_share_impl_t impl_share, FILE *tmpfile))
224 if (!nfs_init_tmpfile(exports, expdir, &tmpf))
225 return (SA_SYSTEM_ERR);
227 error = nfs_exports_lock(lockfile);
229 nfs_abort_tmpfile(&tmpf);
233 error = nfs_copy_entries(tmpf.fp, exports, impl_share->sa_mountpoint);
237 error = cbk(impl_share, tmpf.fp);
241 error = nfs_fini_tmpfile(exports, &tmpf);
242 nfs_exports_unlock(lockfile);
246 nfs_abort_tmpfile(&tmpf);
247 nfs_exports_unlock(lockfile);
252 nfs_is_shared_cb(void *userdata, char *line, boolean_t found_mountpoint)
254 boolean_t *found = userdata;
255 *found = found_mountpoint;
256 return (!found_mountpoint);
260 nfs_is_shared_impl(const char *exports, sa_share_impl_t impl_share)
262 boolean_t found = B_FALSE;
263 nfs_process_exports(exports, impl_share->sa_mountpoint,
264 nfs_is_shared_cb, &found);