ukfs.c revision 1.24 1 /* $NetBSD: ukfs.c,v 1.24 2009/04/26 22:23:01 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 #define UFSLIB "librumpfs_ufs.so"
676 int
677 ukfs_modload(const char *fname)
678 {
679 void *handle, *thesym;
680 struct stat sb;
681 const char *p;
682 int error;
683
684 if (stat(fname, &sb) == -1)
685 return -1;
686
687 handle = dlopen(fname, RTLD_GLOBAL);
688 if (handle == NULL) {
689 const char *dlmsg = dlerror();
690 if (strstr(dlmsg, "Undefined symbol"))
691 return 0;
692 warnx("dlopen %s failed: %s\n", fname, dlmsg);
693 /* XXXerrno */
694 return -1;
695 }
696
697 /*
698 * XXX: the ufs module is not loaded in the same fashion as the
699 * others. But we can't do dlclose() for it, since that would
700 * lead to not being able to load ffs/ext2fs/lfs. Hence hardcode
701 * and kludge around the issue for now. But this should really
702 * be fixed by fixing sys/ufs/ufs to be a kernel module.
703 */
704 if ((p = strrchr(fname, '/')) != NULL)
705 p++;
706 else
707 p = fname;
708 if (strcmp(p, UFSLIB) == 0)
709 return 1;
710
711 thesym = dlsym(handle, "__start_link_set_modules");
712 if (thesym) {
713 error = rump_module_load(thesym);
714 if (error)
715 goto errclose;
716 return 1;
717 }
718 error = EINVAL;
719
720 errclose:
721 dlclose(handle);
722 errno = error;
723 return -1;
724 }
725
726 struct loadfail {
727 char *pname;
728
729 LIST_ENTRY(loadfail) entries;
730 };
731
732 #define RUMPFSMOD_PREFIX "librumpfs_"
733 #define RUMPFSMOD_SUFFIX ".so"
734
735 int
736 ukfs_modload_dir(const char *dir)
737 {
738 char nbuf[MAXPATHLEN+1], *p;
739 struct dirent entry, *result;
740 DIR *libdir;
741 struct loadfail *lf, *nlf;
742 int error, nloaded = 0, redo;
743 LIST_HEAD(, loadfail) lfs;
744
745 libdir = opendir(dir);
746 if (libdir == NULL)
747 return -1;
748
749 LIST_INIT(&lfs);
750 for (;;) {
751 if ((error = readdir_r(libdir, &entry, &result)) != 0)
752 break;
753 if (!result)
754 break;
755 if (strncmp(result->d_name, RUMPFSMOD_PREFIX,
756 strlen(RUMPFSMOD_PREFIX)) != 0)
757 continue;
758 if (((p = strstr(result->d_name, RUMPFSMOD_SUFFIX)) == NULL)
759 || strlen(p) != strlen(RUMPFSMOD_SUFFIX))
760 continue;
761 strlcpy(nbuf, dir, sizeof(nbuf));
762 strlcat(nbuf, "/", sizeof(nbuf));
763 strlcat(nbuf, result->d_name, sizeof(nbuf));
764 switch (ukfs_modload(nbuf)) {
765 case 0:
766 lf = malloc(sizeof(*lf));
767 if (lf == NULL) {
768 error = ENOMEM;
769 break;
770 }
771 lf->pname = strdup(nbuf);
772 if (lf->pname == NULL) {
773 free(lf);
774 error = ENOMEM;
775 break;
776 }
777 LIST_INSERT_HEAD(&lfs, lf, entries);
778 break;
779 case 1:
780 nloaded++;
781 break;
782 default:
783 /* ignore errors */
784 break;
785 }
786 }
787 closedir(libdir);
788 if (error && nloaded != 0)
789 error = 0;
790
791 /*
792 * El-cheapo dependency calculator. Just try to load the
793 * modules n times in a loop
794 */
795 for (redo = 1; redo;) {
796 redo = 0;
797 nlf = LIST_FIRST(&lfs);
798 while ((lf = nlf) != NULL) {
799 nlf = LIST_NEXT(lf, entries);
800 if (ukfs_modload(lf->pname) == 1) {
801 nloaded++;
802 redo = 1;
803 LIST_REMOVE(lf, entries);
804 free(lf->pname);
805 free(lf);
806 }
807 }
808 }
809
810 while ((lf = LIST_FIRST(&lfs)) != NULL) {
811 LIST_REMOVE(lf, entries);
812 free(lf->pname);
813 free(lf);
814 }
815
816 if (error && nloaded == 0) {
817 errno = error;
818 return -1;
819 }
820
821 return nloaded;
822 }
823
824 /* XXX: this code uses definitions from NetBSD, needs rumpdefs */
825 ssize_t
826 ukfs_vfstypes(char *buf, size_t buflen)
827 {
828 int mib[3];
829 struct sysctlnode q, ans[128];
830 size_t alen;
831 int i;
832
833 mib[0] = CTL_VFS;
834 mib[1] = VFS_GENERIC;
835 mib[2] = CTL_QUERY;
836 alen = sizeof(ans);
837
838 memset(&q, 0, sizeof(q));
839 q.sysctl_flags = SYSCTL_VERSION;
840
841 if (rump_sys___sysctl(mib, 3, ans, &alen, &q, sizeof(q)) == -1) {
842 return -1;
843 }
844
845 for (i = 0; i < alen/sizeof(ans[0]); i++)
846 if (strcmp("fstypes", ans[i].sysctl_name) == 0)
847 break;
848 if (i == alen/sizeof(ans[0])) {
849 errno = ENXIO;
850 return -1;
851 }
852
853 mib[0] = CTL_VFS;
854 mib[1] = VFS_GENERIC;
855 mib[2] = ans[i].sysctl_num;
856
857 if (rump_sys___sysctl(mib, 3, buf, &buflen, NULL, 0) == -1) {
858 return -1;
859 }
860
861 return buflen;
862 }
863
864 /*
865 * Utilities
866 */
867 int
868 ukfs_util_builddirs(struct ukfs *ukfs, const char *pathname, mode_t mode)
869 {
870 char *f1, *f2;
871 int rv;
872 mode_t mask;
873 bool end;
874
875 /*ukfs_umask((mask = ukfs_umask(0)));*/
876 umask((mask = umask(0)));
877
878 f1 = f2 = strdup(pathname);
879 if (f1 == NULL) {
880 errno = ENOMEM;
881 return -1;
882 }
883
884 end = false;
885 for (;;) {
886 /* find next component */
887 f2 += strspn(f2, "/");
888 f2 += strcspn(f2, "/");
889 if (*f2 == '\0')
890 end = true;
891 else
892 *f2 = '\0';
893
894 rv = ukfs_mkdir(ukfs, f1, mode & ~mask);
895 if (errno == EEXIST)
896 rv = 0;
897
898 if (rv == -1 || *f2 != '\0' || end)
899 break;
900
901 *f2 = '/';
902 }
903
904 free(f1);
905
906 return rv;
907 }
908