ukfs.c revision 1.28 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