Implement the linux syscalls
openat, mkdirat, mknodat, fchownat, futimesat, fstatat, unlinkat, renameat, linkat, symlinkat, readlinkat, fchmodat, faccessat. Submitted by: rdivacky Sponsored by: Google Summer of Code 2007 Tested by: pho
This commit is contained in:
parent
1cf165afe7
commit
48b05c3f82
@ -579,8 +579,6 @@ int linux_ioctl_unregister_handler(struct linux_ioctl_handler *h);
|
||||
#define LINUX_F_WRLCK 1
|
||||
#define LINUX_F_UNLCK 2
|
||||
|
||||
#define LINUX_AT_FDCWD -100
|
||||
|
||||
/*
|
||||
* mount flags
|
||||
*/
|
||||
|
@ -96,18 +96,6 @@ DUMMY(inotify_init);
|
||||
DUMMY(inotify_add_watch);
|
||||
DUMMY(inotify_rm_watch);
|
||||
DUMMY(migrate_pages);
|
||||
DUMMY(mkdirat);
|
||||
DUMMY(mknodat);
|
||||
DUMMY(fchownat);
|
||||
DUMMY(futimesat);
|
||||
DUMMY(fstatat64);
|
||||
DUMMY(unlinkat);
|
||||
DUMMY(renameat);
|
||||
DUMMY(linkat);
|
||||
DUMMY(symlinkat);
|
||||
DUMMY(readlinkat);
|
||||
DUMMY(fchmodat);
|
||||
DUMMY(faccessat);
|
||||
DUMMY(pselect6);
|
||||
DUMMY(ppoll);
|
||||
DUMMY(unshare);
|
||||
|
@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/exec.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/imgact.h>
|
||||
#include <sys/imgact_elf.h>
|
||||
#include <sys/kernel.h>
|
||||
@ -788,7 +789,7 @@ exec_linux_imgact_try(struct image_params *imgp)
|
||||
*/
|
||||
if ((error = exec_shell_imgact(imgp)) == 0) {
|
||||
linux_emul_convpath(FIRST_THREAD_IN_PROC(imgp->proc),
|
||||
imgp->interpreter_name, UIO_SYSSPACE, &rpath, 0);
|
||||
imgp->interpreter_name, UIO_SYSSPACE, &rpath, 0, AT_FDCWD);
|
||||
if (rpath != NULL) {
|
||||
len = strlen(rpath) + 1;
|
||||
|
||||
|
@ -465,20 +465,31 @@
|
||||
292 AUE_NULL STD { int linux_inotify_add_watch(void); }
|
||||
293 AUE_NULL STD { int linux_inotify_rm_watch(void); }
|
||||
294 AUE_NULL STD { int linux_migrate_pages(void); }
|
||||
295 AUE_OPEN_RWTC STD { int linux_openat(l_int dfd, char *filename, \
|
||||
295 AUE_OPEN_RWTC STD { int linux_openat(l_int dfd, const char *filename, \
|
||||
l_int flags, l_int mode); }
|
||||
296 AUE_NULL STD { int linux_mkdirat(void); }
|
||||
297 AUE_NULL STD { int linux_mknodat(void); }
|
||||
298 AUE_NULL STD { int linux_fchownat(void); }
|
||||
299 AUE_NULL STD { int linux_futimesat(void); }
|
||||
300 AUE_NULL STD { int linux_fstatat64(void); }
|
||||
301 AUE_NULL STD { int linux_unlinkat(void); }
|
||||
302 AUE_NULL STD { int linux_renameat(void); }
|
||||
303 AUE_NULL STD { int linux_linkat(void); }
|
||||
304 AUE_NULL STD { int linux_symlinkat(void); }
|
||||
305 AUE_NULL STD { int linux_readlinkat(void); }
|
||||
306 AUE_NULL STD { int linux_fchmodat(void); }
|
||||
307 AUE_NULL STD { int linux_faccessat(void); }
|
||||
296 AUE_MKDIRAT STD { int linux_mkdirat(l_int dfd, const char *pathname, \
|
||||
l_int mode); }
|
||||
297 AUE_MKNODAT STD { int linux_mknodat(l_int dfd, const char *filename, \
|
||||
l_int mode, l_uint dev); }
|
||||
298 AUE_FCHOWNAT STD { int linux_fchownat(l_int dfd, const char *filename, \
|
||||
l_uid16_t uid, l_gid16_t gid, l_int flag); }
|
||||
299 AUE_FUTIMESAT STD { int linux_futimesat(l_int dfd, char *filename, \
|
||||
struct l_timeval *utimes); }
|
||||
300 AUE_FSTATAT STD { int linux_fstatat64(l_int dfd, char *pathname, \
|
||||
struct l_stat64 *statbuf, l_int flag); }
|
||||
301 AUE_UNLINKAT STD { int linux_unlinkat(l_int dfd, const char *pathname, \
|
||||
l_int flag); }
|
||||
302 AUE_RENAMEAT STD { int linux_renameat(l_int olddfd, const char *oldname, \
|
||||
l_int newdfd, const char *newname); }
|
||||
303 AUE_LINKAT STD { int linux_linkat(l_int olddfd, const char *oldname, \
|
||||
l_int newdfd, const char *newname, l_int flags); }
|
||||
304 AUE_SYMLINKAT STD { int linux_symlinkat(const char *oldname, l_int newdfd, \
|
||||
const char *newname); }
|
||||
305 AUE_READLINKAT STD { int linux_readlinkat(l_int dfd, const char *path, \
|
||||
char *buf, l_int bufsiz); }
|
||||
306 AUE_FCHMODAT STD { int linux_fchmodat(l_int dfd, const char *filename, \
|
||||
l_mode_t mode); }
|
||||
307 AUE_FACCESSAT STD { int linux_faccessat(l_int dfd, const char *filename, l_int mode); }
|
||||
308 AUE_NULL STD { int linux_pselect6(void); }
|
||||
309 AUE_NULL STD { int linux_ppoll(void); }
|
||||
310 AUE_NULL STD { int linux_unshare(void); }
|
||||
|
@ -67,6 +67,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <machine/../linux/linux_proto.h>
|
||||
#endif
|
||||
#include <compat/linux/linux_util.h>
|
||||
#include <compat/linux/linux_file.h>
|
||||
|
||||
int
|
||||
linux_creat(struct thread *td, struct linux_creat_args *args)
|
||||
@ -88,7 +89,7 @@ linux_creat(struct thread *td, struct linux_creat_args *args)
|
||||
|
||||
|
||||
static int
|
||||
linux_common_open(struct thread *td, char *path, int l_flags, int mode, int openat)
|
||||
linux_common_open(struct thread *td, int dirfd, char *path, int l_flags, int mode)
|
||||
{
|
||||
struct proc *p = td->td_proc;
|
||||
struct file *fp;
|
||||
@ -130,7 +131,10 @@ linux_common_open(struct thread *td, char *path, int l_flags, int mode, int open
|
||||
bsd_flags |= O_NOFOLLOW;
|
||||
/* XXX LINUX_O_NOATIME: unable to be easily implemented. */
|
||||
|
||||
error = kern_open(td, path, UIO_SYSSPACE, bsd_flags, mode);
|
||||
if (dirfd != -1)
|
||||
error = kern_openat(td, dirfd, path, UIO_SYSSPACE, bsd_flags, mode);
|
||||
else
|
||||
error = kern_open(td, path, UIO_SYSSPACE, bsd_flags, mode);
|
||||
if (!error) {
|
||||
fd = td->td_retval[0];
|
||||
/*
|
||||
@ -172,122 +176,27 @@ linux_common_open(struct thread *td, char *path, int l_flags, int mode, int open
|
||||
if (ldebug(open))
|
||||
printf(LMSG("open returns error %d"), error);
|
||||
#endif
|
||||
if (!openat)
|
||||
LFREEPATH(path);
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* common code for linux *at set of syscalls
|
||||
*
|
||||
* works like this:
|
||||
* if filename is absolute
|
||||
* ignore dirfd
|
||||
* else
|
||||
* if dirfd == AT_FDCWD
|
||||
* return CWD/filename
|
||||
* else
|
||||
* return DIRFD/filename
|
||||
*/
|
||||
static int
|
||||
linux_at(struct thread *td, int dirfd, char *filename, char **newpath, char **freebuf)
|
||||
{
|
||||
struct file *fp;
|
||||
int error = 0, vfslocked;
|
||||
struct vnode *dvp;
|
||||
struct filedesc *fdp = td->td_proc->p_fd;
|
||||
char *fullpath = "unknown";
|
||||
char *freepath = NULL;
|
||||
|
||||
/* don't do anything if the pathname is absolute */
|
||||
if (*filename == '/') {
|
||||
*newpath= filename;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* check for AT_FDWCD */
|
||||
if (dirfd == LINUX_AT_FDCWD) {
|
||||
FILEDESC_SLOCK(fdp);
|
||||
dvp = fdp->fd_cdir;
|
||||
vref(dvp);
|
||||
FILEDESC_SUNLOCK(fdp);
|
||||
} else {
|
||||
error = fget(td, dirfd, &fp);
|
||||
if (error)
|
||||
return (error);
|
||||
dvp = fp->f_vnode;
|
||||
/* only a dir can be dfd */
|
||||
if (dvp->v_type != VDIR) {
|
||||
fdrop(fp, td);
|
||||
return (ENOTDIR);
|
||||
}
|
||||
vref(dvp);
|
||||
fdrop(fp, td);
|
||||
}
|
||||
|
||||
/*
|
||||
* XXXRW: This is bogus, as vn_fullpath() returns only an advisory
|
||||
* file path, and may fail in several common situations, including
|
||||
* for file systmes that don't use the name cache, and if the entry
|
||||
* for the file falls out of the name cache. We should implement
|
||||
* openat() in the FreeBSD native system call layer properly (using a
|
||||
* requested starting directory), and have Linux and other ABIs wrap
|
||||
* the native implementation.
|
||||
*/
|
||||
error = vn_fullpath(td, dvp, &fullpath, &freepath);
|
||||
if (!error) {
|
||||
*newpath = malloc(strlen(fullpath) + strlen(filename) + 2, M_TEMP, M_WAITOK | M_ZERO);
|
||||
*freebuf = freepath;
|
||||
sprintf(*newpath, "%s/%s", fullpath, filename);
|
||||
} else {
|
||||
*newpath = NULL;
|
||||
}
|
||||
vfslocked = VFS_LOCK_GIANT(dvp->v_mount);
|
||||
vrele(dvp);
|
||||
VFS_UNLOCK_GIANT(vfslocked);
|
||||
return (error);
|
||||
LFREEPATH(path);
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
linux_openat(struct thread *td, struct linux_openat_args *args)
|
||||
{
|
||||
char *newpath, *oldpath, *freebuf, *path;
|
||||
int error;
|
||||
char *path;
|
||||
int dfd;
|
||||
|
||||
oldpath = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
|
||||
error = copyinstr(args->filename, oldpath, MAXPATHLEN, NULL);
|
||||
if (error) {
|
||||
free(oldpath, M_TEMP);
|
||||
return (error);
|
||||
}
|
||||
dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
|
||||
if (args->flags & LINUX_O_CREAT)
|
||||
LCONVPATH_AT(td, args->filename, &path, 1, dfd);
|
||||
else
|
||||
LCONVPATH_AT(td, args->filename, &path, 0, dfd);
|
||||
#ifdef DEBUG
|
||||
if (ldebug(openat))
|
||||
printf(ARGS(openat, "%i, %s, 0x%x, 0x%x"), args->dfd,
|
||||
oldpath, args->flags, args->mode);
|
||||
path, args->flags, args->mode);
|
||||
#endif
|
||||
newpath = freebuf = NULL;
|
||||
error = linux_at(td, args->dfd, oldpath, &newpath, &freebuf);
|
||||
if (error == 0) {
|
||||
#ifdef DEBUG
|
||||
if (ldebug(openat))
|
||||
printf(LMSG("newpath: %s"), newpath);
|
||||
#endif
|
||||
if (args->flags & LINUX_O_CREAT)
|
||||
LCONVPATH_SEG(td, newpath, &path, 1, UIO_SYSSPACE);
|
||||
else
|
||||
LCONVPATH_SEG(td, newpath, &path, 0, UIO_SYSSPACE);
|
||||
}
|
||||
if (freebuf)
|
||||
free(freebuf, M_TEMP);
|
||||
if (*oldpath != '/')
|
||||
free(newpath, M_TEMP);
|
||||
if (error == 0) {
|
||||
error = linux_common_open(td, path, args->flags,
|
||||
args->mode, 1);
|
||||
LFREEPATH(path);
|
||||
}
|
||||
free(oldpath, M_TEMP);
|
||||
return (error);
|
||||
return (linux_common_open(td, dfd, path, args->flags, args->mode));
|
||||
}
|
||||
|
||||
int
|
||||
@ -306,7 +215,7 @@ linux_open(struct thread *td, struct linux_open_args *args)
|
||||
path, args->flags, args->mode);
|
||||
#endif
|
||||
|
||||
return linux_common_open(td, path, args->flags, args->mode, 0);
|
||||
return (linux_common_open(td, -1, path, args->flags, args->mode));
|
||||
}
|
||||
|
||||
int
|
||||
@ -655,6 +564,31 @@ linux_access(struct thread *td, struct linux_access_args *args)
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
linux_faccessat(struct thread *td, struct linux_faccessat_args *args)
|
||||
{
|
||||
char *path;
|
||||
int error, dfd;
|
||||
|
||||
/* linux convention */
|
||||
if (args->mode & ~(F_OK | X_OK | W_OK | R_OK))
|
||||
return (EINVAL);
|
||||
|
||||
dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
|
||||
LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (ldebug(access))
|
||||
printf(ARGS(access, "%s, %d"), path, args->mode);
|
||||
#endif
|
||||
|
||||
error = kern_accessat(td, dfd, path, UIO_SYSSPACE, 0 /* XXX */,
|
||||
args->mode);
|
||||
LFREEPATH(path);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
linux_unlink(struct thread *td, struct linux_unlink_args *args)
|
||||
{
|
||||
@ -679,6 +613,37 @@ linux_unlink(struct thread *td, struct linux_unlink_args *args)
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
linux_unlinkat(struct thread *td, struct linux_unlinkat_args *args)
|
||||
{
|
||||
char *path;
|
||||
int error, dfd;
|
||||
struct stat st;
|
||||
|
||||
if (args->flag & ~LINUX_AT_REMOVEDIR)
|
||||
return (EINVAL);
|
||||
|
||||
dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
|
||||
LCONVPATHEXIST_AT(td, args->pathname, &path, dfd);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (ldebug(unlinkat))
|
||||
printf(ARGS(unlinkat, "%s"), path);
|
||||
#endif
|
||||
|
||||
if (args->flag & LINUX_AT_REMOVEDIR)
|
||||
error = kern_rmdirat(td, dfd, path, UIO_SYSSPACE);
|
||||
else
|
||||
error = kern_unlinkat(td, dfd, path, UIO_SYSSPACE);
|
||||
if (error == EPERM && !(args->flag & LINUX_AT_REMOVEDIR)) {
|
||||
/* Introduce POSIX noncompliant behaviour of Linux */
|
||||
if (kern_statat(td, AT_SYMLINK_NOFOLLOW, dfd, path,
|
||||
UIO_SYSSPACE, &st) == 0 && S_ISDIR(st.st_mode))
|
||||
error = EISDIR;
|
||||
}
|
||||
LFREEPATH(path);
|
||||
return (error);
|
||||
}
|
||||
int
|
||||
linux_chdir(struct thread *td, struct linux_chdir_args *args)
|
||||
{
|
||||
@ -713,6 +678,25 @@ linux_chmod(struct thread *td, struct linux_chmod_args *args)
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
linux_fchmodat(struct thread *td, struct linux_fchmodat_args *args)
|
||||
{
|
||||
char *path;
|
||||
int error, dfd;
|
||||
|
||||
dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
|
||||
LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (ldebug(fchmodat))
|
||||
printf(ARGS(fchmodat, "%s, %d"), path, args->mode);
|
||||
#endif
|
||||
|
||||
error = kern_fchmodat(td, dfd, path, UIO_SYSSPACE, args->mode, 0);
|
||||
LFREEPATH(path);
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
linux_mkdir(struct thread *td, struct linux_mkdir_args *args)
|
||||
{
|
||||
@ -730,6 +714,24 @@ linux_mkdir(struct thread *td, struct linux_mkdir_args *args)
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
linux_mkdirat(struct thread *td, struct linux_mkdirat_args *args)
|
||||
{
|
||||
char *path;
|
||||
int error, dfd;
|
||||
|
||||
dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
|
||||
LCONVPATHCREAT_AT(td, args->pathname, &path, dfd);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (ldebug(mkdirat))
|
||||
printf(ARGS(mkdirat, "%s, %d"), path, args->mode);
|
||||
#endif
|
||||
error = kern_mkdirat(td, dfd, path, UIO_SYSSPACE, args->mode);
|
||||
LFREEPATH(path);
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
linux_rmdir(struct thread *td, struct linux_rmdir_args *args)
|
||||
{
|
||||
@ -755,7 +757,7 @@ linux_rename(struct thread *td, struct linux_rename_args *args)
|
||||
|
||||
LCONVPATHEXIST(td, args->from, &from);
|
||||
/* Expand LCONVPATHCREATE so that `from' can be freed on errors */
|
||||
error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1);
|
||||
error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
|
||||
if (to == NULL) {
|
||||
LFREEPATH(from);
|
||||
return (error);
|
||||
@ -771,6 +773,32 @@ linux_rename(struct thread *td, struct linux_rename_args *args)
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
linux_renameat(struct thread *td, struct linux_renameat_args *args)
|
||||
{
|
||||
char *from, *to;
|
||||
int error, olddfd, newdfd;
|
||||
|
||||
olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
|
||||
newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
|
||||
LCONVPATHEXIST_AT(td, args->oldname, &from, olddfd);
|
||||
/* Expand LCONVPATHCREATE so that `from' can be freed on errors */
|
||||
error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd);
|
||||
if (to == NULL) {
|
||||
LFREEPATH(from);
|
||||
return (error);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (ldebug(renameat))
|
||||
printf(ARGS(renameat, "%s, %s"), from, to);
|
||||
#endif
|
||||
error = kern_renameat(td, olddfd, from, newdfd, to, UIO_SYSSPACE);
|
||||
LFREEPATH(from);
|
||||
LFREEPATH(to);
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
linux_symlink(struct thread *td, struct linux_symlink_args *args)
|
||||
{
|
||||
@ -779,7 +807,7 @@ linux_symlink(struct thread *td, struct linux_symlink_args *args)
|
||||
|
||||
LCONVPATHEXIST(td, args->path, &path);
|
||||
/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
|
||||
error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1);
|
||||
error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
|
||||
if (to == NULL) {
|
||||
LFREEPATH(path);
|
||||
return (error);
|
||||
@ -795,6 +823,32 @@ linux_symlink(struct thread *td, struct linux_symlink_args *args)
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
linux_symlinkat(struct thread *td, struct linux_symlinkat_args *args)
|
||||
{
|
||||
char *path, *to;
|
||||
int error, dfd;
|
||||
|
||||
dfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
|
||||
LCONVPATHEXIST_AT(td, args->oldname, &path, dfd);
|
||||
/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
|
||||
error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, dfd);
|
||||
if (to == NULL) {
|
||||
LFREEPATH(path);
|
||||
return (error);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (ldebug(symlinkat))
|
||||
printf(ARGS(symlinkat, "%s, %s"), path, to);
|
||||
#endif
|
||||
|
||||
error = kern_symlinkat(td, path, dfd, to, UIO_SYSSPACE);
|
||||
LFREEPATH(path);
|
||||
LFREEPATH(to);
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
linux_readlink(struct thread *td, struct linux_readlink_args *args)
|
||||
{
|
||||
@ -814,6 +868,26 @@ linux_readlink(struct thread *td, struct linux_readlink_args *args)
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
linux_readlinkat(struct thread *td, struct linux_readlinkat_args *args)
|
||||
{
|
||||
char *name;
|
||||
int error, dfd;
|
||||
|
||||
dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
|
||||
LCONVPATHEXIST_AT(td, args->path, &name, dfd);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (ldebug(readlinkat))
|
||||
printf(ARGS(readlinkat, "%s, %p, %d"), name, (void *)args->buf,
|
||||
args->bufsiz);
|
||||
#endif
|
||||
|
||||
error = kern_readlinkat(td, dfd, name, UIO_SYSSPACE, args->buf,
|
||||
UIO_USERSPACE, args->bufsiz);
|
||||
LFREEPATH(name);
|
||||
return (error);
|
||||
}
|
||||
int
|
||||
linux_truncate(struct thread *td, struct linux_truncate_args *args)
|
||||
{
|
||||
@ -854,7 +928,7 @@ linux_link(struct thread *td, struct linux_link_args *args)
|
||||
|
||||
LCONVPATHEXIST(td, args->path, &path);
|
||||
/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
|
||||
error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1);
|
||||
error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1, AT_FDCWD);
|
||||
if (to == NULL) {
|
||||
LFREEPATH(path);
|
||||
return (error);
|
||||
@ -870,6 +944,41 @@ linux_link(struct thread *td, struct linux_link_args *args)
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
linux_linkat(struct thread *td, struct linux_linkat_args *args)
|
||||
{
|
||||
char *path, *to;
|
||||
int error, olddfd, newdfd;
|
||||
|
||||
/*
|
||||
* They really introduced flags argument which is forbidden to
|
||||
* use.
|
||||
*/
|
||||
if (args->flags != 0)
|
||||
return (EINVAL);
|
||||
|
||||
olddfd = (args->olddfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->olddfd;
|
||||
newdfd = (args->newdfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->newdfd;
|
||||
LCONVPATHEXIST_AT(td, args->oldname, &path, olddfd);
|
||||
/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
|
||||
error = linux_emul_convpath(td, args->newname, UIO_USERSPACE, &to, 1, newdfd);
|
||||
if (to == NULL) {
|
||||
LFREEPATH(path);
|
||||
return (error);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (ldebug(linkat))
|
||||
printf(ARGS(linkat, "%i, %s, %i, %s, %i"), args->olddfd, path,
|
||||
args->newdfd, to, args->flags);
|
||||
#endif
|
||||
|
||||
error = kern_linkat(td, olddfd, newdfd, path, to, UIO_SYSSPACE, FOLLOW);
|
||||
LFREEPATH(path);
|
||||
LFREEPATH(to);
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
linux_fdatasync(td, uap)
|
||||
struct thread *td;
|
||||
@ -1337,6 +1446,31 @@ linux_chown(struct thread *td, struct linux_chown_args *args)
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
linux_fchownat(struct thread *td, struct linux_fchownat_args *args)
|
||||
{
|
||||
char *path;
|
||||
int error, dfd, follow;
|
||||
|
||||
if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW)
|
||||
return (EINVAL);
|
||||
|
||||
dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
|
||||
LCONVPATHEXIST_AT(td, args->filename, &path, dfd);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (ldebug(fchownat))
|
||||
printf(ARGS(fchownat, "%s, %d, %d"), path, args->uid, args->gid);
|
||||
#endif
|
||||
|
||||
follow = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) == 0 ? 0 :
|
||||
AT_SYMLINK_NOFOLLOW;
|
||||
error = kern_fchownat(td, dfd, path, UIO_SYSSPACE, args->uid, args->gid,
|
||||
follow);
|
||||
LFREEPATH(path);
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
linux_lchown(struct thread *td, struct linux_lchown_args *args)
|
||||
{
|
||||
|
36
sys/compat/linux/linux_file.h
Normal file
36
sys/compat/linux/linux_file.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*-
|
||||
* Copyright (c) 2007 Roman Divacky
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_FILE_H_
|
||||
#define _LINUX_FILE_H_
|
||||
|
||||
#define LINUX_AT_FDCWD -100
|
||||
#define LINUX_AT_SYMLINK_NOFOLLOW 0x100
|
||||
#define LINUX_AT_REMOVEDIR 0x200
|
||||
|
||||
#endif /* !_LINUX_FILE_H_ */
|
@ -87,6 +87,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <machine/../linux/linux_proto.h>
|
||||
#endif
|
||||
|
||||
#include <compat/linux/linux_file.h>
|
||||
#include <compat/linux/linux_mib.h>
|
||||
#include <compat/linux/linux_signal.h>
|
||||
#include <compat/linux/linux_util.h>
|
||||
@ -836,6 +837,39 @@ linux_utimes(struct thread *td, struct linux_utimes_args *args)
|
||||
LFREEPATH(fname);
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
linux_futimesat(struct thread *td, struct linux_futimesat_args *args)
|
||||
{
|
||||
l_timeval ltv[2];
|
||||
struct timeval tv[2], *tvp = NULL;
|
||||
char *fname;
|
||||
int error, dfd;
|
||||
|
||||
dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
|
||||
LCONVPATHEXIST_AT(td, args->filename, &fname, dfd);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (ldebug(futimesat))
|
||||
printf(ARGS(futimesat, "%s, *"), fname);
|
||||
#endif
|
||||
|
||||
if (args->utimes != NULL) {
|
||||
if ((error = copyin(args->utimes, ltv, sizeof ltv))) {
|
||||
LFREEPATH(fname);
|
||||
return (error);
|
||||
}
|
||||
tv[0].tv_sec = ltv[0].tv_sec;
|
||||
tv[0].tv_usec = ltv[0].tv_usec;
|
||||
tv[1].tv_sec = ltv[1].tv_sec;
|
||||
tv[1].tv_usec = ltv[1].tv_usec;
|
||||
tvp = tv;
|
||||
}
|
||||
|
||||
error = kern_utimesat(td, dfd, fname, UIO_SYSSPACE, tvp, UIO_SYSSPACE);
|
||||
LFREEPATH(fname);
|
||||
return (error);
|
||||
}
|
||||
#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
|
||||
|
||||
#define __WCLONE 0x80000000
|
||||
@ -963,6 +997,56 @@ linux_mknod(struct thread *td, struct linux_mknod_args *args)
|
||||
case S_IFREG:
|
||||
error = kern_open(td, path, UIO_SYSSPACE,
|
||||
O_WRONLY | O_CREAT | O_TRUNC, args->mode);
|
||||
if (error == 0)
|
||||
kern_close(td, td->td_retval[0]);
|
||||
break;
|
||||
|
||||
default:
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
LFREEPATH(path);
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
linux_mknodat(struct thread *td, struct linux_mknodat_args *args)
|
||||
{
|
||||
char *path;
|
||||
int error, dfd;
|
||||
|
||||
dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
|
||||
LCONVPATHCREAT_AT(td, args->filename, &path, dfd);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (ldebug(mknodat))
|
||||
printf(ARGS(mknodat, "%s, %d, %d"), path, args->mode, args->dev);
|
||||
#endif
|
||||
|
||||
switch (args->mode & S_IFMT) {
|
||||
case S_IFIFO:
|
||||
case S_IFSOCK:
|
||||
error = kern_mkfifoat(td, dfd, path, UIO_SYSSPACE, args->mode);
|
||||
break;
|
||||
|
||||
case S_IFCHR:
|
||||
case S_IFBLK:
|
||||
error = kern_mknodat(td, dfd, path, UIO_SYSSPACE, args->mode,
|
||||
args->dev);
|
||||
break;
|
||||
|
||||
case S_IFDIR:
|
||||
error = EPERM;
|
||||
break;
|
||||
|
||||
case 0:
|
||||
args->mode |= S_IFREG;
|
||||
/* FALLTHROUGH */
|
||||
case S_IFREG:
|
||||
error = kern_openat(td, dfd, path, UIO_SYSSPACE,
|
||||
O_WRONLY | O_CREAT | O_TRUNC, args->mode);
|
||||
if (error == 0)
|
||||
kern_close(td, td->td_retval[0]);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -57,6 +57,7 @@ __FBSDID("$FreeBSD$");
|
||||
#endif
|
||||
|
||||
#include <compat/linux/linux_util.h>
|
||||
#include <compat/linux/linux_file.h>
|
||||
|
||||
#include <security/mac/mac_framework.h>
|
||||
|
||||
@ -114,9 +115,10 @@ translate_fd_major_minor(struct thread *td, int fd, struct stat *buf)
|
||||
}
|
||||
|
||||
static void
|
||||
translate_path_major_minor(struct thread *td, char *path, struct stat *buf)
|
||||
translate_path_major_minor_at(struct thread *td, char *path,
|
||||
struct stat *buf, int dfd)
|
||||
{
|
||||
struct proc *p = td->td_proc;
|
||||
struct proc *p = td->td_proc;
|
||||
struct filedesc *fdp = p->p_fd;
|
||||
int fd;
|
||||
int temp;
|
||||
@ -124,7 +126,7 @@ translate_path_major_minor(struct thread *td, char *path, struct stat *buf)
|
||||
if (!S_ISCHR(buf->st_mode) && !S_ISBLK(buf->st_mode))
|
||||
return;
|
||||
temp = td->td_retval[0];
|
||||
if (kern_open(td, path, UIO_SYSSPACE, O_RDONLY, 0) != 0)
|
||||
if (kern_openat(td, dfd, path, UIO_SYSSPACE, O_RDONLY, 0) != 0)
|
||||
return;
|
||||
fd = td->td_retval[0];
|
||||
td->td_retval[0] = temp;
|
||||
@ -132,6 +134,12 @@ translate_path_major_minor(struct thread *td, char *path, struct stat *buf)
|
||||
fdclose(fdp, fdp->fd_ofiles[fd], fd, td);
|
||||
}
|
||||
|
||||
static inline void
|
||||
translate_path_major_minor(struct thread *td, char *path, struct stat *buf)
|
||||
{
|
||||
translate_path_major_minor_at(td, path, buf, AT_FDCWD);
|
||||
}
|
||||
|
||||
static int
|
||||
newstat_copyout(struct stat *buf, void *ubuf)
|
||||
{
|
||||
@ -581,4 +589,33 @@ linux_fstat64(struct thread *td, struct linux_fstat64_args *args)
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
linux_fstatat64(struct thread *td, struct linux_fstatat64_args *args)
|
||||
{
|
||||
char *path;
|
||||
int error, dfd, flag;
|
||||
struct stat buf;
|
||||
|
||||
if (args->flag & ~LINUX_AT_SYMLINK_NOFOLLOW)
|
||||
return (EINVAL);
|
||||
flag = (args->flag & LINUX_AT_SYMLINK_NOFOLLOW) ?
|
||||
AT_SYMLINK_NOFOLLOW : 0;
|
||||
|
||||
dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
|
||||
LCONVPATHEXIST_AT(td, args->pathname, &path, dfd);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (ldebug(fstatat64))
|
||||
printf(ARGS(fstatat64, "%i, %s, %i"), args->dfd, path, args->flag);
|
||||
#endif
|
||||
|
||||
error = kern_statat(td, flag, dfd, path, UIO_SYSSPACE, &buf);
|
||||
translate_path_major_minor_at(td, args->pathname, &buf, dfd);
|
||||
if (!error)
|
||||
error = stat64_copyout(&buf, args->statbuf);
|
||||
LFREEPATH(path);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
|
||||
|
@ -66,16 +66,17 @@ const char linux_emul_path[] = "/compat/linux";
|
||||
* named file, i.e. we check if the directory it should be in exists.
|
||||
*/
|
||||
int
|
||||
linux_emul_convpath(td, path, pathseg, pbuf, cflag)
|
||||
linux_emul_convpath(td, path, pathseg, pbuf, cflag, dfd)
|
||||
struct thread *td;
|
||||
char *path;
|
||||
const char *path;
|
||||
enum uio_seg pathseg;
|
||||
char **pbuf;
|
||||
int cflag;
|
||||
int dfd;
|
||||
{
|
||||
|
||||
return (kern_alternate_path(td, linux_emul_path, path, pathseg, pbuf,
|
||||
cflag));
|
||||
cflag, dfd));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -51,23 +51,25 @@
|
||||
|
||||
extern const char linux_emul_path[];
|
||||
|
||||
int linux_emul_convpath(struct thread *, char *, enum uio_seg, char **, int);
|
||||
int linux_emul_convpath(struct thread *, const char *, enum uio_seg, char **, int, int);
|
||||
|
||||
#define LCONVPATH_SEG(td, upath, pathp, i, seg) \
|
||||
#define LCONVPATH_AT(td, upath, pathp, i, dfd) \
|
||||
do { \
|
||||
int _error; \
|
||||
\
|
||||
_error = linux_emul_convpath(td, upath, seg, \
|
||||
pathp, i); \
|
||||
_error = linux_emul_convpath(td, upath, UIO_USERSPACE, \
|
||||
pathp, i, dfd); \
|
||||
if (*(pathp) == NULL) \
|
||||
return (_error); \
|
||||
} while (0)
|
||||
|
||||
#define LCONVPATH(td, upath, pathp, i) \
|
||||
LCONVPATH_SEG(td, upath, pathp, i, UIO_USERSPACE)
|
||||
LCONVPATH_AT(td, upath, pathp, i, AT_FDCWD)
|
||||
|
||||
#define LCONVPATHEXIST(td, upath, pathp) LCONVPATH(td, upath, pathp, 0)
|
||||
#define LCONVPATHEXIST_AT(td, upath, pathp, dfd) LCONVPATH_AT(td, upath, pathp, 0, dfd)
|
||||
#define LCONVPATHCREAT(td, upath, pathp) LCONVPATH(td, upath, pathp, 1)
|
||||
#define LCONVPATHCREAT_AT(td, upath, pathp, dfd) LCONVPATH_AT(td, upath, pathp, 1, dfd)
|
||||
#define LFREEPATH(path) free(path, M_TEMP)
|
||||
|
||||
#define DUMMY(s) \
|
||||
|
@ -258,7 +258,7 @@ svr4_emul_find(struct thread *td, char *path, enum uio_seg pathseg,
|
||||
{
|
||||
|
||||
return (kern_alternate_path(td, svr4_emul_path, path, pathseg, pbuf,
|
||||
create));
|
||||
create, AT_FDCWD));
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -56,5 +56,5 @@ ibcs2_emul_find(struct thread *td, char *path, enum uio_seg pathseg,
|
||||
{
|
||||
|
||||
return (kern_alternate_path(td, ibcs2_emul_path, path, pathseg, pbuf,
|
||||
cflag));
|
||||
cflag, AT_FDCWD));
|
||||
}
|
||||
|
@ -550,8 +550,6 @@ int linux_ioctl_unregister_handler(struct linux_ioctl_handler *h);
|
||||
#define LINUX_F_WRLCK 1
|
||||
#define LINUX_F_UNLCK 2
|
||||
|
||||
#define LINUX_AT_FDCWD -100
|
||||
|
||||
/*
|
||||
* mount flags
|
||||
*/
|
||||
|
@ -87,18 +87,6 @@ DUMMY(inotify_init);
|
||||
DUMMY(inotify_add_watch);
|
||||
DUMMY(inotify_rm_watch);
|
||||
DUMMY(migrate_pages);
|
||||
DUMMY(mkdirat);
|
||||
DUMMY(mknodat);
|
||||
DUMMY(fchownat);
|
||||
DUMMY(futimesat);
|
||||
DUMMY(fstatat64);
|
||||
DUMMY(unlinkat);
|
||||
DUMMY(renameat);
|
||||
DUMMY(linkat);
|
||||
DUMMY(symlinkat);
|
||||
DUMMY(readlinkat);
|
||||
DUMMY(fchmodat);
|
||||
DUMMY(faccessat);
|
||||
DUMMY(pselect6);
|
||||
DUMMY(ppoll);
|
||||
DUMMY(unshare);
|
||||
|
@ -777,7 +777,7 @@ exec_linux_imgact_try(struct image_params *imgp)
|
||||
*/
|
||||
if ((error = exec_shell_imgact(imgp)) == 0) {
|
||||
linux_emul_convpath(FIRST_THREAD_IN_PROC(imgp->proc),
|
||||
imgp->interpreter_name, UIO_SYSSPACE, &rpath, 0);
|
||||
imgp->interpreter_name, UIO_SYSSPACE, &rpath, 0, AT_FDCWD);
|
||||
if (rpath != NULL) {
|
||||
len = strlen(rpath) + 1;
|
||||
|
||||
|
@ -475,20 +475,31 @@
|
||||
292 AUE_NULL STD { int linux_inotify_add_watch(void); }
|
||||
293 AUE_NULL STD { int linux_inotify_rm_watch(void); }
|
||||
294 AUE_NULL STD { int linux_migrate_pages(void); }
|
||||
295 AUE_OPEN_RWTC STD { int linux_openat(l_int dfd, char *filename, \
|
||||
295 AUE_OPEN_RWTC STD { int linux_openat(l_int dfd, const char *filename, \
|
||||
l_int flags, l_int mode); }
|
||||
296 AUE_NULL STD { int linux_mkdirat(void); }
|
||||
297 AUE_NULL STD { int linux_mknodat(void); }
|
||||
298 AUE_NULL STD { int linux_fchownat(void); }
|
||||
299 AUE_NULL STD { int linux_futimesat(void); }
|
||||
300 AUE_NULL STD { int linux_fstatat64(void); }
|
||||
301 AUE_NULL STD { int linux_unlinkat(void); }
|
||||
302 AUE_NULL STD { int linux_renameat(void); }
|
||||
303 AUE_NULL STD { int linux_linkat(void); }
|
||||
304 AUE_NULL STD { int linux_symlinkat(void); }
|
||||
305 AUE_NULL STD { int linux_readlinkat(void); }
|
||||
306 AUE_NULL STD { int linux_fchmodat(void); }
|
||||
307 AUE_NULL STD { int linux_faccessat(void); }
|
||||
296 AUE_MKDIRAT STD { int linux_mkdirat(l_int dfd, const char *pathname, \
|
||||
l_int mode); }
|
||||
297 AUE_MKNODAT STD { int linux_mknodat(l_int dfd, const char *filename, \
|
||||
l_int mode, l_uint dev); }
|
||||
298 AUE_FCHOWNAT STD { int linux_fchownat(l_int dfd, const char *filename, \
|
||||
l_uid16_t uid, l_gid16_t gid, l_int flag); }
|
||||
299 AUE_FUTIMESAT STD { int linux_futimesat(l_int dfd, char *filename, \
|
||||
struct l_timeval *utimes); }
|
||||
300 AUE_FSTATAT STD { int linux_fstatat64(l_int dfd, char *pathname, \
|
||||
struct l_stat64 *statbuf, l_int flag); }
|
||||
301 AUE_UNLINKAT STD { int linux_unlinkat(l_int dfd, const char *pathname, \
|
||||
l_int flag); }
|
||||
302 AUE_RENAMEAT STD { int linux_renameat(l_int olddfd, const char *oldname, \
|
||||
l_int newdfd, const char *newname); }
|
||||
303 AUE_LINKAT STD { int linux_linkat(l_int olddfd, const char *oldname, \
|
||||
l_int newdfd, const char *newname, l_int flags); }
|
||||
304 AUE_SYMLINKAT STD { int linux_symlinkat(const char *oldname, l_int newdfd, \
|
||||
const char *newname); }
|
||||
305 AUE_READLINKAT STD { int linux_readlinkat(l_int dfd, const char *path, \
|
||||
char *buf, l_int bufsiz); }
|
||||
306 AUE_FCHMODAT STD { int linux_fchmodat(l_int dfd, const char *filename, \
|
||||
l_mode_t mode); }
|
||||
307 AUE_FACCESSAT STD { int linux_faccessat(l_int dfd, const char *filename, l_int mode); }
|
||||
308 AUE_NULL STD { int linux_pselect6(void); }
|
||||
309 AUE_NULL STD { int linux_ppoll(void); }
|
||||
310 AUE_NULL STD { int linux_unshare(void); }
|
||||
|
@ -1032,8 +1032,8 @@ NDFREE(struct nameidata *ndp, const u_int flags)
|
||||
* the M_TEMP bucket if one is returned.
|
||||
*/
|
||||
int
|
||||
kern_alternate_path(struct thread *td, const char *prefix, char *path,
|
||||
enum uio_seg pathseg, char **pathbuf, int create)
|
||||
kern_alternate_path(struct thread *td, const char *prefix, const char *path,
|
||||
enum uio_seg pathseg, char **pathbuf, int create, int dirfd)
|
||||
{
|
||||
struct nameidata nd, ndroot;
|
||||
char *ptr, *buf, *cp;
|
||||
@ -1071,6 +1071,15 @@ kern_alternate_path(struct thread *td, const char *prefix, char *path,
|
||||
goto keeporig;
|
||||
}
|
||||
|
||||
if (dirfd != AT_FDCWD) {
|
||||
/*
|
||||
* We want the original because the "prefix" is
|
||||
* included in the already opened dirfd.
|
||||
*/
|
||||
bcopy(ptr, buf, len);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* We know that there is a / somewhere in this pathname.
|
||||
* Search backwards for it, to find the file's parent dir
|
||||
|
@ -60,8 +60,8 @@ int kern_accessat(struct thread *td, int fd, char *path,
|
||||
enum uio_seg pathseg, int flags, int mode);
|
||||
int kern_adjtime(struct thread *td, struct timeval *delta,
|
||||
struct timeval *olddelta);
|
||||
int kern_alternate_path(struct thread *td, const char *prefix, char *path,
|
||||
enum uio_seg pathseg, char **pathbuf, int create);
|
||||
int kern_alternate_path(struct thread *td, const char *prefix, const char *path,
|
||||
enum uio_seg pathseg, char **pathbuf, int create, int dirfd);
|
||||
int kern_bind(struct thread *td, int fd, struct sockaddr *sa);
|
||||
int kern_chdir(struct thread *td, char *path, enum uio_seg pathseg);
|
||||
int kern_chmod(struct thread *td, char *path, enum uio_seg pathseg,
|
||||
|
Loading…
Reference in New Issue
Block a user