1 /* $NetBSD: chan.c,v 1.1 2022/01/22 08:09:40 pho Exp $ */ 2 3 /* 4 * Copyright (c) 2021 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote 16 * products derived from this software without specific prior written 17 * permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 20 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 25 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #if !defined(lint) 34 __RCSID("$NetBSD: chan.c,v 1.1 2022/01/22 08:09:40 pho Exp $"); 35 #endif /* !lint */ 36 37 #include <assert.h> 38 #include <err.h> 39 #include <fuse_internal.h> 40 #if defined(MULTITHREADED_REFUSE) 41 # include <pthread.h> 42 #endif 43 #include <stdlib.h> 44 #include <string.h> 45 46 /* The communication channel API is a part of the public interface of 47 * FUSE. However, it is actually an implementation detail and we can't 48 * really emulate its semantics. We only use it for implementing 49 * pre-3.0 fuse_mount(), i.e. the mount-before-new thingy. 50 */ 51 52 struct fuse_chan { 53 char* mountpoint; 54 struct fuse_args* args; 55 struct fuse* fuse; 56 bool is_to_be_destroyed; 57 }; 58 59 struct refuse_chan_storage { 60 size_t n_alloc; 61 struct fuse_chan** vec; 62 }; 63 64 #if defined(MULTITHREADED_REFUSE) 65 static pthread_mutex_t storage_mutex = PTHREAD_MUTEX_INITIALIZER; 66 #endif 67 static struct refuse_chan_storage storage; 68 69 70 struct fuse_chan* fuse_chan_new(const char* mountpoint, const struct fuse_args* args) { 71 struct fuse_chan* chan; 72 73 chan = calloc(1, sizeof(*chan)); 74 if (!chan) { 75 warn("%s", __func__); 76 return NULL; 77 } 78 79 chan->mountpoint = strdup(mountpoint); 80 if (!chan->mountpoint) { 81 warn("%s", __func__); 82 free(chan); 83 return NULL; 84 } 85 86 chan->args = fuse_opt_deep_copy_args(args->argc, args->argv); 87 if (!chan->args) { 88 warn("%s", __func__); 89 free(chan->mountpoint); 90 free(chan); 91 return NULL; 92 } 93 94 return chan; 95 } 96 97 void 98 fuse_chan_destroy(struct fuse_chan* chan) { 99 free(chan->mountpoint); 100 fuse_opt_free_args(chan->args); 101 free(chan->args); 102 free(chan); 103 } 104 105 int 106 fuse_chan_stash(struct fuse_chan* chan) { 107 int idx; 108 #if defined(MULTITHREADED_REFUSE) 109 int rv; 110 111 rv = pthread_mutex_lock(&storage_mutex); 112 assert(rv == 0); 113 #endif 114 115 /* Find the first empty slot in the storage. */ 116 for (idx = 0; idx < (int)storage.n_alloc; idx++) { 117 if (storage.vec[idx] == NULL) { 118 storage.vec[idx] = chan; 119 goto done; 120 } 121 } 122 123 /* Allocate more space */ 124 storage.n_alloc = (storage.n_alloc + 8) * 2; 125 storage.vec = realloc(storage.vec, sizeof(struct fuse_chan*) * storage.n_alloc); 126 if (!storage.vec) { 127 warn("%s", __func__); 128 idx = -1; 129 goto done; 130 } 131 132 storage.vec[idx] = chan; 133 memset(&storage.vec[idx+1], 0, sizeof(struct fuse_chan*) * (storage.n_alloc - (size_t)idx - 1)); 134 135 done: 136 #if defined(MULTITHREADED_REFUSE) 137 rv = pthread_mutex_unlock(&storage_mutex); 138 assert(rv == 0); 139 #endif 140 return idx; 141 } 142 143 /* Acquire a pointer to a stashed channel with a given index. */ 144 struct fuse_chan* fuse_chan_peek(int idx) { 145 struct fuse_chan* chan = NULL; 146 #if defined(MULTITHREADED_REFUSE) 147 int rv; 148 149 rv = pthread_mutex_lock(&storage_mutex); 150 assert(rv == 0); 151 #endif 152 153 if (idx >= 0 && idx < (int)storage.n_alloc) { 154 chan = storage.vec[idx]; 155 } 156 157 #if defined(MULTITHREADED_REFUSE) 158 rv = pthread_mutex_unlock(&storage_mutex); 159 assert(rv == 0); 160 #endif 161 return chan; 162 } 163 164 /* Like fuse_chan_peek() but also removes the channel from the 165 * storage. */ 166 struct fuse_chan* fuse_chan_take(int idx) { 167 struct fuse_chan* chan = NULL; 168 #if defined(MULTITHREADED_REFUSE) 169 int rv; 170 171 rv = pthread_mutex_lock(&storage_mutex); 172 assert(rv == 0); 173 #endif 174 175 if (idx >= 0 && idx < (int)storage.n_alloc) { 176 chan = storage.vec[idx]; 177 storage.vec[idx] = NULL; 178 } 179 180 #if defined(MULTITHREADED_REFUSE) 181 rv = pthread_mutex_unlock(&storage_mutex); 182 assert(rv == 0); 183 #endif 184 return chan; 185 } 186 187 /* Find the first stashed channel satisfying a given predicate in the 188 * storage, or NULL if no channels satisfy it. */ 189 struct fuse_chan* 190 fuse_chan_find(bool (*pred)(struct fuse_chan*, void*), 191 int* found_idx, void* priv) { 192 int idx; 193 struct fuse_chan* chan = NULL; 194 #if defined(MULTITHREADED_REFUSE) 195 int rv; 196 197 rv = pthread_mutex_lock(&storage_mutex); 198 assert(rv == 0); 199 #endif 200 201 for (idx = 0; idx < (int)storage.n_alloc; idx++) { 202 if (storage.vec[idx] != NULL) { 203 if (pred(storage.vec[idx], priv)) { 204 chan = storage.vec[idx]; 205 if (found_idx) 206 *found_idx = idx; 207 goto done; 208 } 209 } 210 } 211 212 done: 213 #if defined(MULTITHREADED_REFUSE) 214 rv = pthread_mutex_unlock(&storage_mutex); 215 assert(rv == 0); 216 #endif 217 return chan; 218 } 219 220 void 221 fuse_chan_set_fuse(struct fuse_chan* chan, struct fuse* fuse) { 222 chan->fuse = fuse; 223 } 224 225 void 226 fuse_chan_set_to_be_destroyed(struct fuse_chan* chan, bool is_to_be_destroyed) { 227 chan->is_to_be_destroyed = is_to_be_destroyed; 228 } 229 230 const char* 231 fuse_chan_mountpoint(const struct fuse_chan* chan) { 232 return chan->mountpoint; 233 } 234 235 struct fuse_args* 236 fuse_chan_args(struct fuse_chan* chan) { 237 return chan->args; 238 } 239 240 struct fuse* 241 fuse_chan_fuse(struct fuse_chan* chan) { 242 return chan->fuse; 243 } 244 245 bool 246 fuse_chan_is_to_be_destroyed(const struct fuse_chan* chan) { 247 return chan->is_to_be_destroyed; 248 } 249