1 /* $NetBSD: ukfs.c,v 1.26 2009/05/02 15:20:08 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, 0, 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, 0, 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, 0, 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, 0, 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 int 594 ukfs_stat(struct ukfs *ukfs, const char *filename, struct stat *file_stat) 595 { 596 597 STDCALL(ukfs, rump_sys_stat(filename, file_stat)); 598 } 599 600 int 601 ukfs_lstat(struct ukfs *ukfs, const char *filename, struct stat *file_stat) 602 { 603 604 STDCALL(ukfs, rump_sys_lstat(filename, file_stat)); 605 } 606 607 int 608 ukfs_chmod(struct ukfs *ukfs, const char *filename, mode_t mode) 609 { 610 611 STDCALL(ukfs, rump_sys_chmod(filename, mode)); 612 } 613 614 int 615 ukfs_lchmod(struct ukfs *ukfs, const char *filename, mode_t mode) 616 { 617 618 STDCALL(ukfs, rump_sys_lchmod(filename, mode)); 619 } 620 621 int 622 ukfs_chown(struct ukfs *ukfs, const char *filename, uid_t uid, gid_t gid) 623 { 624 625 STDCALL(ukfs, rump_sys_chown(filename, uid, gid)); 626 } 627 628 int 629 ukfs_lchown(struct ukfs *ukfs, const char *filename, uid_t uid, gid_t gid) 630 { 631 632 STDCALL(ukfs, rump_sys_lchown(filename, uid, gid)); 633 } 634 635 int 636 ukfs_chflags(struct ukfs *ukfs, const char *filename, u_long flags) 637 { 638 639 STDCALL(ukfs, rump_sys_chflags(filename, flags)); 640 } 641 642 int 643 ukfs_lchflags(struct ukfs *ukfs, const char *filename, u_long flags) 644 { 645 646 STDCALL(ukfs, rump_sys_lchflags(filename, flags)); 647 } 648 649 int 650 ukfs_utimes(struct ukfs *ukfs, const char *filename, const struct timeval *tptr) 651 { 652 653 STDCALL(ukfs, rump_sys_utimes(filename, tptr)); 654 } 655 656 int 657 ukfs_lutimes(struct ukfs *ukfs, const char *filename, 658 const struct timeval *tptr) 659 { 660 661 STDCALL(ukfs, rump_sys_lutimes(filename, tptr)); 662 } 663 664 /* 665 * Dynamic module support 666 */ 667 668 /* load one library */ 669 670 /* 671 * XXX: the dlerror stuff isn't really threadsafe, but then again I 672 * can't protect against other threads calling dl*() outside of ukfs, 673 * so just live with it being flimsy 674 */ 675 int 676 ukfs_modload(const char *fname) 677 { 678 void *handle; 679 struct modinfo **mi; 680 struct stat sb; 681 int error; 682 683 if (stat(fname, &sb) == -1) 684 return -1; 685 686 handle = dlopen(fname, RTLD_GLOBAL); 687 if (handle == NULL) { 688 const char *dlmsg = dlerror(); 689 if (strstr(dlmsg, "Undefined symbol")) 690 return 0; 691 warnx("dlopen %s failed: %s\n", fname, dlmsg); 692 /* XXXerrno */ 693 return -1; 694 } 695 696 mi = dlsym(handle, "__start_link_set_modules"); 697 if (mi) { 698 error = rump_module_init(*mi, NULL); 699 if (error) 700 goto errclose; 701 return 1; 702 } 703 error = EINVAL; 704 705 errclose: 706 dlclose(handle); 707 errno = error; 708 return -1; 709 } 710 711 struct loadfail { 712 char *pname; 713 714 LIST_ENTRY(loadfail) entries; 715 }; 716 717 #define RUMPFSMOD_PREFIX "librumpfs_" 718 #define RUMPFSMOD_SUFFIX ".so" 719 720 int 721 ukfs_modload_dir(const char *dir) 722 { 723 char nbuf[MAXPATHLEN+1], *p; 724 struct dirent entry, *result; 725 DIR *libdir; 726 struct loadfail *lf, *nlf; 727 int error, nloaded = 0, redo; 728 LIST_HEAD(, loadfail) lfs; 729 730 libdir = opendir(dir); 731 if (libdir == NULL) 732 return -1; 733 734 LIST_INIT(&lfs); 735 for (;;) { 736 if ((error = readdir_r(libdir, &entry, &result)) != 0) 737 break; 738 if (!result) 739 break; 740 if (strncmp(result->d_name, RUMPFSMOD_PREFIX, 741 strlen(RUMPFSMOD_PREFIX)) != 0) 742 continue; 743 if (((p = strstr(result->d_name, RUMPFSMOD_SUFFIX)) == NULL) 744 || strlen(p) != strlen(RUMPFSMOD_SUFFIX)) 745 continue; 746 strlcpy(nbuf, dir, sizeof(nbuf)); 747 strlcat(nbuf, "/", sizeof(nbuf)); 748 strlcat(nbuf, result->d_name, sizeof(nbuf)); 749 switch (ukfs_modload(nbuf)) { 750 case 0: 751 lf = malloc(sizeof(*lf)); 752 if (lf == NULL) { 753 error = ENOMEM; 754 break; 755 } 756 lf->pname = strdup(nbuf); 757 if (lf->pname == NULL) { 758 free(lf); 759 error = ENOMEM; 760 break; 761 } 762 LIST_INSERT_HEAD(&lfs, lf, entries); 763 break; 764 case 1: 765 nloaded++; 766 break; 767 default: 768 /* ignore errors */ 769 break; 770 } 771 } 772 closedir(libdir); 773 if (error && nloaded != 0) 774 error = 0; 775 776 /* 777 * El-cheapo dependency calculator. Just try to load the 778 * modules n times in a loop 779 */ 780 for (redo = 1; redo;) { 781 redo = 0; 782 nlf = LIST_FIRST(&lfs); 783 while ((lf = nlf) != NULL) { 784 nlf = LIST_NEXT(lf, entries); 785 if (ukfs_modload(lf->pname) == 1) { 786 nloaded++; 787 redo = 1; 788 LIST_REMOVE(lf, entries); 789 free(lf->pname); 790 free(lf); 791 } 792 } 793 } 794 795 while ((lf = LIST_FIRST(&lfs)) != NULL) { 796 LIST_REMOVE(lf, entries); 797 free(lf->pname); 798 free(lf); 799 } 800 801 if (error && nloaded == 0) { 802 errno = error; 803 return -1; 804 } 805 806 return nloaded; 807 } 808 809 /* XXX: this code uses definitions from NetBSD, needs rumpdefs */ 810 ssize_t 811 ukfs_vfstypes(char *buf, size_t buflen) 812 { 813 int mib[3]; 814 struct sysctlnode q, ans[128]; 815 size_t alen; 816 int i; 817 818 mib[0] = CTL_VFS; 819 mib[1] = VFS_GENERIC; 820 mib[2] = CTL_QUERY; 821 alen = sizeof(ans); 822 823 memset(&q, 0, sizeof(q)); 824 q.sysctl_flags = SYSCTL_VERSION; 825 826 if (rump_sys___sysctl(mib, 3, ans, &alen, &q, sizeof(q)) == -1) { 827 return -1; 828 } 829 830 for (i = 0; i < alen/sizeof(ans[0]); i++) 831 if (strcmp("fstypes", ans[i].sysctl_name) == 0) 832 break; 833 if (i == alen/sizeof(ans[0])) { 834 errno = ENXIO; 835 return -1; 836 } 837 838 mib[0] = CTL_VFS; 839 mib[1] = VFS_GENERIC; 840 mib[2] = ans[i].sysctl_num; 841 842 if (rump_sys___sysctl(mib, 3, buf, &buflen, NULL, 0) == -1) { 843 return -1; 844 } 845 846 return buflen; 847 } 848 849 /* 850 * Utilities 851 */ 852 int 853 ukfs_util_builddirs(struct ukfs *ukfs, const char *pathname, mode_t mode) 854 { 855 char *f1, *f2; 856 int rv; 857 mode_t mask; 858 bool end; 859 860 /*ukfs_umask((mask = ukfs_umask(0)));*/ 861 umask((mask = umask(0))); 862 863 f1 = f2 = strdup(pathname); 864 if (f1 == NULL) { 865 errno = ENOMEM; 866 return -1; 867 } 868 869 end = false; 870 for (;;) { 871 /* find next component */ 872 f2 += strspn(f2, "/"); 873 f2 += strcspn(f2, "/"); 874 if (*f2 == '\0') 875 end = true; 876 else 877 *f2 = '\0'; 878 879 rv = ukfs_mkdir(ukfs, f1, mode & ~mask); 880 if (errno == EEXIST) 881 rv = 0; 882 883 if (rv == -1 || *f2 != '\0' || end) 884 break; 885 886 *f2 = '/'; 887 } 888 889 free(f1); 890 891 return rv; 892 } 893