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