1 /* 2 * CDDL HEADER START 3 * 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. 7 * 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. 12 * 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] 18 * 19 * CDDL HEADER END 20 */ 21 22 23 #include <sys/types.h> 24 #include <sys/stat.h> 25 #include <sys/file.h> 26 #include <fcntl.h> 27 #include <stdio.h> 28 #include <errno.h> 29 #include <libshare.h> 30 #include "nfs.h" 31 32 33 static int nfs_lock_fd = -1; 34 35 36 /* 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. 40 */ 41 static int 42 nfs_exports_lock(const char *name) 43 { 44 int err; 45 46 nfs_lock_fd = open(name, O_RDWR | O_CREAT | O_CLOEXEC, 0600); 47 if (nfs_lock_fd == -1) { 48 err = errno; 49 fprintf(stderr, "failed to lock %s: %s\n", name, strerror(err)); 50 return (err); 51 } 52 53 if (flock(nfs_lock_fd, LOCK_EX) != 0) { 54 err = errno; 55 fprintf(stderr, "failed to lock %s: %s\n", name, strerror(err)); 56 (void) close(nfs_lock_fd); 57 nfs_lock_fd = -1; 58 return (err); 59 } 60 61 return (0); 62 } 63 64 static void 65 nfs_exports_unlock(const char *name) 66 { 67 verify(nfs_lock_fd > 0); 68 69 if (flock(nfs_lock_fd, LOCK_UN) != 0) { 70 fprintf(stderr, "failed to unlock %s: %s\n", 71 name, strerror(errno)); 72 } 73 74 (void) close(nfs_lock_fd); 75 nfs_lock_fd = -1; 76 } 77 78 static char * 79 nfs_init_tmpfile(const char *prefix, const char *mdir) 80 { 81 char *tmpfile = NULL; 82 struct stat sb; 83 84 if (mdir != NULL && 85 stat(mdir, &sb) < 0 && 86 mkdir(mdir, 0755) < 0) { 87 fprintf(stderr, "failed to create %s: %s\n", 88 mdir, strerror(errno)); 89 return (NULL); 90 } 91 92 if (asprintf(&tmpfile, "%s.XXXXXXXX", prefix) == -1) { 93 fprintf(stderr, "Unable to allocate temporary file\n"); 94 return (NULL); 95 } 96 97 int fd = mkostemp(tmpfile, O_CLOEXEC); 98 if (fd == -1) { 99 fprintf(stderr, "Unable to create temporary file: %s", 100 strerror(errno)); 101 free(tmpfile); 102 return (NULL); 103 } 104 close(fd); 105 return (tmpfile); 106 } 107 108 static int 109 nfs_fini_tmpfile(const char *exports, char *tmpfile) 110 { 111 if (rename(tmpfile, exports) == -1) { 112 fprintf(stderr, "Unable to rename %s: %s\n", tmpfile, 113 strerror(errno)); 114 unlink(tmpfile); 115 free(tmpfile); 116 return (SA_SYSTEM_ERR); 117 } 118 free(tmpfile); 119 return (SA_OK); 120 } 121 122 int 123 nfs_toggle_share(const char *lockfile, const char *exports, 124 const char *expdir, sa_share_impl_t impl_share, 125 int(*cbk)(sa_share_impl_t impl_share, char *filename)) 126 { 127 int error; 128 char *filename; 129 130 if ((filename = nfs_init_tmpfile(exports, expdir)) == NULL) 131 return (SA_SYSTEM_ERR); 132 133 error = nfs_exports_lock(lockfile); 134 if (error != 0) { 135 unlink(filename); 136 free(filename); 137 return (error); 138 } 139 140 error = nfs_copy_entries(filename, impl_share->sa_mountpoint); 141 if (error != SA_OK) 142 goto fullerr; 143 144 error = cbk(impl_share, filename); 145 if (error != SA_OK) 146 goto fullerr; 147 148 error = nfs_fini_tmpfile(exports, filename); 149 nfs_exports_unlock(lockfile); 150 return (error); 151 152 fullerr: 153 unlink(filename); 154 free(filename); 155 nfs_exports_unlock(lockfile); 156 return (error); 157 } 158