aboutsummaryrefslogtreecommitdiff
path: root/sys/compat
diff options
context:
space:
mode:
authorEd Schouten <ed@FreeBSD.org>2015-07-28 06:36:49 +0000
committerEd Schouten <ed@FreeBSD.org>2015-07-28 06:36:49 +0000
commitcec575201a4c9c10aa39dda868fbed5c64908c17 (patch)
tree68425b29eb6d3e6926ae7e7cc9b083ebd55cdabd /sys/compat
parentf40c76d8dedcc7cf095b00787567a4f1d575280f (diff)
downloadsrc-cec575201a4c9c10aa39dda868fbed5c64908c17.tar.gz
src-cec575201a4c9c10aa39dda868fbed5c64908c17.zip
Make fstat() and friends work.
Summary: CloudABI provides access to two different stat structures: - fdstat, containing file descriptor level status: oflags, file descriptor type and Capsicum rights, used by cap_rights_get(), fcntl(F_GETFL), getsockopt(SO_TYPE). - filestat, containing your regular file status: timestamps, inode number, used by fstat(). Unlike FreeBSD's stat::st_mode, CloudABI file descriptor types don't have overloaded meanings (e.g., returning S_ISCHR() for kqueues). Add a utility function to extract the type of a file descriptor accurately. CloudABI does not work with O_ACCMODEs. File descriptors have two sets of Capsicum-style rights: rights that apply to the file descriptor itself ('base') and rights that apply to any new file descriptors yielded through openat() ('inheriting'). Though not perfect, we can pretty safely decompose Capsicum rights to such a pair. This is done in convert_capabilities(). Test Plan: Tests for these system calls are fairly extensive in cloudlibc. Reviewers: jonathan, mjg, #manpages Reviewed By: mjg Subscribers: imp Differential Revision: https://reviews.freebsd.org/D3171
Notes
Notes: svn path=/head/; revision=285930
Diffstat (limited to 'sys/compat')
-rw-r--r--sys/compat/cloudabi/cloudabi_fd.c256
-rw-r--r--sys/compat/cloudabi/cloudabi_file.c82
-rw-r--r--sys/compat/cloudabi/cloudabi_util.h4
3 files changed, 336 insertions, 6 deletions
diff --git a/sys/compat/cloudabi/cloudabi_fd.c b/sys/compat/cloudabi/cloudabi_fd.c
index 8b72c19cdf6f..23eb78b844d8 100644
--- a/sys/compat/cloudabi/cloudabi_fd.c
+++ b/sys/compat/cloudabi/cloudabi_fd.c
@@ -27,13 +27,64 @@
__FBSDID("$FreeBSD$");
#include <sys/param.h>
+#include <sys/capsicum.h>
#include <sys/filedesc.h>
#include <sys/proc.h>
+#include <sys/socketvar.h>
#include <sys/syscallsubr.h>
#include <sys/sysproto.h>
+#include <sys/systm.h>
#include <sys/unistd.h>
+#include <sys/vnode.h>
#include <compat/cloudabi/cloudabi_proto.h>
+#include <compat/cloudabi/cloudabi_syscalldefs.h>
+#include <compat/cloudabi/cloudabi_util.h>
+
+/* Translation between CloudABI and Capsicum rights. */
+#define RIGHTS_MAPPINGS \
+ MAPPING(CLOUDABI_RIGHT_FD_DATASYNC, CAP_FSYNC) \
+ MAPPING(CLOUDABI_RIGHT_FD_READ, CAP_READ) \
+ MAPPING(CLOUDABI_RIGHT_FD_SEEK, CAP_SEEK) \
+ MAPPING(CLOUDABI_RIGHT_FD_STAT_PUT_FLAGS, CAP_FCNTL) \
+ MAPPING(CLOUDABI_RIGHT_FD_SYNC, CAP_FSYNC) \
+ MAPPING(CLOUDABI_RIGHT_FD_TELL, CAP_SEEK_TELL) \
+ MAPPING(CLOUDABI_RIGHT_FD_WRITE, CAP_WRITE) \
+ MAPPING(CLOUDABI_RIGHT_FILE_ADVISE) \
+ MAPPING(CLOUDABI_RIGHT_FILE_ALLOCATE, CAP_WRITE) \
+ MAPPING(CLOUDABI_RIGHT_FILE_CREATE_DIRECTORY, CAP_MKDIRAT) \
+ MAPPING(CLOUDABI_RIGHT_FILE_CREATE_FILE, CAP_CREATE) \
+ MAPPING(CLOUDABI_RIGHT_FILE_CREATE_FIFO, CAP_MKFIFOAT) \
+ MAPPING(CLOUDABI_RIGHT_FILE_LINK_SOURCE, CAP_LOOKUP) \
+ MAPPING(CLOUDABI_RIGHT_FILE_LINK_TARGET, CAP_LINKAT) \
+ MAPPING(CLOUDABI_RIGHT_FILE_OPEN, CAP_LOOKUP) \
+ MAPPING(CLOUDABI_RIGHT_FILE_READDIR, CAP_READ) \
+ MAPPING(CLOUDABI_RIGHT_FILE_READLINK, CAP_LOOKUP) \
+ MAPPING(CLOUDABI_RIGHT_FILE_RENAME_SOURCE, CAP_RENAMEAT) \
+ MAPPING(CLOUDABI_RIGHT_FILE_RENAME_TARGET, CAP_LINKAT) \
+ MAPPING(CLOUDABI_RIGHT_FILE_STAT_FGET, CAP_FSTAT) \
+ MAPPING(CLOUDABI_RIGHT_FILE_STAT_FPUT_SIZE, CAP_FTRUNCATE) \
+ MAPPING(CLOUDABI_RIGHT_FILE_STAT_FPUT_TIMES, CAP_FUTIMES) \
+ MAPPING(CLOUDABI_RIGHT_FILE_STAT_GET, CAP_FSTATAT) \
+ MAPPING(CLOUDABI_RIGHT_FILE_STAT_PUT_TIMES, CAP_FUTIMESAT) \
+ MAPPING(CLOUDABI_RIGHT_FILE_SYMLINK, CAP_SYMLINKAT) \
+ MAPPING(CLOUDABI_RIGHT_FILE_UNLINK, CAP_UNLINKAT) \
+ MAPPING(CLOUDABI_RIGHT_MEM_MAP, CAP_MMAP) \
+ MAPPING(CLOUDABI_RIGHT_MEM_MAP_EXEC, CAP_MMAP_X) \
+ MAPPING(CLOUDABI_RIGHT_POLL_FD_READWRITE, CAP_EVENT) \
+ MAPPING(CLOUDABI_RIGHT_POLL_MODIFY, CAP_KQUEUE_CHANGE) \
+ MAPPING(CLOUDABI_RIGHT_POLL_PROC_TERMINATE, CAP_PDWAIT) \
+ MAPPING(CLOUDABI_RIGHT_POLL_WAIT, CAP_KQUEUE_EVENT) \
+ MAPPING(CLOUDABI_RIGHT_PROC_EXEC, CAP_FEXECVE) \
+ MAPPING(CLOUDABI_RIGHT_SOCK_ACCEPT, CAP_ACCEPT) \
+ MAPPING(CLOUDABI_RIGHT_SOCK_BIND_DIRECTORY, CAP_BINDAT) \
+ MAPPING(CLOUDABI_RIGHT_SOCK_BIND_SOCKET, CAP_BIND) \
+ MAPPING(CLOUDABI_RIGHT_SOCK_CONNECT_DIRECTORY, CAP_CONNECTAT) \
+ MAPPING(CLOUDABI_RIGHT_SOCK_CONNECT_SOCKET, CAP_CONNECT) \
+ MAPPING(CLOUDABI_RIGHT_SOCK_LISTEN, CAP_LISTEN) \
+ MAPPING(CLOUDABI_RIGHT_SOCK_SHUTDOWN, CAP_SHUTDOWN) \
+ MAPPING(CLOUDABI_RIGHT_SOCK_STAT_GET, CAP_GETPEERNAME, \
+ CAP_GETSOCKNAME, CAP_GETSOCKOPT)
int
cloudabi_sys_fd_close(struct thread *td, struct cloudabi_sys_fd_close_args *uap)
@@ -160,13 +211,214 @@ cloudabi_sys_fd_seek(struct thread *td, struct cloudabi_sys_fd_seek_args *uap)
return (sys_lseek(td, &lseek_args));
}
+/* Converts a file descriptor to a CloudABI file descriptor type. */
+cloudabi_filetype_t
+cloudabi_convert_filetype(const struct file *fp)
+{
+ struct socket *so;
+ struct vnode *vp;
+
+ switch (fp->f_type) {
+ case DTYPE_FIFO:
+ return (CLOUDABI_FILETYPE_FIFO);
+ case DTYPE_KQUEUE:
+ return (CLOUDABI_FILETYPE_POLL);
+ case DTYPE_PIPE:
+ return (CLOUDABI_FILETYPE_FIFO);
+ case DTYPE_PROCDESC:
+ return (CLOUDABI_FILETYPE_PROCESS);
+ case DTYPE_SHM:
+ return (CLOUDABI_FILETYPE_SHARED_MEMORY);
+ case DTYPE_SOCKET:
+ so = fp->f_data;
+ switch (so->so_type) {
+ case SOCK_DGRAM:
+ return (CLOUDABI_FILETYPE_SOCKET_DGRAM);
+ case SOCK_SEQPACKET:
+ return (CLOUDABI_FILETYPE_SOCKET_SEQPACKET);
+ case SOCK_STREAM:
+ return (CLOUDABI_FILETYPE_SOCKET_STREAM);
+ default:
+ return (CLOUDABI_FILETYPE_UNKNOWN);
+ }
+ case DTYPE_VNODE:
+ vp = fp->f_vnode;
+ switch (vp->v_type) {
+ case VBLK:
+ return (CLOUDABI_FILETYPE_BLOCK_DEVICE);
+ case VCHR:
+ return (CLOUDABI_FILETYPE_CHARACTER_DEVICE);
+ case VDIR:
+ return (CLOUDABI_FILETYPE_DIRECTORY);
+ case VFIFO:
+ return (CLOUDABI_FILETYPE_FIFO);
+ case VLNK:
+ return (CLOUDABI_FILETYPE_SYMBOLIC_LINK);
+ case VREG:
+ return (CLOUDABI_FILETYPE_REGULAR_FILE);
+ case VSOCK:
+ return (CLOUDABI_FILETYPE_SOCKET_STREAM);
+ default:
+ return (CLOUDABI_FILETYPE_UNKNOWN);
+ }
+ default:
+ return (CLOUDABI_FILETYPE_UNKNOWN);
+ }
+}
+
+/*
+ * Converts FreeBSD's Capsicum rights to CloudABI's set of rights.
+ */
+static void
+convert_capabilities(const cap_rights_t *capabilities,
+ cloudabi_filetype_t filetype, cloudabi_rights_t *base,
+ cloudabi_rights_t *inheriting)
+{
+ cloudabi_rights_t rights;
+
+ /* Convert FreeBSD bits to CloudABI bits. */
+ rights = 0;
+#define MAPPING(cloudabi, ...) do { \
+ if (cap_rights_is_set(capabilities, ##__VA_ARGS__)) \
+ rights |= (cloudabi); \
+} while (0);
+ RIGHTS_MAPPINGS
+#undef MAPPING
+
+ /*
+ * CloudABI has a small number of additional rights bits to
+ * disambiguate between multiple purposes. Remove the bits that
+ * don't apply to the type of the file descriptor.
+ *
+ * As file descriptor access modes (O_ACCMODE) has been fully
+ * replaced by rights bits, CloudABI distinguishes between
+ * rights that apply to the file descriptor itself (base) versus
+ * rights of new file descriptors derived from them
+ * (inheriting). The code below approximates the pair by
+ * decomposing depending on the file descriptor type.
+ *
+ * We need to be somewhat accurate about which actions can
+ * actually be performed on the file descriptor, as functions
+ * like fcntl(fd, F_GETFL) are emulated on top of this.
+ */
+ switch (filetype) {
+ case CLOUDABI_FILETYPE_DIRECTORY:
+ *base = rights & (CLOUDABI_RIGHT_FD_STAT_PUT_FLAGS |
+ CLOUDABI_RIGHT_FD_SYNC | CLOUDABI_RIGHT_FILE_ADVISE |
+ CLOUDABI_RIGHT_FILE_CREATE_DIRECTORY |
+ CLOUDABI_RIGHT_FILE_CREATE_FILE |
+ CLOUDABI_RIGHT_FILE_CREATE_FIFO |
+ CLOUDABI_RIGHT_FILE_LINK_SOURCE |
+ CLOUDABI_RIGHT_FILE_LINK_TARGET |
+ CLOUDABI_RIGHT_FILE_OPEN |
+ CLOUDABI_RIGHT_FILE_READDIR |
+ CLOUDABI_RIGHT_FILE_READLINK |
+ CLOUDABI_RIGHT_FILE_RENAME_SOURCE |
+ CLOUDABI_RIGHT_FILE_RENAME_TARGET |
+ CLOUDABI_RIGHT_FILE_STAT_FGET |
+ CLOUDABI_RIGHT_FILE_STAT_FPUT_TIMES |
+ CLOUDABI_RIGHT_FILE_STAT_GET |
+ CLOUDABI_RIGHT_FILE_STAT_PUT_TIMES |
+ CLOUDABI_RIGHT_FILE_SYMLINK |
+ CLOUDABI_RIGHT_FILE_UNLINK |
+ CLOUDABI_RIGHT_POLL_FD_READWRITE |
+ CLOUDABI_RIGHT_SOCK_BIND_DIRECTORY |
+ CLOUDABI_RIGHT_SOCK_CONNECT_DIRECTORY);
+ *inheriting = rights;
+ break;
+ case CLOUDABI_FILETYPE_FIFO:
+ *base = rights & ~(CLOUDABI_RIGHT_FILE_ADVISE |
+ CLOUDABI_RIGHT_FILE_ALLOCATE |
+ CLOUDABI_RIGHT_FILE_READDIR);
+ *inheriting = 0;
+ break;
+ case CLOUDABI_FILETYPE_POLL:
+ *base = rights & ~CLOUDABI_RIGHT_FILE_ADVISE;
+ *inheriting = 0;
+ break;
+ case CLOUDABI_FILETYPE_PROCESS:
+ *base = rights & ~CLOUDABI_RIGHT_FILE_ADVISE;
+ *inheriting = 0;
+ break;
+ case CLOUDABI_FILETYPE_REGULAR_FILE:
+ *base = rights & ~CLOUDABI_RIGHT_FILE_READDIR;
+ *inheriting = 0;
+ break;
+ case CLOUDABI_FILETYPE_SHARED_MEMORY:
+ *base = rights & ~(CLOUDABI_RIGHT_FD_SEEK |
+ CLOUDABI_RIGHT_FD_TELL |
+ CLOUDABI_RIGHT_FILE_ADVISE |
+ CLOUDABI_RIGHT_FILE_ALLOCATE |
+ CLOUDABI_RIGHT_FILE_READDIR);
+ *inheriting = 0;
+ break;
+ case CLOUDABI_FILETYPE_SOCKET_DGRAM:
+ case CLOUDABI_FILETYPE_SOCKET_SEQPACKET:
+ case CLOUDABI_FILETYPE_SOCKET_STREAM:
+ *base = rights & (CLOUDABI_RIGHT_FD_READ |
+ CLOUDABI_RIGHT_FD_STAT_PUT_FLAGS |
+ CLOUDABI_RIGHT_FD_WRITE |
+ CLOUDABI_RIGHT_FILE_STAT_FGET |
+ CLOUDABI_RIGHT_POLL_FD_READWRITE |
+ CLOUDABI_RIGHT_SOCK_ACCEPT |
+ CLOUDABI_RIGHT_SOCK_BIND_SOCKET |
+ CLOUDABI_RIGHT_SOCK_CONNECT_SOCKET |
+ CLOUDABI_RIGHT_SOCK_LISTEN |
+ CLOUDABI_RIGHT_SOCK_SHUTDOWN |
+ CLOUDABI_RIGHT_SOCK_STAT_GET);
+ *inheriting = rights;
+ break;
+ default:
+ *base = rights;
+ *inheriting = 0;
+ break;
+ }
+}
+
int
cloudabi_sys_fd_stat_get(struct thread *td,
struct cloudabi_sys_fd_stat_get_args *uap)
{
+ cloudabi_fdstat_t fsb = {};
+ struct filedesc *fdp;
+ struct file *fp;
+ seq_t seq;
+ cap_rights_t rights;
+ int error, oflags;
+ bool modified;
- /* Not implemented. */
- return (ENOSYS);
+ /* Obtain file descriptor properties. */
+ fdp = td->td_proc->p_fd;
+ do {
+ error = fget_unlocked(fdp, uap->fd, cap_rights_init(&rights),
+ &fp, &seq);
+ if (error != 0)
+ return (error);
+ if (fp->f_ops == &badfileops) {
+ fdrop(fp, td);
+ return (EBADF);
+ }
+
+ rights = *cap_rights(fdp, uap->fd);
+ oflags = OFLAGS(fp->f_flag);
+ fsb.fs_filetype = cloudabi_convert_filetype(fp);
+
+ modified = fd_modified(fdp, uap->fd, seq);
+ fdrop(fp, td);
+ } while (modified);
+
+ /* Convert file descriptor flags. */
+ if (oflags & O_APPEND)
+ fsb.fs_flags |= CLOUDABI_FDFLAG_APPEND;
+ if (oflags & O_NONBLOCK)
+ fsb.fs_flags |= CLOUDABI_FDFLAG_NONBLOCK;
+ if (oflags & O_SYNC)
+ fsb.fs_flags |= CLOUDABI_FDFLAG_SYNC;
+
+ /* Convert capabilities to CloudABI rights. */
+ convert_capabilities(&rights, fsb.fs_filetype,
+ &fsb.fs_rights_base, &fsb.fs_rights_inheriting);
+ return (copyout(&fsb, (void *)uap->buf, sizeof(fsb)));
}
int
diff --git a/sys/compat/cloudabi/cloudabi_file.c b/sys/compat/cloudabi/cloudabi_file.c
index b5085173811a..3f917a0d84d8 100644
--- a/sys/compat/cloudabi/cloudabi_file.c
+++ b/sys/compat/cloudabi/cloudabi_file.c
@@ -27,14 +27,18 @@
__FBSDID("$FreeBSD$");
#include <sys/param.h>
+#include <sys/capsicum.h>
#include <sys/fcntl.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/namei.h>
+#include <sys/proc.h>
+#include <sys/stat.h>
#include <sys/syscallsubr.h>
#include <compat/cloudabi/cloudabi_proto.h>
#include <compat/cloudabi/cloudabi_syscalldefs.h>
+#include <compat/cloudabi/cloudabi_util.h>
static MALLOC_DEFINE(M_CLOUDABI_PATH, "cloudabipath", "CloudABI pathnames");
@@ -220,13 +224,50 @@ cloudabi_sys_file_rename(struct thread *td,
return (error);
}
+/* Converts a FreeBSD stat structure to a CloudABI stat structure. */
+static void
+convert_stat(const struct stat *sb, cloudabi_filestat_t *csb)
+{
+ cloudabi_filestat_t res = {
+ .st_dev = sb->st_dev,
+ .st_ino = sb->st_ino,
+ .st_nlink = sb->st_nlink,
+ .st_size = sb->st_size,
+ };
+
+ cloudabi_convert_timespec(&sb->st_atim, &res.st_atim);
+ cloudabi_convert_timespec(&sb->st_mtim, &res.st_mtim);
+ cloudabi_convert_timespec(&sb->st_ctim, &res.st_ctim);
+ *csb = res;
+}
+
int
cloudabi_sys_file_stat_fget(struct thread *td,
struct cloudabi_sys_file_stat_fget_args *uap)
{
+ struct stat sb;
+ cloudabi_filestat_t csb;
+ struct file *fp;
+ cap_rights_t rights;
+ cloudabi_filetype_t filetype;
+ int error;
- /* Not implemented. */
- return (ENOSYS);
+ /* Fetch file descriptor attributes. */
+ error = fget(td, uap->fd, cap_rights_init(&rights, CAP_FSTAT), &fp);
+ if (error != 0)
+ return (error);
+ error = fo_stat(fp, &sb, td->td_ucred, td);
+ if (error != 0) {
+ fdrop(fp, td);
+ return (error);
+ }
+ filetype = cloudabi_convert_filetype(fp);
+ fdrop(fp, td);
+
+ /* Convert attributes to CloudABI's format. */
+ convert_stat(&sb, &csb);
+ csb.st_filetype = filetype;
+ return (copyout(&csb, uap->buf, sizeof(csb)));
}
int
@@ -242,9 +283,42 @@ int
cloudabi_sys_file_stat_get(struct thread *td,
struct cloudabi_sys_file_stat_get_args *uap)
{
+ struct stat sb;
+ cloudabi_filestat_t csb;
+ char *path;
+ int error;
- /* Not implemented. */
- return (ENOSYS);
+ error = copyin_path(uap->path, uap->pathlen, &path);
+ if (error != 0)
+ return (error);
+
+ error = kern_statat(td,
+ (uap->fd & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0 ? 0 :
+ AT_SYMLINK_NOFOLLOW, uap->fd, path, UIO_SYSSPACE, &sb, NULL);
+ cloudabi_freestr(path);
+ if (error != 0)
+ return (error);
+
+ /* Convert results and return them. */
+ convert_stat(&sb, &csb);
+ if (S_ISBLK(sb.st_mode))
+ csb.st_filetype = CLOUDABI_FILETYPE_BLOCK_DEVICE;
+ else if (S_ISCHR(sb.st_mode))
+ csb.st_filetype = CLOUDABI_FILETYPE_CHARACTER_DEVICE;
+ else if (S_ISDIR(sb.st_mode))
+ csb.st_filetype = CLOUDABI_FILETYPE_DIRECTORY;
+ else if (S_ISFIFO(sb.st_mode))
+ csb.st_filetype = CLOUDABI_FILETYPE_FIFO;
+ else if (S_ISREG(sb.st_mode))
+ csb.st_filetype = CLOUDABI_FILETYPE_REGULAR_FILE;
+ else if (S_ISSOCK(sb.st_mode)) {
+ /* Inaccurate, but the best that we can do. */
+ csb.st_filetype = CLOUDABI_FILETYPE_SOCKET_STREAM;
+ } else if (S_ISLNK(sb.st_mode))
+ csb.st_filetype = CLOUDABI_FILETYPE_SYMBOLIC_LINK;
+ else
+ csb.st_filetype = CLOUDABI_FILETYPE_UNKNOWN;
+ return (copyout(&csb, uap->buf, sizeof(csb)));
}
int
diff --git a/sys/compat/cloudabi/cloudabi_util.h b/sys/compat/cloudabi/cloudabi_util.h
index 5350d24c082c..557cf1759037 100644
--- a/sys/compat/cloudabi/cloudabi_util.h
+++ b/sys/compat/cloudabi/cloudabi_util.h
@@ -30,6 +30,7 @@
#include <compat/cloudabi/cloudabi_syscalldefs.h>
+struct file;
struct thread;
struct timespec;
@@ -40,6 +41,9 @@ int cloudabi_clock_time_get(struct thread *, cloudabi_clockid_t,
/* Converts a FreeBSD errno to a CloudABI errno. */
cloudabi_errno_t cloudabi_convert_errno(int);
+/* Converts a file descriptor to a CloudABI file descriptor type. */
+cloudabi_filetype_t cloudabi_convert_filetype(const struct file *);
+
/* Converts a struct timespec to a CloudABI timestamp. */
int cloudabi_convert_timespec(const struct timespec *, cloudabi_timestamp_t *);