1 1.129 rillig /* $NetBSD: puffs.c,v 1.129 2022/04/19 20:32:17 rillig Exp $ */ 2 1.1 pooka 3 1.1 pooka /* 4 1.44 pooka * Copyright (c) 2005, 2006, 2007 Antti Kantee. All Rights Reserved. 5 1.1 pooka * 6 1.1 pooka * Development of this software was supported by the 7 1.1 pooka * Google Summer of Code program and the Ulla Tuominen Foundation. 8 1.1 pooka * The Google SoC project was mentored by Bill Studenmund. 9 1.1 pooka * 10 1.1 pooka * Redistribution and use in source and binary forms, with or without 11 1.1 pooka * modification, are permitted provided that the following conditions 12 1.1 pooka * are met: 13 1.1 pooka * 1. Redistributions of source code must retain the above copyright 14 1.1 pooka * notice, this list of conditions and the following disclaimer. 15 1.1 pooka * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 pooka * notice, this list of conditions and the following disclaimer in the 17 1.1 pooka * documentation and/or other materials provided with the distribution. 18 1.1 pooka * 19 1.1 pooka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 20 1.1 pooka * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 1.1 pooka * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 1.1 pooka * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 1.1 pooka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 pooka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 1.1 pooka * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 pooka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 pooka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 pooka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 pooka * SUCH DAMAGE. 30 1.1 pooka */ 31 1.1 pooka 32 1.1 pooka #include <sys/cdefs.h> 33 1.1 pooka #if !defined(lint) 34 1.129 rillig __RCSID("$NetBSD: puffs.c,v 1.129 2022/04/19 20:32:17 rillig Exp $"); 35 1.1 pooka #endif /* !lint */ 36 1.1 pooka 37 1.1 pooka #include <sys/param.h> 38 1.1 pooka #include <sys/mount.h> 39 1.1 pooka 40 1.9 pooka #include <assert.h> 41 1.12 pooka #include <err.h> 42 1.1 pooka #include <errno.h> 43 1.1 pooka #include <fcntl.h> 44 1.21 pooka #include <mntopts.h> 45 1.58 pooka #include <paths.h> 46 1.115 pooka #include <pthread.h> 47 1.1 pooka #include <puffs.h> 48 1.1 pooka #include <stdio.h> 49 1.1 pooka #include <stdlib.h> 50 1.1 pooka #include <string.h> 51 1.1 pooka #include <syslog.h> 52 1.1 pooka #include <unistd.h> 53 1.1 pooka 54 1.19 pooka #include "puffs_priv.h" 55 1.19 pooka 56 1.21 pooka /* Most file systems want this for opts, so just give it to them */ 57 1.21 pooka const struct mntopt puffsmopts[] = { 58 1.21 pooka MOPT_STDOPTS, 59 1.21 pooka PUFFSMOPT_STD, 60 1.21 pooka MOPT_NULL, 61 1.21 pooka }; 62 1.21 pooka 63 1.72 pooka pthread_mutex_t pu_lock = PTHREAD_MUTEX_INITIALIZER; 64 1.72 pooka 65 1.10 pooka #define FILLOP(lower, upper) \ 66 1.10 pooka do { \ 67 1.13 pooka if (pops->puffs_node_##lower) \ 68 1.10 pooka opmask[PUFFS_VN_##upper] = 1; \ 69 1.129 rillig } while (0) 70 1.10 pooka static void 71 1.107 pooka fillvnopmask(struct puffs_ops *pops, struct puffs_kargs *pa) 72 1.10 pooka { 73 1.107 pooka uint8_t *opmask = pa->pa_vnopmask; 74 1.10 pooka 75 1.107 pooka memset(opmask, 0, sizeof(pa->pa_vnopmask)); 76 1.10 pooka 77 1.10 pooka FILLOP(create, CREATE); 78 1.10 pooka FILLOP(mknod, MKNOD); 79 1.10 pooka FILLOP(open, OPEN); 80 1.10 pooka FILLOP(close, CLOSE); 81 1.10 pooka FILLOP(access, ACCESS); 82 1.10 pooka FILLOP(getattr, GETATTR); 83 1.10 pooka FILLOP(setattr, SETATTR); 84 1.106 pooka FILLOP(poll, POLL); 85 1.16 pooka FILLOP(mmap, MMAP); 86 1.10 pooka FILLOP(fsync, FSYNC); 87 1.10 pooka FILLOP(seek, SEEK); 88 1.10 pooka FILLOP(remove, REMOVE); 89 1.10 pooka FILLOP(link, LINK); 90 1.10 pooka FILLOP(rename, RENAME); 91 1.10 pooka FILLOP(mkdir, MKDIR); 92 1.10 pooka FILLOP(rmdir, RMDIR); 93 1.10 pooka FILLOP(symlink, SYMLINK); 94 1.10 pooka FILLOP(readdir, READDIR); 95 1.10 pooka FILLOP(readlink, READLINK); 96 1.10 pooka FILLOP(reclaim, RECLAIM); 97 1.10 pooka FILLOP(inactive, INACTIVE); 98 1.10 pooka FILLOP(print, PRINT); 99 1.10 pooka FILLOP(read, READ); 100 1.10 pooka FILLOP(write, WRITE); 101 1.116 manu FILLOP(advlock, ADVLOCK); 102 1.99 pooka FILLOP(abortop, ABORTOP); 103 1.108 pooka FILLOP(pathconf, PATHCONF); 104 1.107 pooka 105 1.107 pooka FILLOP(getextattr, GETEXTATTR); 106 1.107 pooka FILLOP(setextattr, SETEXTATTR); 107 1.107 pooka FILLOP(listextattr, LISTEXTATTR); 108 1.107 pooka FILLOP(deleteextattr, DELETEEXTATTR); 109 1.118 manu FILLOP(fallocate, FALLOCATE); 110 1.118 manu FILLOP(fdiscard, FDISCARD); 111 1.19 pooka } 112 1.19 pooka #undef FILLOP 113 1.19 pooka 114 1.79 pooka /* 115 1.79 pooka * Go over all framev entries and write everything we can. This is 116 1.79 pooka * mostly for the benefit of delivering "unmount" to the kernel. 117 1.79 pooka */ 118 1.79 pooka static void 119 1.79 pooka finalpush(struct puffs_usermount *pu) 120 1.79 pooka { 121 1.79 pooka struct puffs_fctrl_io *fio; 122 1.79 pooka 123 1.79 pooka LIST_FOREACH(fio, &pu->pu_ios, fio_entries) { 124 1.79 pooka if (fio->stat & FIO_WRGONE) 125 1.79 pooka continue; 126 1.79 pooka 127 1.89 pooka puffs__framev_output(pu, fio->fctrl, fio); 128 1.79 pooka } 129 1.79 pooka } 130 1.79 pooka 131 1.64 pooka /*ARGSUSED*/ 132 1.101 pooka void 133 1.101 pooka puffs_kernerr_abort(struct puffs_usermount *pu, uint8_t type, 134 1.92 pooka int error, const char *str, puffs_cookie_t cookie) 135 1.63 pooka { 136 1.63 pooka 137 1.122 christos warnx("%s: type %d, error %d, cookie %p (%s)", __func__, 138 1.77 pooka type, error, cookie, str); 139 1.63 pooka abort(); 140 1.63 pooka } 141 1.63 pooka 142 1.101 pooka /*ARGSUSED*/ 143 1.101 pooka void 144 1.101 pooka puffs_kernerr_log(struct puffs_usermount *pu, uint8_t type, 145 1.101 pooka int error, const char *str, puffs_cookie_t cookie) 146 1.101 pooka { 147 1.101 pooka 148 1.122 christos syslog(LOG_WARNING, "%s: type %d, error %d, cookie %p (%s)", __func__, 149 1.101 pooka type, error, cookie, str); 150 1.101 pooka } 151 1.101 pooka 152 1.19 pooka int 153 1.19 pooka puffs_getselectable(struct puffs_usermount *pu) 154 1.19 pooka { 155 1.10 pooka 156 1.60 pooka return pu->pu_fd; 157 1.10 pooka } 158 1.19 pooka 159 1.80 pooka uint64_t 160 1.80 pooka puffs__nextreq(struct puffs_usermount *pu) 161 1.80 pooka { 162 1.80 pooka uint64_t rv; 163 1.80 pooka 164 1.80 pooka PU_LOCK(); 165 1.104 pooka rv = pu->pu_nextreq++ | (uint64_t)1<<63; 166 1.80 pooka PU_UNLOCK(); 167 1.80 pooka 168 1.80 pooka return rv; 169 1.80 pooka } 170 1.80 pooka 171 1.19 pooka int 172 1.19 pooka puffs_setblockingmode(struct puffs_usermount *pu, int mode) 173 1.19 pooka { 174 1.46 pooka int rv, x; 175 1.46 pooka 176 1.74 pooka assert(puffs_getstate(pu) == PUFFS_STATE_RUNNING); 177 1.74 pooka 178 1.46 pooka if (mode != PUFFSDEV_BLOCK && mode != PUFFSDEV_NONBLOCK) { 179 1.46 pooka errno = EINVAL; 180 1.46 pooka return -1; 181 1.46 pooka } 182 1.19 pooka 183 1.19 pooka x = mode; 184 1.60 pooka rv = ioctl(pu->pu_fd, FIONBIO, &x); 185 1.46 pooka 186 1.46 pooka if (rv == 0) { 187 1.46 pooka if (mode == PUFFSDEV_BLOCK) 188 1.46 pooka pu->pu_state &= ~PU_ASYNCFD; 189 1.46 pooka else 190 1.46 pooka pu->pu_state |= PU_ASYNCFD; 191 1.46 pooka } 192 1.46 pooka 193 1.46 pooka return rv; 194 1.19 pooka } 195 1.19 pooka 196 1.19 pooka int 197 1.19 pooka puffs_getstate(struct puffs_usermount *pu) 198 1.19 pooka { 199 1.19 pooka 200 1.44 pooka return pu->pu_state & PU_STATEMASK; 201 1.19 pooka } 202 1.19 pooka 203 1.19 pooka void 204 1.19 pooka puffs_setstacksize(struct puffs_usermount *pu, size_t ss) 205 1.19 pooka { 206 1.86 pooka long psize, minsize; 207 1.69 pooka int stackshift; 208 1.87 pooka int bonus; 209 1.78 pooka 210 1.86 pooka assert(puffs_getstate(pu) == PUFFS_STATE_BEFOREMOUNT); 211 1.86 pooka 212 1.78 pooka psize = sysconf(_SC_PAGESIZE); 213 1.87 pooka minsize = 4*psize; 214 1.98 lukem if (ss < (size_t)minsize || ss == PUFFS_STACKSIZE_MIN) { 215 1.86 pooka if (ss != PUFFS_STACKSIZE_MIN) 216 1.120 christos warnx("%s: adjusting " "stacksize to minimum %ld", 217 1.120 christos __func__, minsize); 218 1.87 pooka ss = 4*psize; 219 1.78 pooka } 220 1.69 pooka 221 1.69 pooka stackshift = -1; 222 1.87 pooka bonus = 0; 223 1.69 pooka while (ss) { 224 1.87 pooka if (ss & 0x1) 225 1.87 pooka bonus++; 226 1.69 pooka ss >>= 1; 227 1.69 pooka stackshift++; 228 1.69 pooka } 229 1.87 pooka if (bonus > 1) { 230 1.87 pooka stackshift++; 231 1.120 christos warnx("%s: using next power of two: %d", __func__, 232 1.120 christos 1 << stackshift); 233 1.87 pooka } 234 1.87 pooka 235 1.69 pooka pu->pu_cc_stackshift = stackshift; 236 1.19 pooka } 237 1.19 pooka 238 1.24 pooka struct puffs_pathobj * 239 1.24 pooka puffs_getrootpathobj(struct puffs_usermount *pu) 240 1.19 pooka { 241 1.19 pooka struct puffs_node *pnr; 242 1.19 pooka 243 1.19 pooka pnr = pu->pu_pn_root; 244 1.19 pooka if (pnr == NULL) { 245 1.19 pooka errno = ENOENT; 246 1.24 pooka return NULL; 247 1.19 pooka } 248 1.19 pooka 249 1.24 pooka return &pnr->pn_po; 250 1.24 pooka } 251 1.24 pooka 252 1.35 pooka void 253 1.35 pooka puffs_setroot(struct puffs_usermount *pu, struct puffs_node *pn) 254 1.35 pooka { 255 1.35 pooka 256 1.35 pooka pu->pu_pn_root = pn; 257 1.35 pooka } 258 1.35 pooka 259 1.35 pooka struct puffs_node * 260 1.35 pooka puffs_getroot(struct puffs_usermount *pu) 261 1.35 pooka { 262 1.35 pooka 263 1.35 pooka return pu->pu_pn_root; 264 1.35 pooka } 265 1.35 pooka 266 1.49 pooka void 267 1.49 pooka puffs_setrootinfo(struct puffs_usermount *pu, enum vtype vt, 268 1.127 pho size_t vsize, dev_t rdev) 269 1.49 pooka { 270 1.60 pooka struct puffs_kargs *pargs = pu->pu_kargp; 271 1.49 pooka 272 1.60 pooka if (puffs_getstate(pu) != PUFFS_STATE_BEFOREMOUNT) { 273 1.120 christos warnx("%s: call has effect only before mount", __func__); 274 1.60 pooka return; 275 1.60 pooka } 276 1.49 pooka 277 1.49 pooka pargs->pa_root_vtype = vt; 278 1.127 pho pargs->pa_root_vsize = (voff_t)vsize; 279 1.49 pooka pargs->pa_root_rdev = rdev; 280 1.49 pooka } 281 1.49 pooka 282 1.35 pooka void * 283 1.35 pooka puffs_getspecific(struct puffs_usermount *pu) 284 1.35 pooka { 285 1.35 pooka 286 1.35 pooka return pu->pu_privdata; 287 1.35 pooka } 288 1.35 pooka 289 1.93 pooka void 290 1.93 pooka puffs_setspecific(struct puffs_usermount *pu, void *privdata) 291 1.93 pooka { 292 1.93 pooka 293 1.93 pooka pu->pu_privdata = privdata; 294 1.93 pooka } 295 1.93 pooka 296 1.100 pooka void 297 1.100 pooka puffs_setmntinfo(struct puffs_usermount *pu, 298 1.100 pooka const char *mntfromname, const char *puffsname) 299 1.100 pooka { 300 1.100 pooka struct puffs_kargs *pargs = pu->pu_kargp; 301 1.100 pooka 302 1.100 pooka (void)strlcpy(pargs->pa_mntfromname, mntfromname, 303 1.100 pooka sizeof(pargs->pa_mntfromname)); 304 1.100 pooka (void)strlcpy(pargs->pa_typename, puffsname, 305 1.100 pooka sizeof(pargs->pa_typename)); 306 1.100 pooka } 307 1.100 pooka 308 1.35 pooka size_t 309 1.35 pooka puffs_getmaxreqlen(struct puffs_usermount *pu) 310 1.35 pooka { 311 1.35 pooka 312 1.60 pooka return pu->pu_maxreqlen; 313 1.35 pooka } 314 1.24 pooka 315 1.24 pooka void 316 1.37 pooka puffs_setmaxreqlen(struct puffs_usermount *pu, size_t reqlen) 317 1.37 pooka { 318 1.37 pooka 319 1.44 pooka if (puffs_getstate(pu) != PUFFS_STATE_BEFOREMOUNT) 320 1.120 christos warnx("%s: call has effect only before mount", __func__); 321 1.37 pooka 322 1.66 pooka pu->pu_kargp->pa_maxmsglen = reqlen; 323 1.37 pooka } 324 1.37 pooka 325 1.37 pooka void 326 1.38 pooka puffs_setfhsize(struct puffs_usermount *pu, size_t fhsize, int flags) 327 1.37 pooka { 328 1.37 pooka 329 1.44 pooka if (puffs_getstate(pu) != PUFFS_STATE_BEFOREMOUNT) 330 1.120 christos warnx("%s: call has effect only before mount", __func__); 331 1.37 pooka 332 1.60 pooka pu->pu_kargp->pa_fhsize = fhsize; 333 1.60 pooka pu->pu_kargp->pa_fhflags = flags; 334 1.37 pooka } 335 1.37 pooka 336 1.37 pooka void 337 1.37 pooka puffs_setncookiehash(struct puffs_usermount *pu, int nhash) 338 1.37 pooka { 339 1.37 pooka 340 1.44 pooka if (puffs_getstate(pu) != PUFFS_STATE_BEFOREMOUNT) 341 1.120 christos warnx("%s: call has effect only before mount", __func__); 342 1.37 pooka 343 1.60 pooka pu->pu_kargp->pa_nhashbuckets = nhash; 344 1.37 pooka } 345 1.37 pooka 346 1.37 pooka void 347 1.24 pooka puffs_set_pathbuild(struct puffs_usermount *pu, pu_pathbuild_fn fn) 348 1.24 pooka { 349 1.24 pooka 350 1.24 pooka pu->pu_pathbuild = fn; 351 1.24 pooka } 352 1.24 pooka 353 1.24 pooka void 354 1.24 pooka puffs_set_pathtransform(struct puffs_usermount *pu, pu_pathtransform_fn fn) 355 1.24 pooka { 356 1.24 pooka 357 1.24 pooka pu->pu_pathtransform = fn; 358 1.24 pooka } 359 1.24 pooka 360 1.24 pooka void 361 1.24 pooka puffs_set_pathcmp(struct puffs_usermount *pu, pu_pathcmp_fn fn) 362 1.24 pooka { 363 1.24 pooka 364 1.24 pooka pu->pu_pathcmp = fn; 365 1.24 pooka } 366 1.24 pooka 367 1.24 pooka void 368 1.24 pooka puffs_set_pathfree(struct puffs_usermount *pu, pu_pathfree_fn fn) 369 1.24 pooka { 370 1.19 pooka 371 1.24 pooka pu->pu_pathfree = fn; 372 1.19 pooka } 373 1.19 pooka 374 1.24 pooka void 375 1.24 pooka puffs_set_namemod(struct puffs_usermount *pu, pu_namemod_fn fn) 376 1.24 pooka { 377 1.24 pooka 378 1.24 pooka pu->pu_namemod = fn; 379 1.24 pooka } 380 1.19 pooka 381 1.40 pooka void 382 1.63 pooka puffs_set_errnotify(struct puffs_usermount *pu, pu_errnotify_fn fn) 383 1.63 pooka { 384 1.63 pooka 385 1.63 pooka pu->pu_errnotify = fn; 386 1.63 pooka } 387 1.63 pooka 388 1.63 pooka void 389 1.81 pooka puffs_set_cmap(struct puffs_usermount *pu, pu_cmap_fn fn) 390 1.81 pooka { 391 1.81 pooka 392 1.81 pooka pu->pu_cmap = fn; 393 1.81 pooka } 394 1.81 pooka 395 1.81 pooka void 396 1.46 pooka puffs_ml_setloopfn(struct puffs_usermount *pu, puffs_ml_loop_fn lfn) 397 1.46 pooka { 398 1.46 pooka 399 1.46 pooka pu->pu_ml_lfn = lfn; 400 1.46 pooka } 401 1.46 pooka 402 1.46 pooka void 403 1.46 pooka puffs_ml_settimeout(struct puffs_usermount *pu, struct timespec *ts) 404 1.46 pooka { 405 1.46 pooka 406 1.46 pooka if (ts == NULL) { 407 1.46 pooka pu->pu_ml_timep = NULL; 408 1.46 pooka } else { 409 1.46 pooka pu->pu_ml_timeout = *ts; 410 1.46 pooka pu->pu_ml_timep = &pu->pu_ml_timeout; 411 1.46 pooka } 412 1.46 pooka } 413 1.46 pooka 414 1.46 pooka void 415 1.71 pooka puffs_set_prepost(struct puffs_usermount *pu, 416 1.71 pooka pu_prepost_fn pre, pu_prepost_fn pst) 417 1.71 pooka { 418 1.71 pooka 419 1.71 pooka pu->pu_oppre = pre; 420 1.71 pooka pu->pu_oppost = pst; 421 1.71 pooka } 422 1.71 pooka 423 1.71 pooka void 424 1.40 pooka puffs_setback(struct puffs_cc *pcc, int whatback) 425 1.40 pooka { 426 1.79 pooka struct puffs_req *preq = puffs__framebuf_getdataptr(pcc->pcc_pb); 427 1.40 pooka 428 1.40 pooka assert(PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN && ( 429 1.40 pooka preq->preq_optype == PUFFS_VN_OPEN || 430 1.40 pooka preq->preq_optype == PUFFS_VN_MMAP || 431 1.40 pooka preq->preq_optype == PUFFS_VN_REMOVE || 432 1.54 pooka preq->preq_optype == PUFFS_VN_RMDIR || 433 1.54 pooka preq->preq_optype == PUFFS_VN_INACTIVE)); 434 1.40 pooka 435 1.40 pooka preq->preq_setbacks |= whatback & PUFFS_SETBACK_MASK; 436 1.40 pooka } 437 1.40 pooka 438 1.36 pooka int 439 1.75 pooka puffs_daemon(struct puffs_usermount *pu, int nochdir, int noclose) 440 1.75 pooka { 441 1.97 dsl long int n; 442 1.75 pooka int parent, value, fd; 443 1.128 pho bool is_beforemount; 444 1.75 pooka 445 1.128 pho is_beforemount = (puffs_getstate(pu) < PUFFS_STATE_RUNNING); 446 1.128 pho if (is_beforemount) 447 1.128 pho if (pipe(pu->pu_dpipe) == -1) 448 1.128 pho return -1; 449 1.75 pooka 450 1.75 pooka switch (fork()) { 451 1.75 pooka case -1: 452 1.75 pooka return -1; 453 1.75 pooka case 0: 454 1.75 pooka parent = 0; 455 1.75 pooka break; 456 1.75 pooka default: 457 1.75 pooka parent = 1; 458 1.75 pooka break; 459 1.75 pooka } 460 1.128 pho if (is_beforemount) 461 1.128 pho PU_SETSFLAG(pu, PU_PUFFSDAEMON); 462 1.75 pooka 463 1.75 pooka if (parent) { 464 1.128 pho if (is_beforemount) { 465 1.128 pho close(pu->pu_dpipe[1]); 466 1.128 pho n = read(pu->pu_dpipe[0], &value, sizeof(int)); 467 1.128 pho if (n == -1) 468 1.128 pho err(1, "puffs_daemon"); 469 1.128 pho if (n != sizeof(value)) 470 1.128 pho errx(1, "puffs_daemon got %ld bytes", n); 471 1.128 pho if (value) { 472 1.128 pho errno = value; 473 1.128 pho err(1, "puffs_daemon"); 474 1.128 pho } 475 1.75 pooka } 476 1.75 pooka exit(0); 477 1.75 pooka } else { 478 1.75 pooka if (setsid() == -1) 479 1.75 pooka goto fail; 480 1.75 pooka 481 1.75 pooka if (!nochdir) 482 1.75 pooka chdir("/"); 483 1.75 pooka 484 1.75 pooka if (!noclose) { 485 1.75 pooka fd = open(_PATH_DEVNULL, O_RDWR, 0); 486 1.75 pooka if (fd == -1) 487 1.75 pooka goto fail; 488 1.75 pooka dup2(fd, STDIN_FILENO); 489 1.75 pooka dup2(fd, STDOUT_FILENO); 490 1.75 pooka dup2(fd, STDERR_FILENO); 491 1.75 pooka if (fd > STDERR_FILENO) 492 1.75 pooka close(fd); 493 1.75 pooka } 494 1.75 pooka return 0; 495 1.75 pooka } 496 1.75 pooka 497 1.75 pooka fail: 498 1.128 pho if (is_beforemount) { 499 1.128 pho n = write(pu->pu_dpipe[1], &errno, sizeof(int)); 500 1.128 pho assert(n == 4); 501 1.128 pho } 502 1.75 pooka return -1; 503 1.75 pooka } 504 1.75 pooka 505 1.94 pooka static void 506 1.94 pooka shutdaemon(struct puffs_usermount *pu, int error) 507 1.94 pooka { 508 1.94 pooka ssize_t n; 509 1.94 pooka 510 1.94 pooka n = write(pu->pu_dpipe[1], &error, sizeof(int)); 511 1.94 pooka assert(n == 4); 512 1.94 pooka close(pu->pu_dpipe[0]); 513 1.94 pooka close(pu->pu_dpipe[1]); 514 1.94 pooka pu->pu_state &= ~PU_PUFFSDAEMON; 515 1.94 pooka } 516 1.94 pooka 517 1.75 pooka int 518 1.49 pooka puffs_mount(struct puffs_usermount *pu, const char *dir, int mntflags, 519 1.92 pooka puffs_cookie_t cookie) 520 1.36 pooka { 521 1.75 pooka int rv, fd, sverrno; 522 1.82 pooka char *comfd; 523 1.82 pooka 524 1.82 pooka pu->pu_kargp->pa_root_cookie = cookie; 525 1.36 pooka 526 1.36 pooka /* XXXkludgehere */ 527 1.36 pooka /* kauth doesn't provide this service any longer */ 528 1.36 pooka if (geteuid() != 0) 529 1.36 pooka mntflags |= MNT_NOSUID | MNT_NODEV; 530 1.36 pooka 531 1.82 pooka /* 532 1.82 pooka * Undocumented... Well, documented only here. 533 1.82 pooka * 534 1.82 pooka * This is used for imaginative purposes. If the env variable is 535 1.82 pooka * set, puffs_mount() doesn't do the regular mount procedure. 536 1.82 pooka * Rather, it crams the mount data down the comfd and sets comfd as 537 1.82 pooka * the puffs descriptor. 538 1.82 pooka * 539 1.82 pooka * This shouldn't be used unless you can read my mind ( ... or write 540 1.82 pooka * it, not to mention execute it, but that's starting to get silly). 541 1.82 pooka */ 542 1.82 pooka if ((comfd = getenv("PUFFS_COMFD")) != NULL) { 543 1.82 pooka size_t len; 544 1.82 pooka 545 1.82 pooka if (sscanf(comfd, "%d", &pu->pu_fd) != 1) { 546 1.82 pooka errno = EINVAL; 547 1.82 pooka rv = -1; 548 1.82 pooka goto out; 549 1.82 pooka } 550 1.82 pooka /* check that what we got at least resembles an fd */ 551 1.82 pooka if (fcntl(pu->pu_fd, F_GETFL) == -1) { 552 1.82 pooka rv = -1; 553 1.82 pooka goto out; 554 1.82 pooka } 555 1.82 pooka 556 1.82 pooka #define allwrite(buf, len) \ 557 1.82 pooka do { \ 558 1.82 pooka ssize_t al_rv; \ 559 1.82 pooka al_rv = write(pu->pu_fd, buf, len); \ 560 1.98 lukem if ((size_t)al_rv != len) { \ 561 1.82 pooka if (al_rv != -1) \ 562 1.82 pooka errno = EIO; \ 563 1.82 pooka rv = -1; \ 564 1.82 pooka goto out; \ 565 1.82 pooka } \ 566 1.129 rillig } while (0) 567 1.111 pooka len = strlen(dir)+1; 568 1.82 pooka allwrite(&len, sizeof(len)); 569 1.82 pooka allwrite(dir, len); 570 1.84 pooka len = strlen(pu->pu_kargp->pa_mntfromname)+1; 571 1.83 pooka allwrite(&len, sizeof(len)); 572 1.83 pooka allwrite(pu->pu_kargp->pa_mntfromname, len); 573 1.82 pooka allwrite(&mntflags, sizeof(mntflags)); 574 1.111 pooka len = sizeof(*pu->pu_kargp); 575 1.111 pooka allwrite(&len, sizeof(len)); 576 1.82 pooka allwrite(pu->pu_kargp, sizeof(*pu->pu_kargp)); 577 1.82 pooka allwrite(&pu->pu_flags, sizeof(pu->pu_flags)); 578 1.82 pooka #undef allwrite 579 1.82 pooka 580 1.82 pooka rv = 0; 581 1.82 pooka } else { 582 1.113 pooka char rp[MAXPATHLEN]; 583 1.119 manu size_t rplen,dirlen; 584 1.113 pooka 585 1.113 pooka if (realpath(dir, rp) == NULL) { 586 1.113 pooka rv = -1; 587 1.113 pooka goto out; 588 1.113 pooka } 589 1.113 pooka 590 1.119 manu rplen = strlen(rp); 591 1.119 manu dirlen = strlen(dir); 592 1.119 manu if (strncmp(dir, rp, rplen) != 0 || 593 1.119 manu strspn(dir + rplen, "/") != dirlen - rplen) { 594 1.122 christos warnx("%s: `%s' is a %s path.", __func__, dir, 595 1.122 christos dir[0] != '/' ? "relative" : "non canonical"); 596 1.122 christos warnx("%s: using `%s' instead.", __func__, rp); 597 1.113 pooka } 598 1.113 pooka 599 1.82 pooka fd = open(_PATH_PUFFS, O_RDWR); 600 1.82 pooka if (fd == -1) { 601 1.122 christos warnx("%s: cannot open `%s'", __func__, _PATH_PUFFS); 602 1.82 pooka rv = -1; 603 1.82 pooka goto out; 604 1.82 pooka } 605 1.82 pooka if (fd <= 2) 606 1.122 christos warnx("%s: device fd %d (<= 2), sure this is " 607 1.122 christos "what you want?", __func__, fd); 608 1.82 pooka 609 1.82 pooka pu->pu_kargp->pa_fd = pu->pu_fd = fd; 610 1.82 pooka if ((rv = mount(MOUNT_PUFFS, rp, mntflags, 611 1.82 pooka pu->pu_kargp, sizeof(struct puffs_kargs))) == -1) 612 1.82 pooka goto out; 613 1.74 pooka } 614 1.74 pooka 615 1.49 pooka PU_SETSTATE(pu, PUFFS_STATE_RUNNING); 616 1.36 pooka 617 1.60 pooka out: 618 1.76 pooka if (rv != 0) 619 1.76 pooka sverrno = errno; 620 1.76 pooka else 621 1.76 pooka sverrno = 0; 622 1.60 pooka free(pu->pu_kargp); 623 1.60 pooka pu->pu_kargp = NULL; 624 1.60 pooka 625 1.128 pho if (PU_GETSFLAG(pu, PU_PUFFSDAEMON)) 626 1.94 pooka shutdaemon(pu, sverrno); 627 1.75 pooka 628 1.75 pooka errno = sverrno; 629 1.60 pooka return rv; 630 1.36 pooka } 631 1.10 pooka 632 1.1 pooka struct puffs_usermount * 633 1.107 pooka puffs_init(struct puffs_ops *pops, const char *mntfromname, 634 1.58 pooka const char *puffsname, void *priv, uint32_t pflags) 635 1.1 pooka { 636 1.1 pooka struct puffs_usermount *pu; 637 1.36 pooka struct puffs_kargs *pargs; 638 1.74 pooka int sverrno; 639 1.1 pooka 640 1.100 pooka if (puffsname == PUFFS_DEFER) 641 1.100 pooka puffsname = "n/a"; 642 1.100 pooka if (mntfromname == PUFFS_DEFER) 643 1.100 pooka mntfromname = "n/a"; 644 1.100 pooka if (priv == PUFFS_DEFER) 645 1.100 pooka priv = NULL; 646 1.100 pooka 647 1.36 pooka pu = malloc(sizeof(struct puffs_usermount)); 648 1.36 pooka if (pu == NULL) 649 1.36 pooka goto failfree; 650 1.47 pooka memset(pu, 0, sizeof(struct puffs_usermount)); 651 1.1 pooka 652 1.60 pooka pargs = pu->pu_kargp = malloc(sizeof(struct puffs_kargs)); 653 1.60 pooka if (pargs == NULL) 654 1.60 pooka goto failfree; 655 1.60 pooka memset(pargs, 0, sizeof(struct puffs_kargs)); 656 1.60 pooka 657 1.107 pooka pargs->pa_vers = PUFFSVERSION; 658 1.36 pooka pargs->pa_flags = PUFFS_FLAG_KERN(pflags); 659 1.107 pooka fillvnopmask(pops, pargs); 660 1.100 pooka puffs_setmntinfo(pu, mntfromname, puffsname); 661 1.1 pooka 662 1.49 pooka puffs_zerostatvfs(&pargs->pa_svfsb); 663 1.49 pooka pargs->pa_root_cookie = NULL; 664 1.49 pooka pargs->pa_root_vtype = VDIR; 665 1.49 pooka pargs->pa_root_vsize = 0; 666 1.49 pooka pargs->pa_root_rdev = 0; 667 1.66 pooka pargs->pa_maxmsglen = 0; 668 1.114 pooka if (/*CONSTCOND*/ sizeof(time_t) == 4) 669 1.112 pooka pargs->pa_time32 = 1; 670 1.112 pooka else 671 1.112 pooka pargs->pa_time32 = 0; 672 1.49 pooka 673 1.1 pooka pu->pu_flags = pflags; 674 1.13 pooka pu->pu_ops = *pops; 675 1.21 pooka free(pops); /* XXX */ 676 1.36 pooka 677 1.19 pooka pu->pu_privdata = priv; 678 1.69 pooka pu->pu_cc_stackshift = PUFFS_CC_STACKSHIFT_DEFAULT; 679 1.1 pooka LIST_INIT(&pu->pu_pnodelst); 680 1.79 pooka LIST_INIT(&pu->pu_ios); 681 1.79 pooka LIST_INIT(&pu->pu_ios_rmlist); 682 1.88 pooka LIST_INIT(&pu->pu_ccmagazin); 683 1.67 pooka TAILQ_INIT(&pu->pu_sched); 684 1.1 pooka 685 1.89 pooka pu->pu_framectrl[PU_FRAMECTRL_FS].rfb = puffs__fsframe_read; 686 1.89 pooka pu->pu_framectrl[PU_FRAMECTRL_FS].wfb = puffs__fsframe_write; 687 1.89 pooka pu->pu_framectrl[PU_FRAMECTRL_FS].cmpfb = puffs__fsframe_cmp; 688 1.89 pooka pu->pu_framectrl[PU_FRAMECTRL_FS].gotfb = puffs__fsframe_gotframe; 689 1.79 pooka pu->pu_framectrl[PU_FRAMECTRL_FS].fdnotfn = puffs_framev_unmountonclose; 690 1.79 pooka 691 1.24 pooka /* defaults for some user-settable translation functions */ 692 1.24 pooka pu->pu_cmap = NULL; /* identity translation */ 693 1.24 pooka 694 1.30 pooka pu->pu_pathbuild = puffs_stdpath_buildpath; 695 1.30 pooka pu->pu_pathfree = puffs_stdpath_freepath; 696 1.30 pooka pu->pu_pathcmp = puffs_stdpath_cmppath; 697 1.24 pooka pu->pu_pathtransform = NULL; 698 1.24 pooka pu->pu_namemod = NULL; 699 1.24 pooka 700 1.101 pooka pu->pu_errnotify = puffs_kernerr_log; 701 1.63 pooka 702 1.44 pooka PU_SETSTATE(pu, PUFFS_STATE_BEFOREMOUNT); 703 1.1 pooka 704 1.1 pooka return pu; 705 1.6 pooka 706 1.1 pooka failfree: 707 1.6 pooka /* can't unmount() from here for obvious reasons */ 708 1.60 pooka sverrno = errno; 709 1.1 pooka free(pu); 710 1.60 pooka errno = sverrno; 711 1.1 pooka return NULL; 712 1.1 pooka } 713 1.1 pooka 714 1.94 pooka void 715 1.94 pooka puffs_cancel(struct puffs_usermount *pu, int error) 716 1.94 pooka { 717 1.94 pooka assert(puffs_getstate(pu) < PUFFS_STATE_RUNNING); 718 1.128 pho assert(PU_GETSFLAG(pu, PU_PUFFSDAEMON)); 719 1.94 pooka shutdaemon(pu, error); 720 1.94 pooka free(pu); 721 1.94 pooka } 722 1.94 pooka 723 1.36 pooka /*ARGSUSED1*/ 724 1.21 pooka int 725 1.103 pooka puffs_exit(struct puffs_usermount *pu, int unused /* strict compat */) 726 1.21 pooka { 727 1.103 pooka struct puffs_framebuf *pb; 728 1.103 pooka struct puffs_req *preq; 729 1.103 pooka void *winp; 730 1.103 pooka size_t winlen; 731 1.103 pooka int sverrno; 732 1.21 pooka 733 1.103 pooka pb = puffs_framebuf_make(); 734 1.103 pooka if (pb == NULL) { 735 1.103 pooka errno = ENOMEM; 736 1.103 pooka return -1; 737 1.103 pooka } 738 1.21 pooka 739 1.103 pooka winlen = sizeof(struct puffs_req); 740 1.103 pooka if (puffs_framebuf_getwindow(pb, 0, &winp, &winlen) == -1) { 741 1.103 pooka sverrno = errno; 742 1.103 pooka puffs_framebuf_destroy(pb); 743 1.103 pooka errno = sverrno; 744 1.103 pooka return -1; 745 1.103 pooka } 746 1.103 pooka preq = winp; 747 1.21 pooka 748 1.103 pooka preq->preq_buflen = sizeof(struct puffs_req); 749 1.103 pooka preq->preq_opclass = PUFFSOP_UNMOUNT; 750 1.103 pooka preq->preq_id = puffs__nextreq(pu); 751 1.44 pooka 752 1.103 pooka puffs_framev_enqueue_justsend(pu, puffs_getselectable(pu), pb, 1, 0); 753 1.21 pooka 754 1.103 pooka return 0; 755 1.21 pooka } 756 1.21 pooka 757 1.123 dholland /* no sigset_t static initializer */ 758 1.105 pooka static int sigs[NSIG] = { 0, }; 759 1.105 pooka static int sigcatch = 0; 760 1.105 pooka 761 1.105 pooka int 762 1.105 pooka puffs_unmountonsignal(int sig, bool sigignore) 763 1.105 pooka { 764 1.105 pooka 765 1.105 pooka if (sig < 0 || sig >= (int)NSIG) { 766 1.105 pooka errno = EINVAL; 767 1.105 pooka return -1; 768 1.105 pooka } 769 1.105 pooka if (sigignore) 770 1.105 pooka if (signal(sig, SIG_IGN) == SIG_ERR) 771 1.105 pooka return -1; 772 1.105 pooka 773 1.105 pooka if (!sigs[sig]) 774 1.105 pooka sigcatch++; 775 1.105 pooka sigs[sig] = 1; 776 1.105 pooka 777 1.105 pooka return 0; 778 1.105 pooka } 779 1.105 pooka 780 1.89 pooka /* 781 1.89 pooka * Actual mainloop. This is called from a context which can block. 782 1.89 pooka * It is called either from puffs_mainloop (indirectly, via 783 1.89 pooka * puffs_cc_continue() or from puffs_cc_yield()). 784 1.89 pooka */ 785 1.89 pooka void 786 1.89 pooka puffs__theloop(struct puffs_cc *pcc) 787 1.1 pooka { 788 1.89 pooka struct puffs_usermount *pu = pcc->pcc_pu; 789 1.79 pooka struct puffs_framectrl *pfctrl; 790 1.44 pooka struct puffs_fctrl_io *fio; 791 1.79 pooka struct kevent *curev; 792 1.44 pooka size_t nchanges; 793 1.89 pooka int ndone; 794 1.44 pooka 795 1.89 pooka while (puffs_getstate(pu) != PUFFS_STATE_UNMOUNTED) { 796 1.105 pooka 797 1.89 pooka /* 798 1.89 pooka * Schedule existing requests. 799 1.89 pooka */ 800 1.89 pooka while ((pcc = TAILQ_FIRST(&pu->pu_sched)) != NULL) { 801 1.89 pooka TAILQ_REMOVE(&pu->pu_sched, pcc, pcc_schedent); 802 1.89 pooka puffs__goto(pcc); 803 1.89 pooka } 804 1.19 pooka 805 1.46 pooka if (pu->pu_ml_lfn) 806 1.46 pooka pu->pu_ml_lfn(pu); 807 1.46 pooka 808 1.79 pooka /* XXX: can we still do these optimizations? */ 809 1.79 pooka #if 0 810 1.55 pooka /* 811 1.55 pooka * Do this here, because: 812 1.55 pooka * a) loopfunc might generate some results 813 1.55 pooka * b) it's still "after" event handling (except for round 1) 814 1.55 pooka */ 815 1.55 pooka if (puffs_req_putput(ppr) == -1) 816 1.55 pooka goto out; 817 1.55 pooka puffs_req_resetput(ppr); 818 1.55 pooka 819 1.46 pooka /* micro optimization: skip kevent syscall if possible */ 820 1.79 pooka if (pu->pu_nfds == 1 && pu->pu_ml_timep == NULL 821 1.46 pooka && (pu->pu_state & PU_ASYNCFD) == 0) { 822 1.79 pooka pfctrl = XXX->fctrl; 823 1.79 pooka puffs_framev_input(pu, pfctrl, XXX); 824 1.46 pooka continue; 825 1.46 pooka } 826 1.79 pooka #endif 827 1.55 pooka 828 1.46 pooka /* else: do full processing */ 829 1.79 pooka /* Don't bother worrying about O(n) for now */ 830 1.79 pooka LIST_FOREACH(fio, &pu->pu_ios, fio_entries) { 831 1.46 pooka if (fio->stat & FIO_WRGONE) 832 1.46 pooka continue; 833 1.46 pooka 834 1.79 pooka pfctrl = fio->fctrl; 835 1.79 pooka 836 1.44 pooka /* 837 1.44 pooka * Try to write out everything to avoid the 838 1.44 pooka * need for enabling EVFILT_WRITE. The likely 839 1.44 pooka * case is that we can fit everything into the 840 1.44 pooka * socket buffer. 841 1.44 pooka */ 842 1.89 pooka puffs__framev_output(pu, pfctrl, fio); 843 1.79 pooka } 844 1.79 pooka 845 1.79 pooka /* 846 1.79 pooka * Build list of which to enable/disable in writecheck. 847 1.79 pooka */ 848 1.80 pooka nchanges = 0; 849 1.79 pooka LIST_FOREACH(fio, &pu->pu_ios, fio_entries) { 850 1.79 pooka if (fio->stat & FIO_WRGONE) 851 1.79 pooka continue; 852 1.19 pooka 853 1.46 pooka /* en/disable write checks for kqueue as needed */ 854 1.44 pooka assert((FIO_EN_WRITE(fio) && FIO_RM_WRITE(fio)) == 0); 855 1.44 pooka if (FIO_EN_WRITE(fio)) { 856 1.79 pooka EV_SET(&pu->pu_evs[nchanges], fio->io_fd, 857 1.44 pooka EVFILT_WRITE, EV_ENABLE, 0, 0, 858 1.121 christos (intptr_t)fio); 859 1.46 pooka fio->stat |= FIO_WR; 860 1.44 pooka nchanges++; 861 1.44 pooka } 862 1.44 pooka if (FIO_RM_WRITE(fio)) { 863 1.79 pooka EV_SET(&pu->pu_evs[nchanges], fio->io_fd, 864 1.44 pooka EVFILT_WRITE, EV_DISABLE, 0, 0, 865 1.121 christos (intptr_t)fio); 866 1.46 pooka fio->stat &= ~FIO_WR; 867 1.44 pooka nchanges++; 868 1.44 pooka } 869 1.19 pooka } 870 1.44 pooka 871 1.79 pooka ndone = kevent(pu->pu_kq, pu->pu_evs, nchanges, 872 1.105 pooka pu->pu_evs, pu->pu_nevs, pu->pu_ml_timep); 873 1.50 pooka 874 1.50 pooka if (ndone == -1) { 875 1.50 pooka if (errno != EINTR) 876 1.89 pooka break; 877 1.50 pooka else 878 1.50 pooka continue; 879 1.50 pooka } 880 1.50 pooka 881 1.50 pooka /* uoptimize */ 882 1.46 pooka if (ndone == 0) 883 1.46 pooka continue; 884 1.44 pooka 885 1.44 pooka /* iterate over the results */ 886 1.79 pooka for (curev = pu->pu_evs; ndone--; curev++) { 887 1.61 pooka int what; 888 1.61 pooka 889 1.79 pooka #if 0 890 1.44 pooka /* get & possibly dispatch events from kernel */ 891 1.44 pooka if (curev->ident == puffsfd) { 892 1.44 pooka if (puffs_req_handle(pgr, ppr, 0) == -1) 893 1.44 pooka goto out; 894 1.44 pooka continue; 895 1.44 pooka } 896 1.79 pooka #endif 897 1.44 pooka 898 1.46 pooka fio = (void *)curev->udata; 899 1.105 pooka if (__predict_true(fio)) 900 1.105 pooka pfctrl = fio->fctrl; 901 1.105 pooka else 902 1.105 pooka pfctrl = NULL; 903 1.46 pooka if (curev->flags & EV_ERROR) { 904 1.46 pooka assert(curev->filter == EVFILT_WRITE); 905 1.46 pooka fio->stat &= ~FIO_WR; 906 1.46 pooka 907 1.46 pooka /* XXX: how to know if it's a transient error */ 908 1.89 pooka puffs__framev_writeclose(pu, fio, 909 1.46 pooka (int)curev->data); 910 1.89 pooka puffs__framev_notify(fio, PUFFS_FBIO_ERROR); 911 1.46 pooka continue; 912 1.44 pooka } 913 1.44 pooka 914 1.61 pooka what = 0; 915 1.124 christos switch (curev->filter) { 916 1.124 christos case EVFILT_READ: 917 1.89 pooka puffs__framev_input(pu, pfctrl, fio); 918 1.61 pooka what |= PUFFS_FBIO_READ; 919 1.124 christos break; 920 1.124 christos case EVFILT_WRITE: 921 1.89 pooka puffs__framev_output(pu, pfctrl, fio); 922 1.61 pooka what |= PUFFS_FBIO_WRITE; 923 1.124 christos break; 924 1.124 christos case EVFILT_SIGNAL: 925 1.105 pooka if ((pu->pu_state & PU_DONEXIT) == 0) { 926 1.105 pooka PU_SETSFLAG(pu, PU_DONEXIT); 927 1.105 pooka puffs_exit(pu, 0); 928 1.105 pooka } 929 1.124 christos break; 930 1.124 christos default: 931 1.124 christos warn("unhandled filter %d", curev->filter); 932 1.105 pooka } 933 1.61 pooka if (what) 934 1.89 pooka puffs__framev_notify(fio, what); 935 1.67 pooka } 936 1.67 pooka 937 1.67 pooka /* 938 1.46 pooka * Really free fd's now that we don't have references 939 1.46 pooka * to them. 940 1.46 pooka */ 941 1.79 pooka while ((fio = LIST_FIRST(&pu->pu_ios_rmlist)) != NULL) { 942 1.46 pooka LIST_REMOVE(fio, fio_entries); 943 1.46 pooka free(fio); 944 1.46 pooka } 945 1.18 alc } 946 1.90 pooka 947 1.90 pooka if (puffs__cc_restoremain(pu) == -1) 948 1.90 pooka warn("cannot restore main context. impending doom"); 949 1.89 pooka } 950 1.89 pooka int 951 1.89 pooka puffs_mainloop(struct puffs_usermount *pu) 952 1.89 pooka { 953 1.89 pooka struct puffs_fctrl_io *fio; 954 1.89 pooka struct puffs_cc *pcc; 955 1.89 pooka struct kevent *curev; 956 1.105 pooka size_t nevs; 957 1.105 pooka int sverrno, i; 958 1.89 pooka 959 1.89 pooka assert(puffs_getstate(pu) >= PUFFS_STATE_RUNNING); 960 1.89 pooka 961 1.89 pooka pu->pu_kq = kqueue(); 962 1.89 pooka if (pu->pu_kq == -1) 963 1.89 pooka goto out; 964 1.89 pooka pu->pu_state |= PU_HASKQ; 965 1.89 pooka 966 1.89 pooka puffs_setblockingmode(pu, PUFFSDEV_NONBLOCK); 967 1.89 pooka if (puffs__framev_addfd_ctrl(pu, puffs_getselectable(pu), 968 1.89 pooka PUFFS_FBIO_READ | PUFFS_FBIO_WRITE, 969 1.89 pooka &pu->pu_framectrl[PU_FRAMECTRL_FS]) == -1) 970 1.89 pooka goto out; 971 1.89 pooka 972 1.105 pooka nevs = pu->pu_nevs + sigcatch; 973 1.125 nia if (reallocarr(&pu->pu_evs, nevs, sizeof(struct kevent)) != 0) { 974 1.125 nia errno = ENOMEM; 975 1.89 pooka goto out; 976 1.125 nia } 977 1.105 pooka pu->pu_nevs = nevs; 978 1.89 pooka 979 1.125 nia curev = pu->pu_evs; 980 1.125 nia 981 1.89 pooka LIST_FOREACH(fio, &pu->pu_ios, fio_entries) { 982 1.89 pooka EV_SET(curev, fio->io_fd, EVFILT_READ, EV_ADD, 983 1.121 christos 0, 0, (intptr_t)fio); 984 1.89 pooka curev++; 985 1.89 pooka EV_SET(curev, fio->io_fd, EVFILT_WRITE, EV_ADD | EV_DISABLE, 986 1.121 christos 0, 0, (intptr_t)fio); 987 1.89 pooka curev++; 988 1.89 pooka } 989 1.105 pooka for (i = 0; i < NSIG; i++) { 990 1.105 pooka if (sigs[i]) { 991 1.105 pooka EV_SET(curev, i, EVFILT_SIGNAL, EV_ADD | EV_ENABLE, 992 1.105 pooka 0, 0, 0); 993 1.105 pooka curev++; 994 1.105 pooka } 995 1.105 pooka } 996 1.105 pooka assert(curev - pu->pu_evs == (ssize_t)pu->pu_nevs); 997 1.105 pooka if (kevent(pu->pu_kq, pu->pu_evs, pu->pu_nevs, NULL, 0, NULL) == -1) 998 1.89 pooka goto out; 999 1.89 pooka 1000 1.89 pooka pu->pu_state |= PU_INLOOP; 1001 1.89 pooka 1002 1.90 pooka /* 1003 1.90 pooka * Create alternate execution context and jump to it. Note 1004 1.90 pooka * that we come "out" of savemain twice. Where we come out 1005 1.90 pooka * of it depends on the architecture. If the return address is 1006 1.90 pooka * stored on the stack, we jump out from puffs_cc_continue(), 1007 1.90 pooka * for a register return address from puffs__cc_savemain(). 1008 1.90 pooka * PU_MAINRESTORE makes sure we DTRT in both cases. 1009 1.90 pooka */ 1010 1.90 pooka if (puffs__cc_create(pu, puffs__theloop, &pcc) == -1) { 1011 1.89 pooka goto out; 1012 1.90 pooka } 1013 1.117 chs 1014 1.117 chs #if 0 1015 1.90 pooka if (puffs__cc_savemain(pu) == -1) { 1016 1.90 pooka goto out; 1017 1.90 pooka } 1018 1.117 chs #else 1019 1.117 chs /* 1020 1.117 chs * XXX 1021 1.117 chs * puffs__cc_savemain() uses getcontext() and then returns. 1022 1.117 chs * the caller (this function) may overwrite the stack frame 1023 1.117 chs * of puffs__cc_savemain(), so when we call setcontext() later and 1024 1.117 chs * return from puffs__cc_savemain() again, the return address or 1025 1.117 chs * saved stack pointer can be garbage. 1026 1.117 chs * avoid this by calling getcontext() directly here. 1027 1.117 chs */ 1028 1.117 chs extern int puffs_fakecc; 1029 1.117 chs if (!puffs_fakecc) { 1030 1.117 chs PU_CLRSFLAG(pu, PU_MAINRESTORE); 1031 1.117 chs if (getcontext(&pu->pu_mainctx) == -1) { 1032 1.117 chs goto out; 1033 1.117 chs } 1034 1.117 chs } 1035 1.117 chs #endif 1036 1.117 chs 1037 1.90 pooka if ((pu->pu_state & PU_MAINRESTORE) == 0) 1038 1.90 pooka puffs_cc_continue(pcc); 1039 1.89 pooka 1040 1.79 pooka finalpush(pu); 1041 1.44 pooka errno = 0; 1042 1.18 alc 1043 1.19 pooka out: 1044 1.44 pooka /* store the real error for a while */ 1045 1.44 pooka sverrno = errno; 1046 1.44 pooka 1047 1.44 pooka errno = sverrno; 1048 1.44 pooka if (errno) 1049 1.44 pooka return -1; 1050 1.44 pooka else 1051 1.44 pooka return 0; 1052 1.1 pooka } 1053