1 1.11 rillig /* $NetBSD: puffs_portal.c,v 1.11 2023/04/04 20:39:36 rillig Exp $ */ 2 1.1 pooka 3 1.1 pooka /* 4 1.1 pooka * Copyright (c) 2007 Antti Kantee. All Rights Reserved. 5 1.1 pooka * Development was supported by the Finnish Cultural Foundation. 6 1.1 pooka * 7 1.1 pooka * Redistribution and use in source and binary forms, with or without 8 1.1 pooka * modification, are permitted provided that the following conditions 9 1.1 pooka * are met: 10 1.1 pooka * 1. Redistributions of source code must retain the above copyright 11 1.1 pooka * notice, this list of conditions and the following disclaimer. 12 1.1 pooka * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 pooka * notice, this list of conditions and the following disclaimer in the 14 1.1 pooka * documentation and/or other materials provided with the distribution. 15 1.1 pooka * 16 1.1 pooka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 17 1.1 pooka * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 1.1 pooka * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 1.1 pooka * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 1.1 pooka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 1.1 pooka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 1.1 pooka * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 1.1 pooka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 1.1 pooka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 1.1 pooka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 1.1 pooka * SUCH DAMAGE. 27 1.1 pooka */ 28 1.1 pooka 29 1.1 pooka #include <sys/cdefs.h> 30 1.1 pooka #ifndef lint 31 1.11 rillig __RCSID("$NetBSD: puffs_portal.c,v 1.11 2023/04/04 20:39:36 rillig Exp $"); 32 1.1 pooka #endif /* !lint */ 33 1.1 pooka 34 1.1 pooka #include <sys/types.h> 35 1.1 pooka #include <sys/wait.h> 36 1.7 christos #include <sys/socket.h> 37 1.1 pooka 38 1.1 pooka #include <assert.h> 39 1.1 pooka #include <err.h> 40 1.1 pooka #include <errno.h> 41 1.1 pooka #include <mntopts.h> 42 1.1 pooka #include <paths.h> 43 1.1 pooka #include <poll.h> 44 1.1 pooka #include <puffs.h> 45 1.1 pooka #include <stdio.h> 46 1.1 pooka #include <stdlib.h> 47 1.1 pooka #include <string.h> 48 1.1 pooka #include <unistd.h> 49 1.1 pooka #include <util.h> 50 1.1 pooka 51 1.1 pooka #include "portald.h" 52 1.1 pooka 53 1.1 pooka struct portal_node { 54 1.1 pooka char *path; 55 1.1 pooka int fd; 56 1.1 pooka }; 57 1.1 pooka 58 1.4 joerg __dead static void usage(void); 59 1.1 pooka 60 1.11 rillig PUFFSOP_PROTOS(portal) 61 1.1 pooka 62 1.1 pooka #define PORTAL_ROOT NULL 63 1.1 pooka #define METADATASIZE (sizeof(int) + sizeof(size_t)) 64 1.1 pooka 65 1.1 pooka qelem q; 66 1.1 pooka int readcfg, sigchild; 67 1.1 pooka const char *cfg; 68 1.1 pooka 69 1.1 pooka static void 70 1.6 matt usage(void) 71 1.1 pooka { 72 1.1 pooka 73 1.1 pooka errx(1, "usage: %s [-o options] /path/portal.conf mount_point", 74 1.1 pooka getprogname()); 75 1.1 pooka } 76 1.1 pooka 77 1.1 pooka static void 78 1.1 pooka sighup(int sig) 79 1.1 pooka { 80 1.1 pooka 81 1.1 pooka readcfg = 1; 82 1.1 pooka } 83 1.1 pooka 84 1.1 pooka static void 85 1.1 pooka sigcry(int sig) 86 1.1 pooka { 87 1.1 pooka 88 1.1 pooka sigchild = 1; 89 1.1 pooka } 90 1.1 pooka 91 1.1 pooka static void 92 1.1 pooka portal_loopfn(struct puffs_usermount *pu) 93 1.1 pooka { 94 1.1 pooka 95 1.1 pooka if (readcfg) 96 1.1 pooka conf_read(&q, cfg); 97 1.1 pooka readcfg = 0; 98 1.1 pooka 99 1.1 pooka if (sigchild) { 100 1.1 pooka sigchild = 0; 101 1.1 pooka while (waitpid(-1, NULL, WNOHANG) != -1) 102 1.1 pooka continue; 103 1.1 pooka } 104 1.1 pooka } 105 1.1 pooka 106 1.1 pooka #define PUFBUF_FD 1 107 1.1 pooka #define PUFBUF_DATA 2 108 1.1 pooka 109 1.1 pooka #define CMSIZE (sizeof(struct cmsghdr) + sizeof(int)) 110 1.1 pooka 111 1.1 pooka /* receive file descriptor produced by our child process */ 112 1.1 pooka static int 113 1.1 pooka readfd(struct puffs_framebuf *pufbuf, int fd, int *done) 114 1.1 pooka { 115 1.1 pooka struct cmsghdr *cmp; 116 1.1 pooka struct msghdr msg; 117 1.1 pooka struct iovec iov; 118 1.1 pooka ssize_t n; 119 1.1 pooka int error, rv; 120 1.1 pooka 121 1.1 pooka rv = 0; 122 1.3 pooka cmp = emalloc(CMSG_SPACE(sizeof(int))); 123 1.1 pooka 124 1.1 pooka iov.iov_base = &error; 125 1.1 pooka iov.iov_len = sizeof(int); 126 1.1 pooka msg.msg_iov = &iov; 127 1.1 pooka msg.msg_iovlen = 1; 128 1.1 pooka msg.msg_name = NULL; 129 1.1 pooka msg.msg_namelen = 0; 130 1.1 pooka msg.msg_control = cmp; 131 1.3 pooka msg.msg_controllen = CMSG_SPACE(sizeof(int)); 132 1.1 pooka 133 1.1 pooka n = recvmsg(fd, &msg, 0); 134 1.1 pooka if (n == -1) { 135 1.1 pooka rv = errno; 136 1.1 pooka goto out; 137 1.1 pooka } 138 1.1 pooka if (n == 0) { 139 1.1 pooka rv = ECONNRESET; 140 1.1 pooka goto out; 141 1.1 pooka } 142 1.1 pooka 143 1.1 pooka /* the data for the server */ 144 1.1 pooka puffs_framebuf_putdata_atoff(pufbuf, 0, &error, sizeof(int)); 145 1.1 pooka if (error) { 146 1.1 pooka rv = error; 147 1.1 pooka goto out; 148 1.1 pooka } 149 1.1 pooka puffs_framebuf_putdata_atoff(pufbuf, sizeof(int), 150 1.1 pooka CMSG_DATA(cmp), sizeof(int)); 151 1.1 pooka *done = 1; 152 1.1 pooka 153 1.1 pooka out: 154 1.1 pooka free(cmp); 155 1.1 pooka return rv; 156 1.1 pooka } 157 1.1 pooka 158 1.1 pooka /* 159 1.1 pooka * receive data from provider 160 1.1 pooka * 161 1.1 pooka * XXX: should read directly into the buffer and adjust offsets 162 1.1 pooka * instead of doing memcpy 163 1.1 pooka */ 164 1.1 pooka static int 165 1.1 pooka readdata(struct puffs_framebuf *pufbuf, int fd, int *done) 166 1.1 pooka { 167 1.1 pooka char buf[1024]; 168 1.1 pooka size_t max; 169 1.1 pooka ssize_t n; 170 1.1 pooka size_t moved; 171 1.1 pooka 172 1.1 pooka /* don't override metadata */ 173 1.1 pooka if (puffs_framebuf_telloff(pufbuf) == 0) 174 1.1 pooka puffs_framebuf_seekset(pufbuf, METADATASIZE); 175 1.1 pooka puffs_framebuf_getdata_atoff(pufbuf, sizeof(int), &max, sizeof(size_t)); 176 1.1 pooka moved = puffs_framebuf_tellsize(pufbuf) - METADATASIZE; 177 1.1 pooka assert(max >= moved); 178 1.1 pooka max -= moved; 179 1.1 pooka 180 1.1 pooka do { 181 1.1 pooka n = read(fd, buf, MIN(sizeof(buf), max)); 182 1.1 pooka if (n == 0) { 183 1.8 christos /* 184 1.8 christos * Deal with EOF here by closing the file descriptor 185 1.8 christos * and thus causing an error on subsequent accesses. 186 1.8 christos * This is the last kevent notification we are going 187 1.8 christos * to be getting for regular files. 188 1.8 christos */ 189 1.8 christos close(fd); 190 1.1 pooka if (moved) 191 1.1 pooka break; 192 1.1 pooka else 193 1.1 pooka return -1; /* caught by read */ 194 1.1 pooka } 195 1.1 pooka if (n < 0) { 196 1.1 pooka if (moved) 197 1.1 pooka return 0; 198 1.1 pooka 199 1.1 pooka if (errno != EAGAIN) 200 1.1 pooka return errno; 201 1.1 pooka else 202 1.1 pooka return 0; 203 1.1 pooka } 204 1.1 pooka 205 1.1 pooka puffs_framebuf_putdata(pufbuf, buf, n); 206 1.1 pooka moved += n; 207 1.1 pooka max -= n; 208 1.1 pooka } while (max > 0); 209 1.1 pooka 210 1.1 pooka *done = 1; 211 1.1 pooka 212 1.1 pooka return 0; 213 1.1 pooka } 214 1.1 pooka 215 1.1 pooka static int 216 1.1 pooka portal_frame_rf(struct puffs_usermount *pu, struct puffs_framebuf *pufbuf, 217 1.1 pooka int fd, int *done) 218 1.1 pooka { 219 1.1 pooka int type; 220 1.1 pooka 221 1.1 pooka if (puffs_framebuf_getdata_atoff(pufbuf, 0, &type, sizeof(int)) == -1) 222 1.1 pooka return EINVAL; 223 1.1 pooka 224 1.1 pooka if (type == PUFBUF_FD) 225 1.1 pooka return readfd(pufbuf, fd, done); 226 1.1 pooka else if (type == PUFBUF_DATA) 227 1.1 pooka return readdata(pufbuf, fd, done); 228 1.1 pooka else 229 1.1 pooka abort(); 230 1.1 pooka } 231 1.1 pooka 232 1.1 pooka static int 233 1.1 pooka portal_frame_wf(struct puffs_usermount *pu, struct puffs_framebuf *pufbuf, 234 1.1 pooka int fd, int *done) 235 1.1 pooka { 236 1.1 pooka void *win; 237 1.1 pooka size_t pbsize, pboff, winlen; 238 1.1 pooka ssize_t n; 239 1.1 pooka int error; 240 1.1 pooka 241 1.1 pooka pboff = puffs_framebuf_telloff(pufbuf); 242 1.1 pooka pbsize = puffs_framebuf_tellsize(pufbuf); 243 1.1 pooka error = 0; 244 1.1 pooka 245 1.1 pooka do { 246 1.1 pooka assert(pbsize > pboff); 247 1.1 pooka winlen = pbsize - pboff; 248 1.1 pooka if (puffs_framebuf_getwindow(pufbuf, pboff, &win, &winlen)==-1) 249 1.1 pooka return errno; 250 1.1 pooka n = write(fd, win, winlen); 251 1.1 pooka if (n == 0) { 252 1.1 pooka if (pboff != 0) 253 1.1 pooka break; 254 1.1 pooka else 255 1.1 pooka return -1; /* caught by node_write */ 256 1.1 pooka } 257 1.1 pooka if (n < 0) { 258 1.1 pooka if (pboff != 0) 259 1.1 pooka break; 260 1.1 pooka 261 1.1 pooka if (errno != EAGAIN) 262 1.1 pooka return errno; 263 1.1 pooka return 0; 264 1.1 pooka } 265 1.1 pooka 266 1.1 pooka pboff += n; 267 1.1 pooka puffs_framebuf_seekset(pufbuf, pboff); 268 1.1 pooka } while (pboff != pbsize); 269 1.1 pooka 270 1.1 pooka *done = 1; 271 1.1 pooka puffs_framebuf_putdata_atoff(pufbuf, 0, &pboff, sizeof(size_t)); 272 1.1 pooka return error; 273 1.1 pooka } 274 1.1 pooka 275 1.1 pooka /* transfer file descriptor to master file server */ 276 1.1 pooka static int 277 1.1 pooka sendfd(int s, int fd, int error) 278 1.1 pooka { 279 1.1 pooka struct cmsghdr *cmp; 280 1.1 pooka struct msghdr msg; 281 1.1 pooka struct iovec iov; 282 1.1 pooka ssize_t n; 283 1.1 pooka int rv; 284 1.1 pooka 285 1.1 pooka rv = 0; 286 1.1 pooka cmp = emalloc(CMSG_LEN(sizeof(int))); 287 1.1 pooka 288 1.1 pooka iov.iov_base = &error; 289 1.1 pooka iov.iov_len = sizeof(int); 290 1.1 pooka 291 1.1 pooka msg.msg_iov = &iov; 292 1.1 pooka msg.msg_iovlen = 1; 293 1.1 pooka msg.msg_name = NULL; 294 1.1 pooka msg.msg_namelen = 0; 295 1.1 pooka if (error == 0) { 296 1.1 pooka cmp->cmsg_level = SOL_SOCKET; 297 1.1 pooka cmp->cmsg_type = SCM_RIGHTS; 298 1.1 pooka cmp->cmsg_len = CMSG_LEN(sizeof(int)); 299 1.1 pooka 300 1.1 pooka msg.msg_control = cmp; 301 1.1 pooka msg.msg_controllen = CMSG_LEN(sizeof(int)); 302 1.1 pooka *(int *)CMSG_DATA(cmp) = fd; 303 1.1 pooka } else { 304 1.1 pooka msg.msg_control = NULL; 305 1.1 pooka msg.msg_controllen = 0; 306 1.1 pooka } 307 1.1 pooka 308 1.1 pooka n = sendmsg(s, &msg, 0); 309 1.1 pooka if (n == -1) 310 1.1 pooka rv = errno; 311 1.1 pooka else if (n < (ssize_t)sizeof(int)) 312 1.1 pooka rv = EPROTO; 313 1.1 pooka 314 1.1 pooka free(cmp); 315 1.1 pooka return rv; 316 1.1 pooka } 317 1.1 pooka 318 1.1 pooka /* 319 1.1 pooka * Produce I/O file descriptor by forking (like original portald). 320 1.1 pooka * 321 1.1 pooka * child: run provider and transfer produced fd to parent 322 1.1 pooka * parent: yield until child produces fd. receive it and store it. 323 1.1 pooka */ 324 1.1 pooka static int 325 1.1 pooka provide(struct puffs_usermount *pu, struct portal_node *portn, 326 1.1 pooka struct portal_cred *portc, char **v) 327 1.1 pooka { 328 1.1 pooka struct puffs_cc *pcc = puffs_cc_getcc(pu); 329 1.1 pooka struct puffs_framebuf *pufbuf; 330 1.1 pooka int s[2]; 331 1.1 pooka int fd, error; 332 1.1 pooka int data; 333 1.1 pooka 334 1.1 pooka pufbuf = puffs_framebuf_make(); 335 1.1 pooka if (pufbuf == NULL) 336 1.1 pooka return ENOMEM; 337 1.1 pooka 338 1.1 pooka data = PUFBUF_FD; 339 1.1 pooka if (puffs_framebuf_putdata(pufbuf, &data, sizeof(int)) == -1) 340 1.1 pooka goto bad; 341 1.1 pooka 342 1.1 pooka if (socketpair(AF_LOCAL, SOCK_STREAM, 0, s) == -1) 343 1.1 pooka goto bad; 344 1.1 pooka 345 1.1 pooka switch (fork()) { 346 1.1 pooka case -1: 347 1.10 kre close(s[0]); close(s[1]); 348 1.1 pooka goto bad; 349 1.1 pooka case 0: 350 1.10 kre close(s[0]); 351 1.1 pooka error = activate_argv(portc, portn->path, v, &fd); 352 1.1 pooka sendfd(s[1], fd, error); 353 1.1 pooka exit(0); 354 1.1 pooka default: 355 1.10 kre close(s[1]); 356 1.1 pooka puffs_framev_addfd(pu, s[0], PUFFS_FBIO_READ); 357 1.1 pooka puffs_framev_enqueue_directreceive(pcc, s[0], pufbuf, 0); 358 1.1 pooka puffs_framev_removefd(pu, s[0], 0); 359 1.1 pooka close(s[0]); 360 1.1 pooka 361 1.1 pooka if (puffs_framebuf_tellsize(pufbuf) < sizeof(int)) { 362 1.1 pooka errno = EIO; 363 1.1 pooka goto bad; 364 1.1 pooka } 365 1.1 pooka puffs_framebuf_getdata_atoff(pufbuf, 0, &error, sizeof(int)); 366 1.1 pooka if (error) { 367 1.1 pooka errno = error; 368 1.1 pooka goto bad; 369 1.1 pooka } 370 1.1 pooka 371 1.1 pooka if (puffs_framebuf_tellsize(pufbuf) != 2*sizeof(int)) { 372 1.1 pooka errno = EIO; 373 1.1 pooka goto bad; 374 1.1 pooka } 375 1.1 pooka 376 1.1 pooka puffs_framebuf_getdata_atoff(pufbuf, sizeof(int), 377 1.1 pooka &fd, sizeof(int)); 378 1.1 pooka puffs_framebuf_destroy(pufbuf); 379 1.1 pooka 380 1.1 pooka data = 1; 381 1.1 pooka if (ioctl(fd, FIONBIO, &data) == -1) 382 1.1 pooka return errno; 383 1.1 pooka 384 1.1 pooka if (puffs_framev_addfd(pu, fd, PUFFS_FBIO_WRITE) == -1) 385 1.1 pooka return errno; 386 1.1 pooka 387 1.1 pooka portn->fd = fd; 388 1.1 pooka return 0; 389 1.1 pooka } 390 1.1 pooka 391 1.1 pooka bad: 392 1.1 pooka puffs_framebuf_destroy(pufbuf); 393 1.1 pooka return errno; 394 1.1 pooka } 395 1.1 pooka 396 1.1 pooka int 397 1.1 pooka main(int argc, char *argv[]) 398 1.1 pooka { 399 1.1 pooka struct puffs_usermount *pu; 400 1.1 pooka struct puffs_ops *pops; 401 1.1 pooka mntoptparse_t mp; 402 1.1 pooka int pflags, mntflags; 403 1.1 pooka int detach; 404 1.1 pooka int ch; 405 1.1 pooka 406 1.1 pooka setprogname(argv[0]); 407 1.1 pooka 408 1.1 pooka mntflags = pflags = 0; 409 1.1 pooka detach = 1; 410 1.1 pooka while ((ch = getopt(argc, argv, "o:s")) != -1) { 411 1.1 pooka switch (ch) { 412 1.1 pooka case 'o': 413 1.1 pooka mp = getmntopts(optarg, puffsmopts, &mntflags, &pflags); 414 1.1 pooka if (mp == NULL) 415 1.1 pooka err(1, "getmntopts"); 416 1.1 pooka freemntopts(mp); 417 1.1 pooka break; 418 1.1 pooka case 's': /* stay on top */ 419 1.1 pooka detach = 0; 420 1.1 pooka break; 421 1.1 pooka default: 422 1.1 pooka usage(); 423 1.1 pooka /*NOTREACHED*/ 424 1.1 pooka } 425 1.1 pooka } 426 1.1 pooka pflags |= PUFFS_KFLAG_NOCACHE | PUFFS_KFLAG_LOOKUP_FULLPNBUF; 427 1.1 pooka if (pflags & PUFFS_FLAG_OPDUMP) 428 1.1 pooka detach = 0; 429 1.1 pooka argc -= optind; 430 1.1 pooka argv += optind; 431 1.1 pooka 432 1.1 pooka if (argc != 2) 433 1.1 pooka usage(); 434 1.1 pooka 435 1.1 pooka PUFFSOP_INIT(pops); 436 1.1 pooka 437 1.1 pooka PUFFSOP_SETFSNOP(pops, unmount); 438 1.1 pooka PUFFSOP_SETFSNOP(pops, sync); 439 1.1 pooka PUFFSOP_SETFSNOP(pops, statvfs); 440 1.1 pooka 441 1.1 pooka PUFFSOP_SET(pops, portal, node, lookup); 442 1.1 pooka PUFFSOP_SET(pops, portal, node, getattr); 443 1.1 pooka PUFFSOP_SET(pops, portal, node, setattr); 444 1.1 pooka PUFFSOP_SET(pops, portal, node, open); 445 1.1 pooka PUFFSOP_SET(pops, portal, node, read); 446 1.1 pooka PUFFSOP_SET(pops, portal, node, write); 447 1.1 pooka PUFFSOP_SET(pops, portal, node, seek); 448 1.1 pooka PUFFSOP_SET(pops, portal, node, poll); 449 1.1 pooka PUFFSOP_SET(pops, portal, node, inactive); 450 1.1 pooka PUFFSOP_SET(pops, portal, node, reclaim); 451 1.1 pooka 452 1.1 pooka pu = puffs_init(pops, _PATH_PUFFS, "portal", NULL, pflags); 453 1.1 pooka if (pu == NULL) 454 1.1 pooka err(1, "init"); 455 1.1 pooka 456 1.1 pooka if (signal(SIGHUP, sighup) == SIG_ERR) 457 1.1 pooka warn("cannot set sighup handler"); 458 1.1 pooka if (signal(SIGCHLD, sigcry) == SIG_ERR) 459 1.1 pooka err(1, "cannot set sigchild handler"); 460 1.1 pooka if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) 461 1.1 pooka err(1, "cannot ignore sigpipe"); 462 1.1 pooka 463 1.1 pooka readcfg = 0; 464 1.1 pooka cfg = argv[0]; 465 1.1 pooka if (*cfg != '/') 466 1.1 pooka errx(1, "need absolute path for config"); 467 1.1 pooka q.q_forw = q.q_back = &q; 468 1.1 pooka if (conf_read(&q, cfg) == -1) 469 1.1 pooka err(1, "cannot read cfg \"%s\"", cfg); 470 1.1 pooka 471 1.1 pooka puffs_ml_setloopfn(pu, portal_loopfn); 472 1.1 pooka puffs_framev_init(pu, portal_frame_rf, portal_frame_wf, NULL,NULL,NULL); 473 1.1 pooka 474 1.1 pooka if (detach) 475 1.1 pooka if (puffs_daemon(pu, 1, 1) == -1) 476 1.1 pooka err(1, "puffs_daemon"); 477 1.1 pooka 478 1.1 pooka if (puffs_mount(pu, argv[1], mntflags, PORTAL_ROOT) == -1) 479 1.1 pooka err(1, "mount"); 480 1.1 pooka if (puffs_mainloop(pu) == -1) 481 1.1 pooka err(1, "mainloop"); 482 1.1 pooka 483 1.1 pooka return 0; 484 1.1 pooka } 485 1.1 pooka 486 1.1 pooka static struct portal_node * 487 1.1 pooka makenode(const char *path) 488 1.1 pooka { 489 1.1 pooka struct portal_node *portn; 490 1.1 pooka 491 1.1 pooka portn = emalloc(sizeof(struct portal_node)); 492 1.1 pooka portn->path = estrdup(path); 493 1.1 pooka portn->fd = -1; 494 1.1 pooka 495 1.1 pooka return portn; 496 1.1 pooka } 497 1.1 pooka 498 1.1 pooka static void 499 1.1 pooka credtr(struct portal_cred *portc, const struct puffs_cred *puffc, int mode) 500 1.1 pooka { 501 1.1 pooka memset(portc, 0, sizeof(struct portal_cred)); 502 1.1 pooka 503 1.1 pooka portc->pcr_flag = mode; 504 1.1 pooka puffs_cred_getuid(puffc, &portc->pcr_uid); 505 1.1 pooka puffs_cred_getgid(puffc, &portc->pcr_gid); 506 1.1 pooka puffs_cred_getgroups(puffc, portc->pcr_groups, 507 1.1 pooka (short *)&portc->pcr_ngroups); 508 1.1 pooka } 509 1.1 pooka 510 1.1 pooka /* 511 1.1 pooka * XXX: we could also simply already resolve the name at this stage 512 1.1 pooka * instead of deferring it to open. But doing it in open is how the 513 1.1 pooka * original portald does it, and I don't want to introduce any funny 514 1.1 pooka * incompatibilities. 515 1.1 pooka */ 516 1.1 pooka int 517 1.2 pooka portal_node_lookup(struct puffs_usermount *pu, puffs_cookie_t opc, 518 1.2 pooka struct puffs_newinfo *pni, const struct puffs_cn *pcn) 519 1.1 pooka { 520 1.1 pooka struct portal_node *portn; 521 1.1 pooka 522 1.1 pooka assert(opc == PORTAL_ROOT); 523 1.1 pooka 524 1.1 pooka if (pcn->pcn_nameiop != NAMEI_LOOKUP 525 1.1 pooka && pcn->pcn_nameiop != NAMEI_CREATE) 526 1.1 pooka return EOPNOTSUPP; 527 1.1 pooka 528 1.1 pooka portn = makenode(pcn->pcn_name); 529 1.1 pooka puffs_newinfo_setcookie(pni, portn); 530 1.1 pooka puffs_newinfo_setvtype(pni, VREG); 531 1.1 pooka 532 1.1 pooka pcn->pcn_flags &= ~NAMEI_REQUIREDIR; 533 1.1 pooka pcn->pcn_consume = strlen(pcn->pcn_name) - pcn->pcn_namelen; 534 1.1 pooka 535 1.1 pooka return 0; 536 1.1 pooka } 537 1.1 pooka 538 1.10 kre unsigned int fakeid = 3; 539 1.1 pooka 540 1.1 pooka /* XXX: libpuffs'ize */ 541 1.1 pooka int 542 1.2 pooka portal_node_getattr(struct puffs_usermount *pu, puffs_cookie_t opc, 543 1.2 pooka struct vattr *va, const struct puffs_cred *pcr) 544 1.1 pooka { 545 1.1 pooka struct timeval tv; 546 1.1 pooka struct timespec ts; 547 1.10 kre int res = 0; 548 1.1 pooka 549 1.1 pooka puffs_vattr_null(va); 550 1.1 pooka if (opc == PORTAL_ROOT) { 551 1.1 pooka va->va_type = VDIR; 552 1.1 pooka va->va_mode = 0777; 553 1.1 pooka va->va_nlink = 2; 554 1.9 christos va->va_uid = va->va_gid = 0; 555 1.10 kre #if 0 /* XXX Huh? */ 556 1.9 christos va->va_fileid = fakeid++; 557 1.10 kre #else 558 1.10 kre va->va_fileid = 2; /*XXX; ROOTINO*/ 559 1.10 kre #endif 560 1.9 christos va->va_size = va->va_bytes = 0; 561 1.9 christos va->va_gen = 0; 562 1.9 christos va->va_rdev = PUFFS_VNOVAL; 563 1.9 christos va->va_blocksize = DEV_BSIZE; 564 1.9 christos 565 1.9 christos gettimeofday(&tv, NULL); 566 1.9 christos TIMEVAL_TO_TIMESPEC(&tv, &ts); 567 1.9 christos va->va_atime = va->va_ctime = va->va_mtime = 568 1.9 christos va->va_birthtime = ts; 569 1.1 pooka } else { 570 1.9 christos /* cheat for now */ 571 1.9 christos int error; 572 1.10 kre int newfd; 573 1.9 christos struct stat st; 574 1.9 christos struct portal_node *portn = opc; 575 1.9 christos struct portal_cred portc; 576 1.9 christos char **v = conf_match(&q, portn->path); 577 1.10 kre 578 1.9 christos if (v == NULL) 579 1.9 christos return ENOENT; 580 1.10 kre if (portn->fd == -1) { 581 1.10 kre credtr(&portc, pcr, 0777); 582 1.10 kre error = provide(pu, portn, &portc, v); 583 1.10 kre if (error) 584 1.10 kre return error; 585 1.10 kre newfd = 1; 586 1.10 kre } else 587 1.10 kre newfd = 0; 588 1.10 kre 589 1.9 christos if (fstat(portn->fd, &st) == -1) 590 1.10 kre res = errno; 591 1.10 kre else { 592 1.10 kre #if 0 593 1.10 kre va->va_type = S_ISDIR(st.st_mode) ? VDIR : VREG; /* XXX */ 594 1.10 kre #else 595 1.10 kre va->va_type = puffs_mode2vt(st.st_mode); 596 1.10 kre #endif 597 1.10 kre /* puffs supplies S_IFMT bits later */ 598 1.10 kre va->va_mode = (st.st_mode & ~S_IFMT); 599 1.10 kre 600 1.10 kre va->va_nlink = st.st_nlink ? st.st_nlink : 1; 601 1.10 kre va->va_uid = st.st_uid; 602 1.10 kre va->va_gid = st.st_gid; 603 1.10 kre va->va_fileid = st.st_ino ? st.st_ino : fakeid++; 604 1.10 kre va->va_size = va->va_bytes = st.st_size; 605 1.10 kre va->va_gen = 0; 606 1.10 kre va->va_rdev = st.st_rdev; 607 1.10 kre va->va_blocksize = st.st_blksize; 608 1.10 kre va->va_atime = st.st_atim; 609 1.10 kre va->va_ctime = st.st_ctim; 610 1.10 kre va->va_mtime = st.st_mtim; 611 1.10 kre va->va_birthtime = st.st_birthtim; 612 1.10 kre } 613 1.10 kre if (newfd) { 614 1.10 kre puffs_framev_removefd(pu, portn->fd, 0); 615 1.10 kre close(portn->fd); 616 1.10 kre portn->fd = -1; 617 1.10 kre } 618 1.9 christos } 619 1.1 pooka 620 1.10 kre return res; 621 1.1 pooka } 622 1.1 pooka 623 1.1 pooka /* for writing, just pretend we care */ 624 1.1 pooka int 625 1.2 pooka portal_node_setattr(struct puffs_usermount *pu, puffs_cookie_t opc, 626 1.2 pooka const struct vattr *va, const struct puffs_cred *pcr) 627 1.1 pooka { 628 1.1 pooka 629 1.1 pooka return 0; 630 1.1 pooka } 631 1.1 pooka 632 1.1 pooka int 633 1.2 pooka portal_node_open(struct puffs_usermount *pu, puffs_cookie_t opc, int mode, 634 1.1 pooka const struct puffs_cred *pcr) 635 1.1 pooka { 636 1.1 pooka struct portal_node *portn = opc; 637 1.1 pooka struct portal_cred portc; 638 1.1 pooka char **v; 639 1.1 pooka 640 1.1 pooka if (opc == PORTAL_ROOT) 641 1.1 pooka return 0; 642 1.1 pooka 643 1.1 pooka if (mode & O_NONBLOCK) 644 1.1 pooka return EOPNOTSUPP; 645 1.1 pooka 646 1.1 pooka v = conf_match(&q, portn->path); 647 1.1 pooka if (v == NULL) 648 1.1 pooka return ENOENT; 649 1.1 pooka 650 1.1 pooka credtr(&portc, pcr, mode); 651 1.1 pooka return provide(pu, portn, &portc, v); 652 1.1 pooka } 653 1.1 pooka 654 1.1 pooka int 655 1.2 pooka portal_node_read(struct puffs_usermount *pu, puffs_cookie_t opc, 656 1.1 pooka uint8_t *buf, off_t offset, size_t *resid, 657 1.1 pooka const struct puffs_cred *pcr, int ioflag) 658 1.1 pooka { 659 1.1 pooka struct puffs_cc *pcc = puffs_cc_getcc(pu); 660 1.1 pooka struct portal_node *portn = opc; 661 1.1 pooka struct puffs_framebuf *pufbuf; 662 1.1 pooka size_t xfersize, winsize, boff; 663 1.1 pooka void *win; 664 1.1 pooka int rv, error; 665 1.1 pooka int data, dummy; 666 1.1 pooka 667 1.1 pooka assert(opc != PORTAL_ROOT); 668 1.1 pooka error = 0; 669 1.1 pooka 670 1.1 pooka /* if we can't (re-)enable it, treat it as EOF */ 671 1.1 pooka rv = puffs_framev_enablefd(pu, portn->fd, PUFFS_FBIO_READ); 672 1.1 pooka if (rv == -1) 673 1.1 pooka return 0; 674 1.1 pooka 675 1.1 pooka pufbuf = puffs_framebuf_make(); 676 1.1 pooka data = PUFBUF_DATA; 677 1.1 pooka puffs_framebuf_putdata(pufbuf, &data, sizeof(int)); 678 1.1 pooka puffs_framebuf_putdata(pufbuf, resid, sizeof(size_t)); 679 1.1 pooka 680 1.1 pooka /* if we are doing nodelay, do read directly */ 681 1.1 pooka if (ioflag & PUFFS_IO_NDELAY) { 682 1.1 pooka rv = readdata(pufbuf, portn->fd, &dummy); 683 1.1 pooka if (rv != 0) { 684 1.1 pooka error = rv; 685 1.1 pooka goto out; 686 1.1 pooka } 687 1.1 pooka } else { 688 1.1 pooka rv = puffs_framev_enqueue_directreceive(pcc, 689 1.1 pooka portn->fd, pufbuf, 0); 690 1.1 pooka 691 1.1 pooka if (rv == -1) { 692 1.1 pooka error = errno; 693 1.1 pooka goto out; 694 1.1 pooka } 695 1.1 pooka } 696 1.1 pooka 697 1.1 pooka xfersize = puffs_framebuf_tellsize(pufbuf) - METADATASIZE; 698 1.1 pooka if (xfersize == 0) { 699 1.1 pooka assert(ioflag & PUFFS_IO_NDELAY); 700 1.1 pooka error = EAGAIN; 701 1.1 pooka goto out; 702 1.1 pooka } 703 1.1 pooka 704 1.1 pooka *resid -= xfersize; 705 1.1 pooka boff = 0; 706 1.1 pooka while (xfersize > 0) { 707 1.1 pooka winsize = xfersize; 708 1.1 pooka rv = puffs_framebuf_getwindow(pufbuf, METADATASIZE, 709 1.1 pooka &win, &winsize); 710 1.1 pooka assert(rv == 0); 711 1.1 pooka assert(winsize > 0); 712 1.1 pooka 713 1.1 pooka memcpy(buf + boff, win, winsize); 714 1.1 pooka xfersize -= winsize; 715 1.1 pooka boff += winsize; 716 1.1 pooka } 717 1.1 pooka 718 1.1 pooka out: 719 1.1 pooka puffs_framev_disablefd(pu, portn->fd, PUFFS_FBIO_READ); 720 1.1 pooka puffs_framebuf_destroy(pufbuf); 721 1.1 pooka 722 1.1 pooka /* a trickery, from readdata() */ 723 1.1 pooka if (error == -1) 724 1.1 pooka return 0; 725 1.1 pooka return error; 726 1.1 pooka } 727 1.1 pooka 728 1.1 pooka int 729 1.2 pooka portal_node_write(struct puffs_usermount *pu, puffs_cookie_t opc, 730 1.1 pooka uint8_t *buf, off_t offset, size_t *resid, 731 1.1 pooka const struct puffs_cred *pcr, int ioflag) 732 1.1 pooka { 733 1.1 pooka struct puffs_cc *pcc = puffs_cc_getcc(pu); 734 1.1 pooka struct portal_node *portn = opc; 735 1.1 pooka struct puffs_framebuf *pufbuf; 736 1.1 pooka size_t written; 737 1.1 pooka int error, rv, dummy; 738 1.1 pooka 739 1.1 pooka assert(opc != PORTAL_ROOT); 740 1.1 pooka 741 1.1 pooka pufbuf = puffs_framebuf_make(); 742 1.1 pooka puffs_framebuf_putdata(pufbuf, buf, *resid); 743 1.1 pooka 744 1.1 pooka error = 0; 745 1.1 pooka if (ioflag & PUFFS_IO_NDELAY) { 746 1.1 pooka rv = portal_frame_wf(pu, pufbuf, portn->fd, &dummy); 747 1.1 pooka if (rv) { 748 1.1 pooka error = rv; 749 1.1 pooka goto out; 750 1.1 pooka } 751 1.1 pooka } else { 752 1.1 pooka rv = puffs_framev_enqueue_directsend(pcc, portn->fd, pufbuf, 0); 753 1.1 pooka if (rv == -1) { 754 1.1 pooka error = errno; 755 1.1 pooka goto out; 756 1.1 pooka } 757 1.1 pooka } 758 1.1 pooka 759 1.1 pooka rv = puffs_framebuf_getdata_atoff(pufbuf, 0, &written, sizeof(size_t)); 760 1.1 pooka assert(rv == 0); 761 1.1 pooka assert(written <= *resid); 762 1.1 pooka *resid -= written; 763 1.1 pooka 764 1.1 pooka out: 765 1.1 pooka puffs_framebuf_destroy(pufbuf); 766 1.1 pooka if (error == -1) 767 1.1 pooka error = 0; 768 1.1 pooka return 0; 769 1.1 pooka } 770 1.1 pooka 771 1.1 pooka int 772 1.2 pooka portal_node_seek(struct puffs_usermount *pu, puffs_cookie_t opc, 773 1.2 pooka off_t oldoff, off_t newoff, const struct puffs_cred *pcr) 774 1.1 pooka { 775 1.1 pooka struct portal_node *portn = opc; 776 1.1 pooka 777 1.1 pooka if (opc == PORTAL_ROOT || portn->fd == -1) 778 1.1 pooka return EOPNOTSUPP; 779 1.1 pooka 780 1.1 pooka if (lseek(portn->fd, newoff, SEEK_SET) == -1) 781 1.1 pooka return errno; 782 1.1 pooka return 0; 783 1.1 pooka } 784 1.1 pooka 785 1.1 pooka int 786 1.2 pooka portal_node_poll(struct puffs_usermount *pu, puffs_cookie_t opc, int *events) 787 1.1 pooka { 788 1.1 pooka struct puffs_cc *pcc = puffs_cc_getcc(pu); 789 1.1 pooka struct portal_node *portn = opc; 790 1.1 pooka int what; 791 1.1 pooka 792 1.1 pooka what = 0; 793 1.1 pooka if (*events & POLLIN) 794 1.1 pooka what |= PUFFS_FBIO_READ; 795 1.1 pooka if (*events & POLLOUT) 796 1.1 pooka what |= PUFFS_FBIO_WRITE; 797 1.1 pooka if (*events & POLLERR) 798 1.1 pooka what |= PUFFS_FBIO_ERROR; 799 1.1 pooka 800 1.5 riastrad if (puffs_framev_enqueue_waitevent(pcc, portn->fd, &what) == -1) { 801 1.1 pooka *events = POLLERR; 802 1.5 riastrad return errno; 803 1.1 pooka } 804 1.1 pooka 805 1.1 pooka *events = 0; 806 1.1 pooka if (what & PUFFS_FBIO_READ) 807 1.1 pooka *events |= POLLIN; 808 1.1 pooka if (what & PUFFS_FBIO_WRITE) 809 1.1 pooka *events |= POLLOUT; 810 1.1 pooka if (what & PUFFS_FBIO_ERROR) 811 1.1 pooka *events |= POLLERR; 812 1.1 pooka 813 1.1 pooka return 0; 814 1.1 pooka } 815 1.1 pooka 816 1.1 pooka int 817 1.2 pooka portal_node_inactive(struct puffs_usermount *pu, puffs_cookie_t opc) 818 1.1 pooka { 819 1.1 pooka 820 1.1 pooka if (opc == PORTAL_ROOT) 821 1.1 pooka return 0; 822 1.1 pooka 823 1.1 pooka puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N1); 824 1.1 pooka return 0; 825 1.1 pooka } 826 1.1 pooka 827 1.1 pooka int 828 1.2 pooka portal_node_reclaim(struct puffs_usermount *pu, puffs_cookie_t opc) 829 1.1 pooka { 830 1.1 pooka struct portal_node *portn = opc; 831 1.1 pooka 832 1.1 pooka if (portn->fd != -1) { 833 1.1 pooka puffs_framev_removefd(pu, portn->fd, 0); 834 1.1 pooka close(portn->fd); 835 1.1 pooka } 836 1.1 pooka free(portn->path); 837 1.1 pooka free(portn); 838 1.1 pooka 839 1.1 pooka return 0; 840 1.1 pooka } 841