ukfs.c revision 1.29 1 /* $NetBSD: ukfs.c,v 1.29 2009/07/21 00:19:57 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 int error;
720
721 handle = dlopen(fname, RTLD_GLOBAL);
722 if (handle == NULL) {
723 const char *dlmsg = dlerror();
724 if (strstr(dlmsg, "Undefined symbol"))
725 return 0;
726 warnx("dlopen %s failed: %s\n", fname, dlmsg);
727 /* XXXerrno */
728 return -1;
729 }
730
731 mi = dlsym(handle, "__start_link_set_modules");
732 if (mi) {
733 error = rump_module_init(*mi, NULL);
734 if (error)
735 goto errclose;
736 return 1;
737 }
738 error = EINVAL;
739
740 errclose:
741 dlclose(handle);
742 errno = error;
743 return -1;
744 }
745
746 struct loadfail {
747 char *pname;
748
749 LIST_ENTRY(loadfail) entries;
750 };
751
752 #define RUMPFSMOD_PREFIX "librumpfs_"
753 #define RUMPFSMOD_SUFFIX ".so"
754
755 int
756 ukfs_modload_dir(const char *dir)
757 {
758 char nbuf[MAXPATHLEN+1], *p;
759 struct dirent entry, *result;
760 DIR *libdir;
761 struct loadfail *lf, *nlf;
762 int error, nloaded = 0, redo;
763 LIST_HEAD(, loadfail) lfs;
764
765 libdir = opendir(dir);
766 if (libdir == NULL)
767 return -1;
768
769 LIST_INIT(&lfs);
770 for (;;) {
771 if ((error = readdir_r(libdir, &entry, &result)) != 0)
772 break;
773 if (!result)
774 break;
775 if (strncmp(result->d_name, RUMPFSMOD_PREFIX,
776 strlen(RUMPFSMOD_PREFIX)) != 0)
777 continue;
778 if (((p = strstr(result->d_name, RUMPFSMOD_SUFFIX)) == NULL)
779 || strlen(p) != strlen(RUMPFSMOD_SUFFIX))
780 continue;
781 strlcpy(nbuf, dir, sizeof(nbuf));
782 strlcat(nbuf, "/", sizeof(nbuf));
783 strlcat(nbuf, result->d_name, sizeof(nbuf));
784 switch (ukfs_modload(nbuf)) {
785 case 0:
786 lf = malloc(sizeof(*lf));
787 if (lf == NULL) {
788 error = ENOMEM;
789 break;
790 }
791 lf->pname = strdup(nbuf);
792 if (lf->pname == NULL) {
793 free(lf);
794 error = ENOMEM;
795 break;
796 }
797 LIST_INSERT_HEAD(&lfs, lf, entries);
798 break;
799 case 1:
800 nloaded++;
801 break;
802 default:
803 /* ignore errors */
804 break;
805 }
806 }
807 closedir(libdir);
808 if (error && nloaded != 0)
809 error = 0;
810
811 /*
812 * El-cheapo dependency calculator. Just try to load the
813 * modules n times in a loop
814 */
815 for (redo = 1; redo;) {
816 redo = 0;
817 nlf = LIST_FIRST(&lfs);
818 while ((lf = nlf) != NULL) {
819 nlf = LIST_NEXT(lf, entries);
820 if (ukfs_modload(lf->pname) == 1) {
821 nloaded++;
822 redo = 1;
823 LIST_REMOVE(lf, entries);
824 free(lf->pname);
825 free(lf);
826 }
827 }
828 }
829
830 while ((lf = LIST_FIRST(&lfs)) != NULL) {
831 LIST_REMOVE(lf, entries);
832 free(lf->pname);
833 free(lf);
834 }
835
836 if (error && nloaded == 0) {
837 errno = error;
838 return -1;
839 }
840
841 return nloaded;
842 }
843
844 /* XXX: this code uses definitions from NetBSD, needs rumpdefs */
845 ssize_t
846 ukfs_vfstypes(char *buf, size_t buflen)
847 {
848 int mib[3];
849 struct sysctlnode q, ans[128];
850 size_t alen;
851 int i;
852
853 mib[0] = CTL_VFS;
854 mib[1] = VFS_GENERIC;
855 mib[2] = CTL_QUERY;
856 alen = sizeof(ans);
857
858 memset(&q, 0, sizeof(q));
859 q.sysctl_flags = SYSCTL_VERSION;
860
861 if (rump_sys___sysctl(mib, 3, ans, &alen, &q, sizeof(q)) == -1) {
862 return -1;
863 }
864
865 for (i = 0; i < alen/sizeof(ans[0]); i++)
866 if (strcmp("fstypes", ans[i].sysctl_name) == 0)
867 break;
868 if (i == alen/sizeof(ans[0])) {
869 errno = ENXIO;
870 return -1;
871 }
872
873 mib[0] = CTL_VFS;
874 mib[1] = VFS_GENERIC;
875 mib[2] = ans[i].sysctl_num;
876
877 if (rump_sys___sysctl(mib, 3, buf, &buflen, NULL, 0) == -1) {
878 return -1;
879 }
880
881 return buflen;
882 }
883
884 /*
885 * Utilities
886 */
887 int
888 ukfs_util_builddirs(struct ukfs *ukfs, const char *pathname, mode_t mode)
889 {
890 char *f1, *f2;
891 int rv;
892 mode_t mask;
893 bool end;
894
895 /*ukfs_umask((mask = ukfs_umask(0)));*/
896 umask((mask = umask(0)));
897
898 f1 = f2 = strdup(pathname);
899 if (f1 == NULL) {
900 errno = ENOMEM;
901 return -1;
902 }
903
904 end = false;
905 for (;;) {
906 /* find next component */
907 f2 += strspn(f2, "/");
908 f2 += strcspn(f2, "/");
909 if (*f2 == '\0')
910 end = true;
911 else
912 *f2 = '\0';
913
914 rv = ukfs_mkdir(ukfs, f1, mode & ~mask);
915 if (errno == EEXIST)
916 rv = 0;
917
918 if (rv == -1 || *f2 != '\0' || end)
919 break;
920
921 *f2 = '/';
922 }
923
924 free(f1);
925
926 return rv;
927 }
928