Implement the basic system calls that operate on pathnames.
Summary: Unlike FreeBSD, CloudABI does not use null terminated strings for its pathnames. Introduce a function called copyin_path() that can be used by all of the filesystem system calls that use pathnames. This change already implements the system calls that don't depend on any additional functionality (e.g., conversion of struct stat). Also implement the socket system calls that operate on pathnames, namely the ones used by the C library functions bindat() and connectat(). These don't receive a 'struct sockaddr_un', but just the pathname, meaning they could be implemented in such a way that they don't depend on the size of sun_path. For now, just use the existing interfaces. Add a missing #include to cloudabi_syscalldefs.h to get this code to build, as one of its macros depends on UINT64_C(). Test Plan: These implementations have already been tested in the CloudABI branch on GitHub. They pass all of the tests. Reviewers: kib, pjd Subscribers: imp Differential Revision: https://reviews.freebsd.org/D3097
This commit is contained in:
parent
d2e3ed5af6
commit
4615998165
@ -28,11 +28,67 @@ __FBSDID("$FreeBSD$");
|
|||||||
|
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/fcntl.h>
|
#include <sys/fcntl.h>
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
#include <sys/malloc.h>
|
||||||
|
#include <sys/namei.h>
|
||||||
#include <sys/syscallsubr.h>
|
#include <sys/syscallsubr.h>
|
||||||
|
|
||||||
#include <compat/cloudabi/cloudabi_proto.h>
|
#include <compat/cloudabi/cloudabi_proto.h>
|
||||||
#include <compat/cloudabi/cloudabi_syscalldefs.h>
|
#include <compat/cloudabi/cloudabi_syscalldefs.h>
|
||||||
|
|
||||||
|
static MALLOC_DEFINE(M_CLOUDABI_PATH, "cloudabipath", "CloudABI pathnames");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copying pathnames from userspace to kernelspace.
|
||||||
|
*
|
||||||
|
* Unlike most operating systems, CloudABI doesn't use null-terminated
|
||||||
|
* pathname strings. Processes always pass pathnames to the kernel by
|
||||||
|
* providing a base pointer and a length. This has a couple of reasons:
|
||||||
|
*
|
||||||
|
* - It makes it easier to use CloudABI in combination with programming
|
||||||
|
* languages other than C, that may use non-null terminated strings.
|
||||||
|
* - It allows for calling system calls on individual components of the
|
||||||
|
* pathname without modifying the input string.
|
||||||
|
*
|
||||||
|
* The function below copies in pathname strings and null-terminates it.
|
||||||
|
* It also ensure that the string itself does not contain any null
|
||||||
|
* bytes.
|
||||||
|
*
|
||||||
|
* TODO(ed): Add an abstraction to vfs_lookup.c that allows us to pass
|
||||||
|
* in unterminated pathname strings, so we can do away with
|
||||||
|
* the copying.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int
|
||||||
|
copyin_path(const char *uaddr, size_t len, char **result)
|
||||||
|
{
|
||||||
|
char *buf;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
if (len >= PATH_MAX)
|
||||||
|
return (ENAMETOOLONG);
|
||||||
|
buf = malloc(len + 1, M_CLOUDABI_PATH, M_WAITOK);
|
||||||
|
error = copyin(uaddr, buf, len);
|
||||||
|
if (error != 0) {
|
||||||
|
free(buf, M_CLOUDABI_PATH);
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
if (memchr(buf, '\0', len) != NULL) {
|
||||||
|
free(buf, M_CLOUDABI_PATH);
|
||||||
|
return (EINVAL);
|
||||||
|
}
|
||||||
|
buf[len] = '\0';
|
||||||
|
*result = buf;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cloudabi_freestr(char *buf)
|
||||||
|
{
|
||||||
|
|
||||||
|
free(buf, M_CLOUDABI_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
cloudabi_sys_file_advise(struct thread *td,
|
cloudabi_sys_file_advise(struct thread *td,
|
||||||
struct cloudabi_sys_file_advise_args *uap)
|
struct cloudabi_sys_file_advise_args *uap)
|
||||||
@ -86,9 +142,24 @@ int
|
|||||||
cloudabi_sys_file_link(struct thread *td,
|
cloudabi_sys_file_link(struct thread *td,
|
||||||
struct cloudabi_sys_file_link_args *uap)
|
struct cloudabi_sys_file_link_args *uap)
|
||||||
{
|
{
|
||||||
|
char *path1, *path2;
|
||||||
|
int error;
|
||||||
|
|
||||||
/* Not implemented. */
|
error = copyin_path(uap->path1, uap->path1len, &path1);
|
||||||
return (ENOSYS);
|
if (error != 0)
|
||||||
|
return (error);
|
||||||
|
error = copyin_path(uap->path2, uap->path2len, &path2);
|
||||||
|
if (error != 0) {
|
||||||
|
cloudabi_freestr(path1);
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
error = kern_linkat(td, uap->fd1, uap->fd2, path1, path2,
|
||||||
|
UIO_SYSSPACE, (uap->fd1 & CLOUDABI_LOOKUP_SYMLINK_FOLLOW) != 0 ?
|
||||||
|
FOLLOW : NOFOLLOW);
|
||||||
|
cloudabi_freestr(path1);
|
||||||
|
cloudabi_freestr(path2);
|
||||||
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -113,18 +184,40 @@ int
|
|||||||
cloudabi_sys_file_readlink(struct thread *td,
|
cloudabi_sys_file_readlink(struct thread *td,
|
||||||
struct cloudabi_sys_file_readlink_args *uap)
|
struct cloudabi_sys_file_readlink_args *uap)
|
||||||
{
|
{
|
||||||
|
char *path;
|
||||||
|
int error;
|
||||||
|
|
||||||
/* Not implemented. */
|
error = copyin_path(uap->path, uap->pathlen, &path);
|
||||||
return (ENOSYS);
|
if (error != 0)
|
||||||
|
return (error);
|
||||||
|
|
||||||
|
error = kern_readlinkat(td, uap->fd, path, UIO_SYSSPACE,
|
||||||
|
uap->buf, UIO_USERSPACE, uap->bufsize);
|
||||||
|
cloudabi_freestr(path);
|
||||||
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
cloudabi_sys_file_rename(struct thread *td,
|
cloudabi_sys_file_rename(struct thread *td,
|
||||||
struct cloudabi_sys_file_rename_args *uap)
|
struct cloudabi_sys_file_rename_args *uap)
|
||||||
{
|
{
|
||||||
|
char *old, *new;
|
||||||
|
int error;
|
||||||
|
|
||||||
/* Not implemented. */
|
error = copyin_path(uap->old, uap->oldlen, &old);
|
||||||
return (ENOSYS);
|
if (error != 0)
|
||||||
|
return (error);
|
||||||
|
error = copyin_path(uap->new, uap->newlen, &new);
|
||||||
|
if (error != 0) {
|
||||||
|
cloudabi_freestr(old);
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
error = kern_renameat(td, uap->oldfd, old, uap->newfd, new,
|
||||||
|
UIO_SYSSPACE);
|
||||||
|
cloudabi_freestr(old);
|
||||||
|
cloudabi_freestr(new);
|
||||||
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -167,16 +260,39 @@ int
|
|||||||
cloudabi_sys_file_symlink(struct thread *td,
|
cloudabi_sys_file_symlink(struct thread *td,
|
||||||
struct cloudabi_sys_file_symlink_args *uap)
|
struct cloudabi_sys_file_symlink_args *uap)
|
||||||
{
|
{
|
||||||
|
char *path1, *path2;
|
||||||
|
int error;
|
||||||
|
|
||||||
/* Not implemented. */
|
error = copyin_path(uap->path1, uap->path1len, &path1);
|
||||||
return (ENOSYS);
|
if (error != 0)
|
||||||
|
return (error);
|
||||||
|
error = copyin_path(uap->path2, uap->path2len, &path2);
|
||||||
|
if (error != 0) {
|
||||||
|
cloudabi_freestr(path1);
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
|
error = kern_symlinkat(td, path1, uap->fd, path2, UIO_SYSSPACE);
|
||||||
|
cloudabi_freestr(path1);
|
||||||
|
cloudabi_freestr(path2);
|
||||||
|
return (error);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
cloudabi_sys_file_unlink(struct thread *td,
|
cloudabi_sys_file_unlink(struct thread *td,
|
||||||
struct cloudabi_sys_file_unlink_args *uap)
|
struct cloudabi_sys_file_unlink_args *uap)
|
||||||
{
|
{
|
||||||
|
char *path;
|
||||||
|
int error;
|
||||||
|
|
||||||
/* Not implemented. */
|
error = copyin_path(uap->path, uap->pathlen, &path);
|
||||||
return (ENOSYS);
|
if (error != 0)
|
||||||
|
return (error);
|
||||||
|
|
||||||
|
if (uap->flag & CLOUDABI_UNLINK_REMOVEDIR)
|
||||||
|
error = kern_rmdirat(td, uap->fd, path, UIO_SYSSPACE);
|
||||||
|
else
|
||||||
|
error = kern_unlinkat(td, uap->fd, path, UIO_SYSSPACE, 0);
|
||||||
|
cloudabi_freestr(path);
|
||||||
|
return (error);
|
||||||
}
|
}
|
||||||
|
@ -26,12 +26,38 @@
|
|||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__FBSDID("$FreeBSD$");
|
__FBSDID("$FreeBSD$");
|
||||||
|
|
||||||
|
#include <sys/param.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
#include <sys/syscallsubr.h>
|
||||||
#include <sys/sysproto.h>
|
#include <sys/sysproto.h>
|
||||||
|
#include <sys/systm.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
|
||||||
#include <compat/cloudabi/cloudabi_proto.h>
|
#include <compat/cloudabi/cloudabi_proto.h>
|
||||||
#include <compat/cloudabi/cloudabi_syscalldefs.h>
|
#include <compat/cloudabi/cloudabi_syscalldefs.h>
|
||||||
|
|
||||||
|
/* Copies a pathname into a UNIX socket address structure. */
|
||||||
|
static int
|
||||||
|
copyin_sockaddr_un(const char *path, size_t pathlen, struct sockaddr_un *sun)
|
||||||
|
{
|
||||||
|
int error;
|
||||||
|
|
||||||
|
/* Copy in pathname string if there's enough space. */
|
||||||
|
if (pathlen >= sizeof(sun->sun_path))
|
||||||
|
return (ENAMETOOLONG);
|
||||||
|
error = copyin(path, &sun->sun_path, pathlen);
|
||||||
|
if (error != 0)
|
||||||
|
return (error);
|
||||||
|
if (memchr(sun->sun_path, '\0', pathlen) != NULL)
|
||||||
|
return (EINVAL);
|
||||||
|
|
||||||
|
/* Initialize the rest of the socket address. */
|
||||||
|
sun->sun_path[pathlen] = '\0';
|
||||||
|
sun->sun_family = AF_UNIX;
|
||||||
|
sun->sun_len = sizeof(*sun);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
cloudabi_sys_sock_accept(struct thread *td,
|
cloudabi_sys_sock_accept(struct thread *td,
|
||||||
struct cloudabi_sys_sock_accept_args *uap)
|
struct cloudabi_sys_sock_accept_args *uap)
|
||||||
@ -45,18 +71,26 @@ int
|
|||||||
cloudabi_sys_sock_bind(struct thread *td,
|
cloudabi_sys_sock_bind(struct thread *td,
|
||||||
struct cloudabi_sys_sock_bind_args *uap)
|
struct cloudabi_sys_sock_bind_args *uap)
|
||||||
{
|
{
|
||||||
|
struct sockaddr_un sun;
|
||||||
|
int error;
|
||||||
|
|
||||||
/* Not implemented. */
|
error = copyin_sockaddr_un(uap->path, uap->pathlen, &sun);
|
||||||
return (ENOSYS);
|
if (error != 0)
|
||||||
|
return (error);
|
||||||
|
return (kern_bindat(td, uap->fd, uap->s, (struct sockaddr *)&sun));
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
cloudabi_sys_sock_connect(struct thread *td,
|
cloudabi_sys_sock_connect(struct thread *td,
|
||||||
struct cloudabi_sys_sock_connect_args *uap)
|
struct cloudabi_sys_sock_connect_args *uap)
|
||||||
{
|
{
|
||||||
|
struct sockaddr_un sun;
|
||||||
|
int error;
|
||||||
|
|
||||||
/* Not implemented. */
|
error = copyin_sockaddr_un(uap->path, uap->pathlen, &sun);
|
||||||
return (ENOSYS);
|
if (error != 0)
|
||||||
|
return (error);
|
||||||
|
return (kern_connectat(td, uap->fd, uap->s, (struct sockaddr *)&sun));
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#define _CLOUDABI_SYSCALLDEFS_H_
|
#define _CLOUDABI_SYSCALLDEFS_H_
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <sys/stdint.h>
|
||||||
|
|
||||||
#define alignas _Alignas
|
#define alignas _Alignas
|
||||||
#define alignof _Alignof
|
#define alignof _Alignof
|
||||||
|
Loading…
Reference in New Issue
Block a user