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