1 /* $NetBSD: ukfs.c,v 1.46 2009/12/12 00:46:04 pooka Exp $ */
4 * Copyright (c) 2007, 2008, 2009 Antti Kantee. All Rights Reserved.
6 * Development of this software was supported by the
7 * Finnish Cultural Foundation.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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
32 * This library enables access to files systems directly without
33 * involving system calls.
37 #define _XOPEN_SOURCE 500
39 #define _FILE_OFFSET_BITS 64
42 #include <sys/param.h>
43 #include <sys/queue.h>
45 #include <sys/sysctl.h>
46 #include <sys/mount.h>
61 #include <rump/ukfs.h>
63 #include <rump/rump.h>
64 #include <rump/rump_syscalls.h>
65 #include <rump/rumpuser.h>
67 #include "ukfs_int_disklabel.h"
69 #define UKFS_MODE_DEFAULT 0555
72 struct mount
*ukfs_mp
;
73 struct vnode
*ukfs_rvp
;
76 pthread_spinlock_t ukfs_spin
;
78 struct vnode
*ukfs_cdir
;
82 struct ukfs_part
*ukfs_part
;
85 static int builddirs(const char *, mode_t
,
86 int (*mkdirfn
)(struct ukfs
*, const char *, mode_t
), struct ukfs
*);
89 ukfs_getmp(struct ukfs
*ukfs
)
96 ukfs_getrvp(struct ukfs
*ukfs
)
100 rvp
= ukfs
->ukfs_rvp
;
101 rump_pub_vp_incref(rvp
);
107 ukfs_setspecific(struct ukfs
*ukfs
, void *priv
)
110 ukfs
->ukfs_specific
= priv
;
114 ukfs_getspecific(struct ukfs
*ukfs
)
117 return ukfs
->ukfs_specific
;
120 #ifdef DONT_WANT_PTHREAD_LINKAGE
121 #define pthread_spin_lock(a)
122 #define pthread_spin_unlock(a)
123 #define pthread_spin_init(a,b)
124 #define pthread_spin_destroy(a)
128 nextpid(struct ukfs
*ukfs
)
132 pthread_spin_lock(&ukfs
->ukfs_spin
);
133 if (ukfs
->ukfs_nextpid
== 0)
134 ukfs
->ukfs_nextpid
++;
135 npid
= ukfs
->ukfs_nextpid
++;
136 pthread_spin_unlock(&ukfs
->ukfs_spin
);
142 precall(struct ukfs
*ukfs
)
144 struct vnode
*rvp
, *cvp
;
146 rump_pub_lwp_alloc_and_switch(nextpid(ukfs
), 1);
147 rvp
= ukfs_getrvp(ukfs
);
148 pthread_spin_lock(&ukfs
->ukfs_spin
);
149 cvp
= ukfs
->ukfs_cdir
;
150 pthread_spin_unlock(&ukfs
->ukfs_spin
);
151 rump_pub_rcvp_set(rvp
, cvp
); /* takes refs */
152 rump_pub_vp_rele(rvp
);
156 postcall(struct ukfs
*ukfs
)
160 rvp
= ukfs_getrvp(ukfs
);
161 rump_pub_rcvp_set(NULL
, rvp
);
162 rump_pub_vp_rele(rvp
);
163 rump_pub_lwp_release(rump_pub_lwp_curlwp());
167 pthread_spinlock_t part_lck
;
176 enum ukfs_parttype
{ UKFS_PART_NONE
, UKFS_PART_DISKLABEL
, UKFS_PART_OFFSET
};
178 static struct ukfs_part ukfs__part_none
= {
179 .part_type
= UKFS_PART_NONE
,
181 .part_devsize
= RUMP_ETFS_SIZE_ENDOFF
,
183 static struct ukfs_part ukfs__part_na
;
184 struct ukfs_part
*ukfs_part_none
= &ukfs__part_none
;
185 struct ukfs_part
*ukfs_part_na
= &ukfs__part_na
;
187 #define PART2LOCKSIZE(len) ((len) == RUMP_ETFS_SIZE_ENDOFF ? 0 : (len))
190 _ukfs_init(int version
)
194 if (version
!= UKFS_VERSION
) {
195 printf("incompatible ukfs version, %d vs. %d\n",
196 version
, UKFS_VERSION
);
197 errno
= EPROGMISMATCH
;
201 if ((rv
= rump_init()) != 0) {
211 rumpmkdir(struct ukfs
*dummy
, const char *path
, mode_t mode
)
214 return rump_sys_mkdir(path
, mode
);
218 ukfs_part_probe(char *devpath
, struct ukfs_part
**partp
)
220 struct ukfs_part
*part
;
225 if ((p
= strstr(devpath
, UKFS_PARTITION_SCANMAGIC
)) != NULL
) {
226 fprintf(stderr
, "ukfs: %%PART is deprecated. use "
227 "%%DISKLABEL instead\n");
232 part
= malloc(sizeof(*part
));
237 if (pthread_spin_init(&part
->part_lck
, PTHREAD_PROCESS_PRIVATE
) == -1) {
243 part
->part_type
= UKFS_PART_NONE
;
244 part
->part_refcount
= 1;
247 * Check for magic in pathname:
248 * disklabel: /regularpath%DISKLABEL:labelchar%\0
249 * offsets: /regularpath%OFFSET:start,end%\0
251 #define MAGICADJ_DISKLABEL(p, n) (p+sizeof(UKFS_DISKLABEL_SCANMAGIC)-1+n)
252 if ((p
= strstr(devpath
, UKFS_DISKLABEL_SCANMAGIC
)) != NULL
253 && strlen(p
) == UKFS_DISKLABEL_MAGICLEN
254 && *(MAGICADJ_DISKLABEL(p
,1)) == '%') {
255 if (*(MAGICADJ_DISKLABEL(p
,0)) >= 'a' &&
256 *(MAGICADJ_DISKLABEL(p
,0)) < 'a' + UKFS_MAXPARTITIONS
) {
257 struct ukfs__disklabel dl
;
258 struct ukfs__partition
*pp
;
260 char labelchar
= *(MAGICADJ_DISKLABEL(p
,0));
261 int partition
= labelchar
- 'a';
264 devfd
= open(devpath
, O_RDONLY
);
270 /* Locate the disklabel and find the partition. */
271 if (pread(devfd
, buf
, sizeof(buf
), 0) == -1) {
276 if (ukfs__disklabel_scan(&dl
, buf
, sizeof(buf
)) != 0) {
281 if (dl
.d_npartitions
< partition
) {
286 pp
= &dl
.d_partitions
[partition
];
287 part
->part_type
= UKFS_PART_DISKLABEL
;
288 part
->part_labelchar
= labelchar
;
289 part
->part_devoff
= pp
->p_offset
<< DEV_BSHIFT
;
290 part
->part_devsize
= pp
->p_size
<< DEV_BSHIFT
;
294 #define MAGICADJ_OFFSET(p, n) (p+sizeof(UKFS_OFFSET_SCANMAGIC)-1+n)
295 } else if (((p
= strstr(devpath
, UKFS_OFFSET_SCANMAGIC
)) != NULL
)
296 && (strlen(p
) >= UKFS_OFFSET_MINLEN
)) {
297 char *comma
, *pers
, *ep
, *nptr
;
300 comma
= strchr(p
, ',');
305 pers
= strchr(comma
, '%');
314 nptr
= MAGICADJ_OFFSET(p
,0);
315 /* check if string is negative */
320 val
= strtouq(nptr
, &ep
, 10);
321 if (val
== UQUAD_MAX
) {
326 error
= EADDRNOTAVAIL
; /* creative ;) */
329 part
->part_devoff
= val
;
334 /* check if string is negative */
339 val
= strtouq(nptr
, &ep
, 10);
340 if (val
== UQUAD_MAX
) {
345 error
= EADDRNOTAVAIL
; /* creative ;) */
348 part
->part_devsize
= val
;
349 part
->part_type
= UKFS_PART_OFFSET
;
351 ukfs_part_release(part
);
352 part
= ukfs_part_none
;
365 return error
? -1 : 0;
369 ukfs_part_tostring(struct ukfs_part
*part
, char *str
, size_t strsize
)
374 /* "pseudo" values */
375 if (part
== ukfs_part_na
) {
379 if (part
== ukfs_part_none
)
383 switch (part
->part_type
) {
387 case UKFS_PART_DISKLABEL
:
388 snprintf(str
, strsize
, "%%DISKLABEL:%c%%",part
->part_labelchar
);
392 case UKFS_PART_OFFSET
:
393 snprintf(str
, strsize
, "[%llu,%llu]",
394 (unsigned long long)part
->part_devoff
,
395 (unsigned long long)(part
->part_devoff
+part
->part_devsize
));
404 unlockdev(int fd
, struct ukfs_part
*part
)
408 if (part
== ukfs_part_na
)
411 memset(&flarg
, 0, sizeof(flarg
));
412 flarg
.l_type
= F_UNLCK
;
413 flarg
.l_whence
= SEEK_SET
;
414 flarg
.l_start
= part
->part_devoff
;
415 flarg
.l_len
= PART2LOCKSIZE(part
->part_devsize
);
416 if (fcntl(fd
, F_SETLK
, &flarg
) == -1)
417 warn("ukfs: cannot unlock device file");
421 * Open the disk file and flock it. Also, if we are operation on
422 * an embedded partition, find the partition offset and size from
425 * We hard-fail only in two cases:
426 * 1) we failed to get the partition info out (don't know what offset
428 * 2) we failed to flock the source device (i.e. fcntl() fails,
429 * not e.g. open() before it)
431 * Otherwise we let the code proceed to mount and let the file system
432 * throw the proper error. The only questionable bit is that if we
433 * soft-fail before flock and mount does succeed...
435 * Returns: -1 error (errno reports error code)
438 * dfdp: -1 device is not open
442 process_diskdevice(const char *devpath
, struct ukfs_part
*part
, int rdonly
,
451 devfd
= open(devpath
, rdonly
? O_RDONLY
: O_RDWR
);
457 if (fstat(devfd
, &sb
) == -1) {
463 * We do this only for non-block device since the
464 * (NetBSD) kernel allows block device open only once.
465 * We also need to close the device for fairly obvious reasons.
467 if (!S_ISBLK(sb
.st_mode
)) {
470 memset(&flarg
, 0, sizeof(flarg
));
471 flarg
.l_type
= rdonly
? F_RDLCK
: F_WRLCK
;
472 flarg
.l_whence
= SEEK_SET
;
473 flarg
.l_start
= part
->part_devoff
;
474 flarg
.l_len
= PART2LOCKSIZE(part
->part_devsize
);
475 if (fcntl(devfd
, F_SETLK
, &flarg
) == -1) {
480 if (fcntl(devfd
, F_GETLK
, &flarg
) != 1)
481 holder
= flarg
.l_pid
;
484 warnx("ukfs_mount: cannot lock device. held by pid %d",
505 doukfsmount(const char *vfsname
, const char *devpath
, struct ukfs_part
*part
,
506 const char *mountpath
, int mntflags
, void *arg
, size_t alen
)
508 struct ukfs
*fs
= NULL
;
509 int rv
= 0, devfd
= -1;
513 pthread_spin_lock(&part
->part_lck
);
514 part
->part_refcount
++;
515 pthread_spin_unlock(&part
->part_lck
);
516 if (part
!= ukfs_part_na
) {
517 if ((rv
= process_diskdevice(devpath
, part
,
518 mntflags
& MNT_RDONLY
, &devfd
)) != 0)
522 fs
= malloc(sizeof(struct ukfs
));
527 memset(fs
, 0, sizeof(struct ukfs
));
529 /* create our mountpoint. this is never removed. */
530 if (builddirs(mountpath
, 0777, rumpmkdir
, NULL
) == -1) {
531 if (errno
!= EEXIST
) {
537 if (part
!= ukfs_part_na
) {
539 rv
= rump_pub_etfs_register_withsize(devpath
, devpath
,
540 RUMP_ETFS_BLK
, part
->part_devoff
, part
->part_devsize
);
547 rv
= rump_sys_mount(vfsname
, mountpath
, mntflags
, arg
, alen
);
553 rv
= rump_pub_vfs_getmp(mountpath
, &fs
->ukfs_mp
);
557 rv
= rump_pub_vfs_root(fs
->ukfs_mp
, &fs
->ukfs_rvp
, 0);
563 fs
->ukfs_devpath
= strdup(devpath
);
565 fs
->ukfs_mountpath
= strdup(mountpath
);
566 fs
->ukfs_cdir
= ukfs_getrvp(fs
);
567 pthread_spin_init(&fs
->ukfs_spin
, PTHREAD_PROCESS_SHARED
);
568 fs
->ukfs_devfd
= devfd
;
569 fs
->ukfs_part
= part
;
576 rump_pub_vp_rele(fs
->ukfs_rvp
);
581 rump_sys_unmount(mountpath
, MNT_FORCE
);
583 rump_pub_etfs_remove(devpath
);
585 unlockdev(devfd
, part
);
588 ukfs_part_release(part
);
596 ukfs_mount(const char *vfsname
, const char *devpath
,
597 const char *mountpath
, int mntflags
, void *arg
, size_t alen
)
600 return doukfsmount(vfsname
, devpath
, ukfs_part_na
,
601 mountpath
, mntflags
, arg
, alen
);
605 ukfs_mount_disk(const char *vfsname
, const char *devpath
,
606 struct ukfs_part
*part
, const char *mountpath
, int mntflags
,
607 void *arg
, size_t alen
)
610 return doukfsmount(vfsname
, devpath
, part
,
611 mountpath
, mntflags
, arg
, alen
);
615 ukfs_release(struct ukfs
*fs
, int flags
)
618 if ((flags
& UKFS_RELFLAG_NOUNMOUNT
) == 0) {
619 int rv
, mntflag
, error
;
623 if (flags
& UKFS_RELFLAG_FORCE
)
625 rump_pub_lwp_alloc_and_switch(nextpid(fs
), 1);
626 rump_pub_vp_rele(fs
->ukfs_rvp
);
628 rv
= rump_sys_unmount(fs
->ukfs_mountpath
, mntflag
);
631 rump_pub_vfs_root(fs
->ukfs_mp
, &fs
->ukfs_rvp
, 0);
632 rump_pub_lwp_release(rump_pub_lwp_curlwp());
633 ukfs_chdir(fs
, fs
->ukfs_mountpath
);
637 rump_pub_lwp_release(rump_pub_lwp_curlwp());
640 if (fs
->ukfs_devpath
) {
641 rump_pub_etfs_remove(fs
->ukfs_devpath
);
642 free(fs
->ukfs_devpath
);
644 free(fs
->ukfs_mountpath
);
646 pthread_spin_destroy(&fs
->ukfs_spin
);
647 if (fs
->ukfs_devfd
!= -1) {
648 unlockdev(fs
->ukfs_devfd
, fs
->ukfs_part
);
649 close(fs
->ukfs_devfd
);
651 ukfs_part_release(fs
->ukfs_part
);
658 ukfs_part_release(struct ukfs_part
*part
)
662 if (part
!= ukfs_part_none
&& part
!= ukfs_part_na
) {
663 pthread_spin_lock(&part
->part_lck
);
664 release
= --part
->part_refcount
== 0;
665 pthread_spin_unlock(&part
->part_lck
);
667 pthread_spin_destroy(&part
->part_lck
);
673 #define STDCALL(ukfs, thecall) \
682 ukfs_opendir(struct ukfs
*ukfs
, const char *dirname
, struct ukfs_dircookie
**c
)
688 rv
= rump_pub_namei(RUMP_NAMEI_LOOKUP
, RUMP_NAMEI_LOCKLEAF
, dirname
,
693 RUMP_VOP_UNLOCK(vp
, 0);
700 *c
= (struct ukfs_dircookie
*)vp
;
705 getmydents(struct vnode
*vp
, off_t
*off
, uint8_t *buf
, size_t bufsize
)
712 uio
= rump_pub_uio_setup(buf
, bufsize
, *off
, RUMPUIO_READ
);
713 cred
= rump_pub_cred_suserget();
714 rv
= RUMP_VOP_READDIR(vp
, uio
, cred
, &eofflag
, NULL
, NULL
);
715 rump_pub_cred_put(cred
);
716 RUMP_VOP_UNLOCK(vp
, 0);
717 *off
= rump_pub_uio_getoff(uio
);
718 resid
= rump_pub_uio_free(uio
);
725 /* LINTED: not totally correct return type, but follows syscall */
726 return bufsize
- resid
;
731 ukfs_getdents_cookie(struct ukfs
*ukfs
, struct ukfs_dircookie
*c
, off_t
*off
,
732 uint8_t *buf
, size_t bufsize
)
735 struct vnode
*vp
= (struct vnode
*)c
;
737 RUMP_VOP_LOCK(vp
, RUMP_LK_SHARED
);
738 return getmydents(vp
, off
, buf
, bufsize
);
742 ukfs_getdents(struct ukfs
*ukfs
, const char *dirname
, off_t
*off
,
743 uint8_t *buf
, size_t bufsize
)
749 rv
= rump_pub_namei(RUMP_NAMEI_LOOKUP
, RUMP_NAMEI_LOCKLEAF
, dirname
,
757 rv
= getmydents(vp
, off
, buf
, bufsize
);
758 rump_pub_vp_rele(vp
);
764 ukfs_closedir(struct ukfs
*ukfs
, struct ukfs_dircookie
*c
)
768 rump_pub_vp_rele((struct vnode
*)c
);
773 ukfs_open(struct ukfs
*ukfs
, const char *filename
, int flags
)
778 fd
= rump_sys_open(filename
, flags
, 0);
787 ukfs_read(struct ukfs
*ukfs
, const char *filename
, off_t off
,
788 uint8_t *buf
, size_t bufsize
)
791 ssize_t xfer
= -1; /* XXXgcc */
794 fd
= rump_sys_open(filename
, RUMP_O_RDONLY
, 0);
798 xfer
= rump_sys_pread(fd
, buf
, bufsize
, off
);
811 ukfs_read_fd(struct ukfs
*ukfs
, int fd
, off_t off
, uint8_t *buf
, size_t buflen
)
814 return rump_sys_pread(fd
, buf
, buflen
, off
);
818 ukfs_write(struct ukfs
*ukfs
, const char *filename
, off_t off
,
819 uint8_t *buf
, size_t bufsize
)
822 ssize_t xfer
= -1; /* XXXgcc */
825 fd
= rump_sys_open(filename
, RUMP_O_WRONLY
, 0);
829 /* write and commit */
830 xfer
= rump_sys_pwrite(fd
, buf
, bufsize
, off
);
846 ukfs_write_fd(struct ukfs
*ukfs
, int fd
, off_t off
, uint8_t *buf
, size_t buflen
,
851 xfer
= rump_sys_pwrite(fd
, buf
, buflen
, off
);
852 if (xfer
> 0 && dosync
)
860 ukfs_close(struct ukfs
*ukfs
, int fd
)
868 ukfs_create(struct ukfs
*ukfs
, const char *filename
, mode_t mode
)
873 fd
= rump_sys_open(filename
, RUMP_O_WRONLY
| RUMP_O_CREAT
, mode
);
883 ukfs_mknod(struct ukfs
*ukfs
, const char *path
, mode_t mode
, dev_t dev
)
886 STDCALL(ukfs
, rump_sys_mknod(path
, mode
, dev
));
890 ukfs_mkfifo(struct ukfs
*ukfs
, const char *path
, mode_t mode
)
893 STDCALL(ukfs
, rump_sys_mkfifo(path
, mode
));
897 ukfs_mkdir(struct ukfs
*ukfs
, const char *filename
, mode_t mode
)
900 STDCALL(ukfs
, rump_sys_mkdir(filename
, mode
));
904 ukfs_remove(struct ukfs
*ukfs
, const char *filename
)
907 STDCALL(ukfs
, rump_sys_unlink(filename
));
911 ukfs_rmdir(struct ukfs
*ukfs
, const char *filename
)
914 STDCALL(ukfs
, rump_sys_rmdir(filename
));
918 ukfs_link(struct ukfs
*ukfs
, const char *filename
, const char *f_create
)
921 STDCALL(ukfs
, rump_sys_link(filename
, f_create
));
925 ukfs_symlink(struct ukfs
*ukfs
, const char *filename
, const char *linkname
)
928 STDCALL(ukfs
, rump_sys_symlink(filename
, linkname
));
932 ukfs_readlink(struct ukfs
*ukfs
, const char *filename
,
933 char *linkbuf
, size_t buflen
)
938 rv
= rump_sys_readlink(filename
, linkbuf
, buflen
);
944 ukfs_rename(struct ukfs
*ukfs
, const char *from
, const char *to
)
947 STDCALL(ukfs
, rump_sys_rename(from
, to
));
951 ukfs_chdir(struct ukfs
*ukfs
, const char *path
)
953 struct vnode
*newvp
, *oldvp
;
957 rv
= rump_sys_chdir(path
);
961 newvp
= rump_pub_cdir_get();
962 pthread_spin_lock(&ukfs
->ukfs_spin
);
963 oldvp
= ukfs
->ukfs_cdir
;
964 ukfs
->ukfs_cdir
= newvp
;
965 pthread_spin_unlock(&ukfs
->ukfs_spin
);
967 rump_pub_vp_rele(oldvp
);
975 * If we want to use post-time_t file systems on pre-time_t hosts,
976 * we must translate the stat structure. Since we don't currently
977 * have a general method for making compat calls in rump, special-case
980 * Note that this does not allow making system calls to older rump
981 * kernels from newer hosts.
983 #define VERS_TIMECHANGE 599000700
991 return __NetBSD_Version__
< VERS_TIMECHANGE
992 && rump_pub_getversion() >= VERS_TIMECHANGE
;
999 ukfs_stat(struct ukfs
*ukfs
, const char *filename
, struct stat
*file_stat
)
1005 rv
= rump_pub_sys___stat30(filename
, file_stat
);
1007 rv
= rump_sys_stat(filename
, file_stat
);
1014 ukfs_lstat(struct ukfs
*ukfs
, const char *filename
, struct stat
*file_stat
)
1020 rv
= rump_pub_sys___lstat30(filename
, file_stat
);
1022 rv
= rump_sys_lstat(filename
, file_stat
);
1029 ukfs_chmod(struct ukfs
*ukfs
, const char *filename
, mode_t mode
)
1032 STDCALL(ukfs
, rump_sys_chmod(filename
, mode
));
1036 ukfs_lchmod(struct ukfs
*ukfs
, const char *filename
, mode_t mode
)
1039 STDCALL(ukfs
, rump_sys_lchmod(filename
, mode
));
1043 ukfs_chown(struct ukfs
*ukfs
, const char *filename
, uid_t uid
, gid_t gid
)
1046 STDCALL(ukfs
, rump_sys_chown(filename
, uid
, gid
));
1050 ukfs_lchown(struct ukfs
*ukfs
, const char *filename
, uid_t uid
, gid_t gid
)
1053 STDCALL(ukfs
, rump_sys_lchown(filename
, uid
, gid
));
1057 ukfs_chflags(struct ukfs
*ukfs
, const char *filename
, u_long flags
)
1060 STDCALL(ukfs
, rump_sys_chflags(filename
, flags
));
1064 ukfs_lchflags(struct ukfs
*ukfs
, const char *filename
, u_long flags
)
1067 STDCALL(ukfs
, rump_sys_lchflags(filename
, flags
));
1071 ukfs_utimes(struct ukfs
*ukfs
, const char *filename
, const struct timeval
*tptr
)
1074 STDCALL(ukfs
, rump_sys_utimes(filename
, tptr
));
1078 ukfs_lutimes(struct ukfs
*ukfs
, const char *filename
,
1079 const struct timeval
*tptr
)
1082 STDCALL(ukfs
, rump_sys_lutimes(filename
, tptr
));
1086 * Dynamic module support
1089 /* load one library */
1092 * XXX: the dlerror stuff isn't really threadsafe, but then again I
1093 * can't protect against other threads calling dl*() outside of ukfs,
1094 * so just live with it being flimsy
1097 ukfs_modload(const char *fname
)
1100 struct modinfo
**mi
;
1103 handle
= dlopen(fname
, RTLD_LAZY
|RTLD_GLOBAL
);
1104 if (handle
== NULL
) {
1105 const char *dlmsg
= dlerror();
1106 if (strstr(dlmsg
, "Undefined symbol"))
1108 warnx("dlopen %s failed: %s\n", fname
, dlmsg
);
1113 mi
= dlsym(handle
, "__start_link_set_modules");
1115 error
= rump_pub_module_init(*mi
, NULL
);
1131 LIST_ENTRY(loadfail
) entries
;
1134 #define RUMPFSMOD_PREFIX "librumpfs_"
1135 #define RUMPFSMOD_SUFFIX ".so"
1138 ukfs_modload_dir(const char *dir
)
1140 char nbuf
[MAXPATHLEN
+1], *p
;
1141 struct dirent entry
, *result
;
1143 struct loadfail
*lf
, *nlf
;
1144 int error
, nloaded
= 0, redo
;
1145 LIST_HEAD(, loadfail
) lfs
;
1147 libdir
= opendir(dir
);
1153 if ((error
= readdir_r(libdir
, &entry
, &result
)) != 0)
1157 if (strncmp(result
->d_name
, RUMPFSMOD_PREFIX
,
1158 strlen(RUMPFSMOD_PREFIX
)) != 0)
1160 if (((p
= strstr(result
->d_name
, RUMPFSMOD_SUFFIX
)) == NULL
)
1161 || strlen(p
) != strlen(RUMPFSMOD_SUFFIX
))
1163 strlcpy(nbuf
, dir
, sizeof(nbuf
));
1164 strlcat(nbuf
, "/", sizeof(nbuf
));
1165 strlcat(nbuf
, result
->d_name
, sizeof(nbuf
));
1166 switch (ukfs_modload(nbuf
)) {
1168 lf
= malloc(sizeof(*lf
));
1173 lf
->pname
= strdup(nbuf
);
1174 if (lf
->pname
== NULL
) {
1179 LIST_INSERT_HEAD(&lfs
, lf
, entries
);
1190 if (error
&& nloaded
!= 0)
1194 * El-cheapo dependency calculator. Just try to load the
1195 * modules n times in a loop
1197 for (redo
= 1; redo
;) {
1199 nlf
= LIST_FIRST(&lfs
);
1200 while ((lf
= nlf
) != NULL
) {
1201 nlf
= LIST_NEXT(lf
, entries
);
1202 if (ukfs_modload(lf
->pname
) == 1) {
1205 LIST_REMOVE(lf
, entries
);
1212 while ((lf
= LIST_FIRST(&lfs
)) != NULL
) {
1213 LIST_REMOVE(lf
, entries
);
1218 if (error
&& nloaded
== 0) {
1226 /* XXX: this code uses definitions from NetBSD, needs rumpdefs */
1228 ukfs_vfstypes(char *buf
, size_t buflen
)
1231 struct sysctlnode q
, ans
[128];
1236 mib
[1] = VFS_GENERIC
;
1240 memset(&q
, 0, sizeof(q
));
1241 q
.sysctl_flags
= SYSCTL_VERSION
;
1243 if (rump_sys___sysctl(mib
, 3, ans
, &alen
, &q
, sizeof(q
)) == -1) {
1247 for (i
= 0; i
< alen
/sizeof(ans
[0]); i
++)
1248 if (strcmp("fstypes", ans
[i
].sysctl_name
) == 0)
1250 if (i
== alen
/sizeof(ans
[0])) {
1256 mib
[1] = VFS_GENERIC
;
1257 mib
[2] = ans
[i
].sysctl_num
;
1259 if (rump_sys___sysctl(mib
, 3, buf
, &buflen
, NULL
, 0) == -1) {
1270 builddirs(const char *pathname
, mode_t mode
,
1271 int (*mkdirfn
)(struct ukfs
*, const char *, mode_t
), struct ukfs
*fs
)
1278 /*ukfs_umask((mask = ukfs_umask(0)));*/
1279 umask((mask
= umask(0)));
1281 f1
= f2
= strdup(pathname
);
1289 /* find next component */
1290 f2
+= strspn(f2
, "/");
1291 f2
+= strcspn(f2
, "/");
1297 rv
= mkdirfn(fs
, f1
, mode
& ~mask
);
1298 if (errno
== EEXIST
)
1301 if (rv
== -1 || *f2
!= '\0' || end
)
1313 ukfs_util_builddirs(struct ukfs
*ukfs
, const char *pathname
, mode_t mode
)
1316 return builddirs(pathname
, mode
, ukfs_mkdir
, ukfs
);