1 /* $NetBSD: ukfs.c,v 1.35 2009/08/04 12:37:14 pooka Exp $ */ 2 3 /* 4 * Copyright (c) 2007, 2008 Antti Kantee. All Rights Reserved. 5 * 6 * Development of this software was supported by the 7 * Finnish Cultural Foundation. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 19 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 /* 32 * This library enables access to files systems directly without 33 * involving system calls. 34 */ 35 36 #ifdef __linux__ 37 #define _XOPEN_SOURCE 500 38 #define _BSD_SOURCE 39 #define _FILE_OFFSET_BITS 64 40 #endif 41 42 #include <sys/param.h> 43 #include <sys/queue.h> 44 #include <sys/stat.h> 45 #include <sys/sysctl.h> 46 #include <sys/mount.h> 47 48 #include <assert.h> 49 #include <dirent.h> 50 #include <dlfcn.h> 51 #include <err.h> 52 #include <errno.h> 53 #include <fcntl.h> 54 #include <pthread.h> 55 #include <stdio.h> 56 #include <stdlib.h> 57 #include <string.h> 58 #include <unistd.h> 59 #include <stdint.h> 60 61 #include <rump/ukfs.h> 62 63 #include <rump/rump.h> 64 #include <rump/rump_syscalls.h> 65 66 #define UKFS_MODE_DEFAULT 0555 67 68 struct ukfs { 69 struct mount *ukfs_mp; 70 struct vnode *ukfs_rvp; 71 72 pthread_spinlock_t ukfs_spin; 73 pid_t ukfs_nextpid; 74 struct vnode *ukfs_cdir; 75 int ukfs_devfd; 76 char *ukfs_devpath; 77 char *ukfs_mountpath; 78 }; 79 80 static int builddirs(const char *, mode_t, 81 int (*mkdirfn)(struct ukfs *, const char *, mode_t), struct ukfs *); 82 83 struct mount * 84 ukfs_getmp(struct ukfs *ukfs) 85 { 86 87 return ukfs->ukfs_mp; 88 } 89 90 struct vnode * 91 ukfs_getrvp(struct ukfs *ukfs) 92 { 93 struct vnode *rvp; 94 95 rvp = ukfs->ukfs_rvp; 96 rump_vp_incref(rvp); 97 98 return rvp; 99 } 100 101 #ifdef DONT_WANT_PTHREAD_LINKAGE 102 #define pthread_spin_lock(a) 103 #define pthread_spin_unlock(a) 104 #define pthread_spin_init(a,b) 105 #define pthread_spin_destroy(a) 106 #endif 107 108 static pid_t 109 nextpid(struct ukfs *ukfs) 110 { 111 pid_t npid; 112 113 pthread_spin_lock(&ukfs->ukfs_spin); 114 if (ukfs->ukfs_nextpid == 0) 115 ukfs->ukfs_nextpid++; 116 npid = ukfs->ukfs_nextpid++; 117 pthread_spin_unlock(&ukfs->ukfs_spin); 118 119 return npid; 120 } 121 122 static void 123 precall(struct ukfs *ukfs) 124 { 125 struct vnode *rvp, *cvp; 126 127 rump_setup_curlwp(nextpid(ukfs), 1, 1); 128 rvp = ukfs_getrvp(ukfs); 129 pthread_spin_lock(&ukfs->ukfs_spin); 130 cvp = ukfs->ukfs_cdir; 131 pthread_spin_unlock(&ukfs->ukfs_spin); 132 rump_rcvp_set(rvp, cvp); /* takes refs */ 133 rump_vp_rele(rvp); 134 } 135 136 static void 137 postcall(struct ukfs *ukfs) 138 { 139 struct vnode *rvp; 140 141 rvp = ukfs_getrvp(ukfs); 142 rump_rcvp_set(NULL, rvp); 143 rump_vp_rele(rvp); 144 rump_clear_curlwp(); 145 } 146 147 int 148 _ukfs_init(int version) 149 { 150 int rv; 151 152 if (version != UKFS_VERSION) { 153 printf("incompatible ukfs version, %d vs. %d\n", 154 version, UKFS_VERSION); 155 errno = EPROGMISMATCH; 156 return -1; 157 } 158 159 if ((rv = rump_init()) != 0) { 160 errno = rv; 161 return -1; 162 } 163 164 return 0; 165 } 166 167 /*ARGSUSED*/ 168 static int 169 rumpmkdir(struct ukfs *dummy, const char *path, mode_t mode) 170 { 171 172 return rump_sys_mkdir(path, mode); 173 } 174 175 struct ukfs * 176 ukfs_mount(const char *vfsname, const char *devpath, const char *mountpath, 177 int mntflags, void *arg, size_t alen) 178 { 179 struct stat sb; 180 struct ukfs *fs = NULL; 181 int rv = 0, devfd = -1, rdonly; 182 int mounted = 0; 183 int regged = 0; 184 int doreg = 0; 185 186 /* 187 * Try open and lock the device. if we can't open it, assume 188 * it's a file system which doesn't use a real device and let 189 * it slide. The mount will fail anyway if the fs requires a 190 * device. 191 * 192 * XXX: strictly speaking this is not 100% correct, as virtual 193 * file systems can use a device path which does exist and can 194 * be opened. E.g. tmpfs should be mountable multiple times 195 * with "device" path "/swap", but now isn't. But I think the 196 * chances are so low that it's currently acceptable to let 197 * this one slip. 198 */ 199 rdonly = mntflags & MNT_RDONLY; 200 devfd = open(devpath, rdonly ? O_RDONLY : O_RDWR); 201 if (devfd != -1) { 202 if (fstat(devfd, &sb) == -1) { 203 close(devfd); 204 devfd = -1; 205 rv = errno; 206 goto out; 207 } 208 209 /* 210 * We do this only for non-block device since the 211 * (NetBSD) kernel allows block device open only once. 212 */ 213 if (!S_ISBLK(sb.st_mode)) { 214 if (flock(devfd, LOCK_NB | (rdonly ? LOCK_SH:LOCK_EX)) 215 == -1) { 216 warnx("ukfs_mount: cannot get %s lock on " 217 "device", rdonly ? "shared" : "exclusive"); 218 close(devfd); 219 devfd = -1; 220 rv = errno; 221 goto out; 222 } 223 } else { 224 close(devfd); 225 devfd = -1; 226 } 227 doreg = 1; 228 } else if (errno != ENOENT) { 229 doreg = 1; 230 } 231 232 fs = malloc(sizeof(struct ukfs)); 233 if (fs == NULL) { 234 rv = ENOMEM; 235 goto out; 236 } 237 memset(fs, 0, sizeof(struct ukfs)); 238 239 /* create our mountpoint. this is never removed. */ 240 if (builddirs(mountpath, 0777, rumpmkdir, NULL) == -1) { 241 if (errno != EEXIST) { 242 rv = errno; 243 goto out; 244 } 245 } 246 247 if (doreg) { 248 rv = rump_etfs_register(devpath, devpath, RUMP_ETFS_BLK); 249 if (rv) { 250 goto out; 251 } 252 regged = 1; 253 } 254 rv = rump_sys_mount(vfsname, mountpath, mntflags, arg, alen); 255 if (rv) { 256 rv = errno; 257 goto out; 258 } 259 mounted = 1; 260 rv = rump_vfs_getmp(mountpath, &fs->ukfs_mp); 261 if (rv) { 262 goto out; 263 } 264 rv = rump_vfs_root(fs->ukfs_mp, &fs->ukfs_rvp, 0); 265 if (rv) { 266 goto out; 267 } 268 269 if (regged) { 270 fs->ukfs_devpath = strdup(devpath); 271 } 272 fs->ukfs_mountpath = strdup(mountpath); 273 fs->ukfs_cdir = ukfs_getrvp(fs); 274 pthread_spin_init(&fs->ukfs_spin, PTHREAD_PROCESS_SHARED); 275 fs->ukfs_devfd = devfd; 276 assert(rv == 0); 277 278 out: 279 if (rv) { 280 if (fs) { 281 if (fs->ukfs_rvp) 282 rump_vp_rele(fs->ukfs_rvp); 283 free(fs); 284 fs = NULL; 285 } 286 if (mounted) 287 rump_sys_unmount(mountpath, MNT_FORCE); 288 if (regged) 289 rump_etfs_remove(devpath); 290 if (devfd != -1) { 291 flock(devfd, LOCK_UN); 292 close(devfd); 293 } 294 errno = rv; 295 } 296 297 return fs; 298 } 299 300 int 301 ukfs_release(struct ukfs *fs, int flags) 302 { 303 304 if ((flags & UKFS_RELFLAG_NOUNMOUNT) == 0) { 305 int rv, mntflag; 306 307 ukfs_chdir(fs, "/"); 308 mntflag = 0; 309 if (flags & UKFS_RELFLAG_FORCE) 310 mntflag = MNT_FORCE; 311 rv = rump_sys_unmount(fs->ukfs_mountpath, mntflag); 312 if (rv) { 313 ukfs_chdir(fs, fs->ukfs_mountpath); 314 errno = rv; 315 return -1; 316 } 317 } 318 319 if (fs->ukfs_devpath) { 320 rump_etfs_remove(fs->ukfs_devpath); 321 free(fs->ukfs_devpath); 322 } 323 free(fs->ukfs_mountpath); 324 325 pthread_spin_destroy(&fs->ukfs_spin); 326 if (fs->ukfs_devfd != -1) { 327 flock(fs->ukfs_devfd, LOCK_UN); 328 close(fs->ukfs_devfd); 329 } 330 free(fs); 331 332 return 0; 333 } 334 335 #define STDCALL(ukfs, thecall) \ 336 int rv = 0; \ 337 \ 338 precall(ukfs); \ 339 rv = thecall; \ 340 postcall(ukfs); \ 341 return rv; 342 343 int 344 ukfs_opendir(struct ukfs *ukfs, const char *dirname, struct ukfs_dircookie **c) 345 { 346 struct vnode *vp; 347 int rv; 348 349 precall(ukfs); 350 rv = rump_namei(RUMP_NAMEI_LOOKUP, RUMP_NAMEI_LOCKLEAF, dirname, 351 NULL, &vp, NULL); 352 postcall(ukfs); 353 354 if (rv == 0) { 355 RUMP_VOP_UNLOCK(vp, 0); 356 } else { 357 errno = rv; 358 rv = -1; 359 } 360 361 /*LINTED*/ 362 *c = (struct ukfs_dircookie *)vp; 363 return rv; 364 } 365 366 static int 367 getmydents(struct vnode *vp, off_t *off, uint8_t *buf, size_t bufsize) 368 { 369 struct uio *uio; 370 size_t resid; 371 int rv, eofflag; 372 kauth_cred_t cred; 373 374 uio = rump_uio_setup(buf, bufsize, *off, RUMPUIO_READ); 375 cred = rump_cred_suserget(); 376 rv = RUMP_VOP_READDIR(vp, uio, cred, &eofflag, NULL, NULL); 377 rump_cred_suserput(cred); 378 RUMP_VOP_UNLOCK(vp, 0); 379 *off = rump_uio_getoff(uio); 380 resid = rump_uio_free(uio); 381 382 if (rv) { 383 errno = rv; 384 return -1; 385 } 386 387 /* LINTED: not totally correct return type, but follows syscall */ 388 return bufsize - resid; 389 } 390 391 /*ARGSUSED*/ 392 int 393 ukfs_getdents_cookie(struct ukfs *ukfs, struct ukfs_dircookie *c, off_t *off, 394 uint8_t *buf, size_t bufsize) 395 { 396 /*LINTED*/ 397 struct vnode *vp = (struct vnode *)c; 398 399 RUMP_VOP_LOCK(vp, RUMP_LK_SHARED); 400 return getmydents(vp, off, buf, bufsize); 401 } 402 403 int 404 ukfs_getdents(struct ukfs *ukfs, const char *dirname, off_t *off, 405 uint8_t *buf, size_t bufsize) 406 { 407 struct vnode *vp; 408 int rv; 409 410 precall(ukfs); 411 rv = rump_namei(RUMP_NAMEI_LOOKUP, RUMP_NAMEI_LOCKLEAF, dirname, 412 NULL, &vp, NULL); 413 postcall(ukfs); 414 if (rv) { 415 errno = rv; 416 return -1; 417 } 418 419 rv = getmydents(vp, off, buf, bufsize); 420 rump_vp_rele(vp); 421 return rv; 422 } 423 424 /*ARGSUSED*/ 425 int 426 ukfs_closedir(struct ukfs *ukfs, struct ukfs_dircookie *c) 427 { 428 429 /*LINTED*/ 430 rump_vp_rele((struct vnode *)c); 431 return 0; 432 } 433 434 int 435 ukfs_open(struct ukfs *ukfs, const char *filename, int flags) 436 { 437 int fd; 438 439 precall(ukfs); 440 fd = rump_sys_open(filename, flags, 0); 441 postcall(ukfs); 442 if (fd == -1) 443 return -1; 444 445 return fd; 446 } 447 448 ssize_t 449 ukfs_read(struct ukfs *ukfs, const char *filename, off_t off, 450 uint8_t *buf, size_t bufsize) 451 { 452 int fd; 453 ssize_t xfer = -1; /* XXXgcc */ 454 455 precall(ukfs); 456 fd = rump_sys_open(filename, RUMP_O_RDONLY, 0); 457 if (fd == -1) 458 goto out; 459 460 xfer = rump_sys_pread(fd, buf, bufsize, off); 461 rump_sys_close(fd); 462 463 out: 464 postcall(ukfs); 465 if (fd == -1) { 466 return -1; 467 } 468 return xfer; 469 } 470 471 /*ARGSUSED*/ 472 ssize_t 473 ukfs_read_fd(struct ukfs *ukfs, int fd, off_t off, uint8_t *buf, size_t buflen) 474 { 475 476 return rump_sys_pread(fd, buf, buflen, off); 477 } 478 479 ssize_t 480 ukfs_write(struct ukfs *ukfs, const char *filename, off_t off, 481 uint8_t *buf, size_t bufsize) 482 { 483 int fd; 484 ssize_t xfer = -1; /* XXXgcc */ 485 486 precall(ukfs); 487 fd = rump_sys_open(filename, RUMP_O_WRONLY, 0); 488 if (fd == -1) 489 goto out; 490 491 /* write and commit */ 492 xfer = rump_sys_pwrite(fd, buf, bufsize, off); 493 if (xfer > 0) 494 rump_sys_fsync(fd); 495 496 rump_sys_close(fd); 497 498 out: 499 postcall(ukfs); 500 if (fd == -1) { 501 return -1; 502 } 503 return xfer; 504 } 505 506 /*ARGSUSED*/ 507 ssize_t 508 ukfs_write_fd(struct ukfs *ukfs, int fd, off_t off, uint8_t *buf, size_t buflen, 509 int dosync) 510 { 511 ssize_t xfer; 512 513 xfer = rump_sys_pwrite(fd, buf, buflen, off); 514 if (xfer > 0 && dosync) 515 rump_sys_fsync(fd); 516 517 return xfer; 518 } 519 520 /*ARGSUSED*/ 521 int 522 ukfs_close(struct ukfs *ukfs, int fd) 523 { 524 525 rump_sys_close(fd); 526 return 0; 527 } 528 529 int 530 ukfs_create(struct ukfs *ukfs, const char *filename, mode_t mode) 531 { 532 int fd; 533 534 precall(ukfs); 535 fd = rump_sys_open(filename, RUMP_O_WRONLY | RUMP_O_CREAT, mode); 536 if (fd == -1) 537 return -1; 538 rump_sys_close(fd); 539 540 postcall(ukfs); 541 return 0; 542 } 543 544 int 545 ukfs_mknod(struct ukfs *ukfs, const char *path, mode_t mode, dev_t dev) 546 { 547 548 STDCALL(ukfs, rump_sys_mknod(path, mode, dev)); 549 } 550 551 int 552 ukfs_mkfifo(struct ukfs *ukfs, const char *path, mode_t mode) 553 { 554 555 STDCALL(ukfs, rump_sys_mkfifo(path, mode)); 556 } 557 558 int 559 ukfs_mkdir(struct ukfs *ukfs, const char *filename, mode_t mode) 560 { 561 562 STDCALL(ukfs, rump_sys_mkdir(filename, mode)); 563 } 564 565 int 566 ukfs_remove(struct ukfs *ukfs, const char *filename) 567 { 568 569 STDCALL(ukfs, rump_sys_unlink(filename)); 570 } 571 572 int 573 ukfs_rmdir(struct ukfs *ukfs, const char *filename) 574 { 575 576 STDCALL(ukfs, rump_sys_rmdir(filename)); 577 } 578 579 int 580 ukfs_link(struct ukfs *ukfs, const char *filename, const char *f_create) 581 { 582 583 STDCALL(ukfs, rump_sys_link(filename, f_create)); 584 } 585 586 int 587 ukfs_symlink(struct ukfs *ukfs, const char *filename, const char *linkname) 588 { 589 590 STDCALL(ukfs, rump_sys_symlink(filename, linkname)); 591 } 592 593 ssize_t 594 ukfs_readlink(struct ukfs *ukfs, const char *filename, 595 char *linkbuf, size_t buflen) 596 { 597 ssize_t rv; 598 599 precall(ukfs); 600 rv = rump_sys_readlink(filename, linkbuf, buflen); 601 postcall(ukfs); 602 return rv; 603 } 604 605 int 606 ukfs_rename(struct ukfs *ukfs, const char *from, const char *to) 607 { 608 609 STDCALL(ukfs, rump_sys_rename(from, to)); 610 } 611 612 int 613 ukfs_chdir(struct ukfs *ukfs, const char *path) 614 { 615 struct vnode *newvp, *oldvp; 616 int rv; 617 618 precall(ukfs); 619 rv = rump_sys_chdir(path); 620 if (rv == -1) 621 goto out; 622 623 newvp = rump_cdir_get(); 624 pthread_spin_lock(&ukfs->ukfs_spin); 625 oldvp = ukfs->ukfs_cdir; 626 ukfs->ukfs_cdir = newvp; 627 pthread_spin_unlock(&ukfs->ukfs_spin); 628 if (oldvp) 629 rump_vp_rele(oldvp); 630 631 out: 632 postcall(ukfs); 633 return rv; 634 } 635 636 /* 637 * If we want to use post-time_t file systems on pre-time_t hosts, 638 * we must translate the stat structure. Since we don't currently 639 * have a general method for making compat calls in rump, special-case 640 * this one. 641 * 642 * Note that this does not allow making system calls to older rump 643 * kernels from newer hosts. 644 */ 645 #define VERS_TIMECHANGE 599000700 646 647 static int 648 needcompat(void) 649 { 650 651 #ifdef __NetBSD__ 652 /*LINTED*/ 653 return __NetBSD_Version__ < VERS_TIMECHANGE 654 && rump_getversion() >= VERS_TIMECHANGE; 655 #else 656 return 0; 657 #endif 658 } 659 660 int 661 ukfs_stat(struct ukfs *ukfs, const char *filename, struct stat *file_stat) 662 { 663 int rv; 664 665 precall(ukfs); 666 if (needcompat()) 667 rv = rump_sys___stat30(filename, file_stat); 668 else 669 rv = rump_sys_stat(filename, file_stat); 670 postcall(ukfs); 671 672 return rv; 673 } 674 675 int 676 ukfs_lstat(struct ukfs *ukfs, const char *filename, struct stat *file_stat) 677 { 678 int rv; 679 680 precall(ukfs); 681 if (needcompat()) 682 rv = rump_sys___lstat30(filename, file_stat); 683 else 684 rv = rump_sys_lstat(filename, file_stat); 685 postcall(ukfs); 686 687 return rv; 688 } 689 690 int 691 ukfs_chmod(struct ukfs *ukfs, const char *filename, mode_t mode) 692 { 693 694 STDCALL(ukfs, rump_sys_chmod(filename, mode)); 695 } 696 697 int 698 ukfs_lchmod(struct ukfs *ukfs, const char *filename, mode_t mode) 699 { 700 701 STDCALL(ukfs, rump_sys_lchmod(filename, mode)); 702 } 703 704 int 705 ukfs_chown(struct ukfs *ukfs, const char *filename, uid_t uid, gid_t gid) 706 { 707 708 STDCALL(ukfs, rump_sys_chown(filename, uid, gid)); 709 } 710 711 int 712 ukfs_lchown(struct ukfs *ukfs, const char *filename, uid_t uid, gid_t gid) 713 { 714 715 STDCALL(ukfs, rump_sys_lchown(filename, uid, gid)); 716 } 717 718 int 719 ukfs_chflags(struct ukfs *ukfs, const char *filename, u_long flags) 720 { 721 722 STDCALL(ukfs, rump_sys_chflags(filename, flags)); 723 } 724 725 int 726 ukfs_lchflags(struct ukfs *ukfs, const char *filename, u_long flags) 727 { 728 729 STDCALL(ukfs, rump_sys_lchflags(filename, flags)); 730 } 731 732 int 733 ukfs_utimes(struct ukfs *ukfs, const char *filename, const struct timeval *tptr) 734 { 735 736 STDCALL(ukfs, rump_sys_utimes(filename, tptr)); 737 } 738 739 int 740 ukfs_lutimes(struct ukfs *ukfs, const char *filename, 741 const struct timeval *tptr) 742 { 743 744 STDCALL(ukfs, rump_sys_lutimes(filename, tptr)); 745 } 746 747 /* 748 * Dynamic module support 749 */ 750 751 /* load one library */ 752 753 /* 754 * XXX: the dlerror stuff isn't really threadsafe, but then again I 755 * can't protect against other threads calling dl*() outside of ukfs, 756 * so just live with it being flimsy 757 */ 758 int 759 ukfs_modload(const char *fname) 760 { 761 void *handle; 762 struct modinfo **mi; 763 int error; 764 765 handle = dlopen(fname, RTLD_GLOBAL); 766 if (handle == NULL) { 767 const char *dlmsg = dlerror(); 768 if (strstr(dlmsg, "Undefined symbol")) 769 return 0; 770 warnx("dlopen %s failed: %s\n", fname, dlmsg); 771 /* XXXerrno */ 772 return -1; 773 } 774 775 mi = dlsym(handle, "__start_link_set_modules"); 776 if (mi) { 777 error = rump_module_init(*mi, NULL); 778 if (error) 779 goto errclose; 780 return 1; 781 } 782 error = EINVAL; 783 784 errclose: 785 dlclose(handle); 786 errno = error; 787 return -1; 788 } 789 790 struct loadfail { 791 char *pname; 792 793 LIST_ENTRY(loadfail) entries; 794 }; 795 796 #define RUMPFSMOD_PREFIX "librumpfs_" 797 #define RUMPFSMOD_SUFFIX ".so" 798 799 int 800 ukfs_modload_dir(const char *dir) 801 { 802 char nbuf[MAXPATHLEN+1], *p; 803 struct dirent entry, *result; 804 DIR *libdir; 805 struct loadfail *lf, *nlf; 806 int error, nloaded = 0, redo; 807 LIST_HEAD(, loadfail) lfs; 808 809 libdir = opendir(dir); 810 if (libdir == NULL) 811 return -1; 812 813 LIST_INIT(&lfs); 814 for (;;) { 815 if ((error = readdir_r(libdir, &entry, &result)) != 0) 816 break; 817 if (!result) 818 break; 819 if (strncmp(result->d_name, RUMPFSMOD_PREFIX, 820 strlen(RUMPFSMOD_PREFIX)) != 0) 821 continue; 822 if (((p = strstr(result->d_name, RUMPFSMOD_SUFFIX)) == NULL) 823 || strlen(p) != strlen(RUMPFSMOD_SUFFIX)) 824 continue; 825 strlcpy(nbuf, dir, sizeof(nbuf)); 826 strlcat(nbuf, "/", sizeof(nbuf)); 827 strlcat(nbuf, result->d_name, sizeof(nbuf)); 828 switch (ukfs_modload(nbuf)) { 829 case 0: 830 lf = malloc(sizeof(*lf)); 831 if (lf == NULL) { 832 error = ENOMEM; 833 break; 834 } 835 lf->pname = strdup(nbuf); 836 if (lf->pname == NULL) { 837 free(lf); 838 error = ENOMEM; 839 break; 840 } 841 LIST_INSERT_HEAD(&lfs, lf, entries); 842 break; 843 case 1: 844 nloaded++; 845 break; 846 default: 847 /* ignore errors */ 848 break; 849 } 850 } 851 closedir(libdir); 852 if (error && nloaded != 0) 853 error = 0; 854 855 /* 856 * El-cheapo dependency calculator. Just try to load the 857 * modules n times in a loop 858 */ 859 for (redo = 1; redo;) { 860 redo = 0; 861 nlf = LIST_FIRST(&lfs); 862 while ((lf = nlf) != NULL) { 863 nlf = LIST_NEXT(lf, entries); 864 if (ukfs_modload(lf->pname) == 1) { 865 nloaded++; 866 redo = 1; 867 LIST_REMOVE(lf, entries); 868 free(lf->pname); 869 free(lf); 870 } 871 } 872 } 873 874 while ((lf = LIST_FIRST(&lfs)) != NULL) { 875 LIST_REMOVE(lf, entries); 876 free(lf->pname); 877 free(lf); 878 } 879 880 if (error && nloaded == 0) { 881 errno = error; 882 return -1; 883 } 884 885 return nloaded; 886 } 887 888 /* XXX: this code uses definitions from NetBSD, needs rumpdefs */ 889 ssize_t 890 ukfs_vfstypes(char *buf, size_t buflen) 891 { 892 int mib[3]; 893 struct sysctlnode q, ans[128]; 894 size_t alen; 895 int i; 896 897 mib[0] = CTL_VFS; 898 mib[1] = VFS_GENERIC; 899 mib[2] = CTL_QUERY; 900 alen = sizeof(ans); 901 902 memset(&q, 0, sizeof(q)); 903 q.sysctl_flags = SYSCTL_VERSION; 904 905 if (rump_sys___sysctl(mib, 3, ans, &alen, &q, sizeof(q)) == -1) { 906 return -1; 907 } 908 909 for (i = 0; i < alen/sizeof(ans[0]); i++) 910 if (strcmp("fstypes", ans[i].sysctl_name) == 0) 911 break; 912 if (i == alen/sizeof(ans[0])) { 913 errno = ENXIO; 914 return -1; 915 } 916 917 mib[0] = CTL_VFS; 918 mib[1] = VFS_GENERIC; 919 mib[2] = ans[i].sysctl_num; 920 921 if (rump_sys___sysctl(mib, 3, buf, &buflen, NULL, 0) == -1) { 922 return -1; 923 } 924 925 return buflen; 926 } 927 928 /* 929 * Utilities 930 */ 931 static int 932 builddirs(const char *pathname, mode_t mode, 933 int (*mkdirfn)(struct ukfs *, const char *, mode_t), struct ukfs *fs) 934 { 935 char *f1, *f2; 936 int rv; 937 mode_t mask; 938 bool end; 939 940 /*ukfs_umask((mask = ukfs_umask(0)));*/ 941 umask((mask = umask(0))); 942 943 f1 = f2 = strdup(pathname); 944 if (f1 == NULL) { 945 errno = ENOMEM; 946 return -1; 947 } 948 949 end = false; 950 for (;;) { 951 /* find next component */ 952 f2 += strspn(f2, "/"); 953 f2 += strcspn(f2, "/"); 954 if (*f2 == '\0') 955 end = true; 956 else 957 *f2 = '\0'; 958 959 rv = mkdirfn(fs, f1, mode & ~mask); 960 if (errno == EEXIST) 961 rv = 0; 962 963 if (rv == -1 || *f2 != '\0' || end) 964 break; 965 966 *f2 = '/'; 967 } 968 969 free(f1); 970 971 return rv; 972 } 973 974 int 975 ukfs_util_builddirs(struct ukfs *ukfs, const char *pathname, mode_t mode) 976 { 977 978 return builddirs(pathname, mode, ukfs_mkdir, ukfs); 979 } 980