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