Implement the openat() linux syscall

Submitted by:	Roman Divacky (rdivacky@)
MFC after:	2 weeks
This commit is contained in:
Julian Elischer 2007-03-29 02:11:46 +00:00
parent bc5676e30c
commit 6734f35eac
12 changed files with 164 additions and 43 deletions

View File

@ -531,6 +531,7 @@ int linux_ioctl_unregister_handler(struct linux_ioctl_handler *h);
#define LINUX_O_RDONLY 00000000
#define LINUX_O_WRONLY 00000001
#define LINUX_O_RDWR 00000002
#define LINUX_O_ACCMODE 00000003
#define LINUX_O_CREAT 00000100
#define LINUX_O_EXCL 00000200
#define LINUX_O_NOCTTY 00000400
@ -565,6 +566,8 @@ 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
*/

View File

@ -97,7 +97,6 @@ DUMMY(inotify_init);
DUMMY(inotify_add_watch);
DUMMY(inotify_rm_watch);
DUMMY(migrate_pages);
DUMMY(openat);
DUMMY(mkdirat);
DUMMY(mknodat);
DUMMY(fchownat);

View File

@ -871,7 +871,10 @@ struct linux_migrate_pages_args {
register_t dummy;
};
struct linux_openat_args {
register_t dummy;
char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)];
char filename_l_[PADL_(char *)]; char * filename; char filename_r_[PADR_(char *)];
char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)];
char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)];
};
struct linux_mkdirat_args {
register_t dummy;
@ -1381,7 +1384,7 @@ int linux_unshare(struct thread *, struct linux_unshare_args *);
#define LINUX_SYS_AUE_linux_inotify_add_watch AUE_NULL
#define LINUX_SYS_AUE_linux_inotify_rm_watch AUE_NULL
#define LINUX_SYS_AUE_linux_migrate_pages AUE_NULL
#define LINUX_SYS_AUE_linux_openat AUE_NULL
#define LINUX_SYS_AUE_linux_openat AUE_OPEN_RWTC
#define LINUX_SYS_AUE_linux_mkdirat AUE_NULL
#define LINUX_SYS_AUE_linux_mknodat AUE_NULL
#define LINUX_SYS_AUE_linux_fchownat AUE_NULL

View File

@ -315,7 +315,7 @@ struct sysent linux_sysent[] = {
{ 0, (sy_call_t *)linux_inotify_add_watch, AUE_NULL, NULL, 0, 0 }, /* 292 = linux_inotify_add_watch */
{ 0, (sy_call_t *)linux_inotify_rm_watch, AUE_NULL, NULL, 0, 0 }, /* 293 = linux_inotify_rm_watch */
{ 0, (sy_call_t *)linux_migrate_pages, AUE_NULL, NULL, 0, 0 }, /* 294 = linux_migrate_pages */
{ 0, (sy_call_t *)linux_openat, AUE_NULL, NULL, 0, 0 }, /* 295 = linux_openat */
{ AS(linux_openat_args), (sy_call_t *)linux_openat, AUE_OPEN_RWTC, NULL, 0, 0 }, /* 295 = linux_openat */
{ 0, (sy_call_t *)linux_mkdirat, AUE_NULL, NULL, 0, 0 }, /* 296 = linux_mkdirat */
{ 0, (sy_call_t *)linux_mknodat, AUE_NULL, NULL, 0, 0 }, /* 297 = linux_mknodat */
{ 0, (sy_call_t *)linux_fchownat, AUE_NULL, NULL, 0, 0 }, /* 298 = linux_fchownat */

View File

@ -463,7 +463,8 @@
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_NULL STD { int linux_openat(void); }
295 AUE_OPEN_RWTC STD { int linux_openat(l_int dfd, 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); }

View File

@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$");
#include <sys/malloc.h>
#include <sys/mount.h>
#include <sys/mutex.h>
#include <sys/namei.h>
#include <sys/proc.h>
#include <sys/stat.h>
#include <sys/sx.h>
@ -85,57 +86,51 @@ linux_creat(struct thread *td, struct linux_creat_args *args)
return (error);
}
int
linux_open(struct thread *td, struct linux_open_args *args)
static int
linux_common_open(struct thread *td, char *path, int l_flags, int mode, int openat)
{
struct proc *p = td->td_proc;
struct file *fp;
int fd;
char *path;
int bsd_flags, error;
if (args->flags & LINUX_O_CREAT)
LCONVPATHCREAT(td, args->path, &path);
else
LCONVPATHEXIST(td, args->path, &path);
#ifdef DEBUG
if (ldebug(open))
printf(ARGS(open, "%s, 0x%x, 0x%x"),
path, args->flags, args->mode);
#endif
bsd_flags = 0;
if (args->flags & LINUX_O_RDONLY)
bsd_flags |= O_RDONLY;
if (args->flags & LINUX_O_WRONLY)
switch (l_flags & LINUX_O_ACCMODE) {
case LINUX_O_WRONLY:
bsd_flags |= O_WRONLY;
if (args->flags & LINUX_O_RDWR)
break;
case LINUX_O_RDWR:
bsd_flags |= O_RDWR;
if (args->flags & LINUX_O_NDELAY)
break;
default:
bsd_flags |= O_RDONLY;
}
if (l_flags & LINUX_O_NDELAY)
bsd_flags |= O_NONBLOCK;
if (args->flags & LINUX_O_APPEND)
if (l_flags & LINUX_O_APPEND)
bsd_flags |= O_APPEND;
if (args->flags & LINUX_O_SYNC)
if (l_flags & LINUX_O_SYNC)
bsd_flags |= O_FSYNC;
if (args->flags & LINUX_O_NONBLOCK)
if (l_flags & LINUX_O_NONBLOCK)
bsd_flags |= O_NONBLOCK;
if (args->flags & LINUX_FASYNC)
if (l_flags & LINUX_FASYNC)
bsd_flags |= O_ASYNC;
if (args->flags & LINUX_O_CREAT)
if (l_flags & LINUX_O_CREAT)
bsd_flags |= O_CREAT;
if (args->flags & LINUX_O_TRUNC)
if (l_flags & LINUX_O_TRUNC)
bsd_flags |= O_TRUNC;
if (args->flags & LINUX_O_EXCL)
if (l_flags & LINUX_O_EXCL)
bsd_flags |= O_EXCL;
if (args->flags & LINUX_O_NOCTTY)
if (l_flags & LINUX_O_NOCTTY)
bsd_flags |= O_NOCTTY;
if (args->flags & LINUX_O_DIRECT)
if (l_flags & LINUX_O_DIRECT)
bsd_flags |= O_DIRECT;
if (args->flags & LINUX_O_NOFOLLOW)
if (l_flags & LINUX_O_NOFOLLOW)
bsd_flags |= O_NOFOLLOW;
/* XXX LINUX_O_NOATIME: unable to be easily implemented. */
error = kern_open(td, path, UIO_SYSSPACE, bsd_flags, args->mode);
error = kern_open(td, path, UIO_SYSSPACE, bsd_flags, mode);
if (!error) {
fd = td->td_retval[0];
/*
@ -158,7 +153,7 @@ linux_open(struct thread *td, struct linux_open_args *args)
PROC_UNLOCK(p);
sx_sunlock(&proctree_lock);
}
if (args->flags & LINUX_O_DIRECTORY) {
if (l_flags & LINUX_O_DIRECTORY) {
if (fp->f_type != DTYPE_VNODE ||
fp->f_vnode->v_type != VDIR) {
error = ENOTDIR;
@ -177,10 +172,121 @@ linux_open(struct thread *td, struct linux_open_args *args)
if (ldebug(open))
printf(LMSG("open returns error %d"), error);
#endif
LFREEPATH(path);
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;
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_LOCK(fdp);
dvp = fdp->fd_cdir;
FILEDESC_UNLOCK(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);
}
fdrop(fp, td);
}
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);
}
return (error);
}
int
linux_openat(struct thread *td, struct linux_openat_args *args)
{
char *newpath, *oldpath, *freebuf = NULL, *path;
int error;
oldpath = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
error = copyinstr(args->filename, oldpath, MAXPATHLEN, NULL);
#ifdef DEBUG
if (ldebug(openat))
printf(ARGS(openat, "%i, %s, 0x%x, 0x%x"), args->dfd,
oldpath, args->flags, args->mode);
#endif
error = linux_at(td, args->dfd, oldpath, &newpath, &freebuf);
if (error)
return (error);
#ifdef DEBUG
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);
error = linux_common_open(td, path, args->flags, args->mode, 1);
free(oldpath, M_TEMP);
return (error);
}
int
linux_open(struct thread *td, struct linux_open_args *args)
{
char *path;
if (args->flags & LINUX_O_CREAT)
LCONVPATHCREAT(td, args->path, &path);
else
LCONVPATHEXIST(td, args->path, &path);
#ifdef DEBUG
if (ldebug(open))
printf(ARGS(open, "%s, 0x%x, 0x%x"),
path, args->flags, args->mode);
#endif
return linux_common_open(td, path, args->flags, args->mode, 0);
}
int
linux_lseek(struct thread *td, struct linux_lseek_args *args)
{

View File

@ -53,16 +53,19 @@ extern const char linux_emul_path[];
int linux_emul_convpath(struct thread *, char *, enum uio_seg, char **, int);
#define LCONVPATH(td, upath, pathp, i) \
#define LCONVPATH_SEG(td, upath, pathp, i, seg) \
do { \
int _error; \
\
_error = linux_emul_convpath(td, upath, UIO_USERSPACE, \
_error = linux_emul_convpath(td, upath, seg, \
pathp, i); \
if (*(pathp) == NULL) \
return (_error); \
} while (0)
#define LCONVPATH(td, upath, pathp, i) \
LCONVPATH_SEG(td, upath, pathp, i, UIO_USERSPACE)
#define LCONVPATHEXIST(td, upath, pathp) LCONVPATH(td, upath, pathp, 0)
#define LCONVPATHCREAT(td, upath, pathp) LCONVPATH(td, upath, pathp, 1)
#define LFREEPATH(path) free(path, M_TEMP)

View File

@ -502,6 +502,7 @@ int linux_ioctl_unregister_handler(struct linux_ioctl_handler *h);
#define LINUX_O_RDONLY 00000000
#define LINUX_O_WRONLY 00000001
#define LINUX_O_RDWR 00000002
#define LINUX_O_ACCMODE 00000003
#define LINUX_O_CREAT 00000100
#define LINUX_O_EXCL 00000200
#define LINUX_O_NOCTTY 00000400
@ -536,6 +537,8 @@ 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
*/

View File

@ -87,7 +87,6 @@ DUMMY(inotify_init);
DUMMY(inotify_add_watch);
DUMMY(inotify_rm_watch);
DUMMY(migrate_pages);
DUMMY(openat);
DUMMY(mkdirat);
DUMMY(mknodat);
DUMMY(fchownat);

View File

@ -893,7 +893,10 @@ struct linux_migrate_pages_args {
register_t dummy;
};
struct linux_openat_args {
register_t dummy;
char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)];
char filename_l_[PADL_(char *)]; char * filename; char filename_r_[PADR_(char *)];
char flags_l_[PADL_(l_int)]; l_int flags; char flags_r_[PADR_(l_int)];
char mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)];
};
struct linux_mkdirat_args {
register_t dummy;
@ -1407,7 +1410,7 @@ int linux_unshare(struct thread *, struct linux_unshare_args *);
#define LINUX_SYS_AUE_linux_inotify_add_watch AUE_NULL
#define LINUX_SYS_AUE_linux_inotify_rm_watch AUE_NULL
#define LINUX_SYS_AUE_linux_migrate_pages AUE_NULL
#define LINUX_SYS_AUE_linux_openat AUE_NULL
#define LINUX_SYS_AUE_linux_openat AUE_OPEN_RWTC
#define LINUX_SYS_AUE_linux_mkdirat AUE_NULL
#define LINUX_SYS_AUE_linux_mknodat AUE_NULL
#define LINUX_SYS_AUE_linux_fchownat AUE_NULL

View File

@ -314,7 +314,7 @@ struct sysent linux_sysent[] = {
{ 0, (sy_call_t *)linux_inotify_add_watch, AUE_NULL, NULL, 0, 0 }, /* 292 = linux_inotify_add_watch */
{ 0, (sy_call_t *)linux_inotify_rm_watch, AUE_NULL, NULL, 0, 0 }, /* 293 = linux_inotify_rm_watch */
{ 0, (sy_call_t *)linux_migrate_pages, AUE_NULL, NULL, 0, 0 }, /* 294 = linux_migrate_pages */
{ 0, (sy_call_t *)linux_openat, AUE_NULL, NULL, 0, 0 }, /* 295 = linux_openat */
{ AS(linux_openat_args), (sy_call_t *)linux_openat, AUE_OPEN_RWTC, NULL, 0, 0 }, /* 295 = linux_openat */
{ 0, (sy_call_t *)linux_mkdirat, AUE_NULL, NULL, 0, 0 }, /* 296 = linux_mkdirat */
{ 0, (sy_call_t *)linux_mknodat, AUE_NULL, NULL, 0, 0 }, /* 297 = linux_mknodat */
{ 0, (sy_call_t *)linux_fchownat, AUE_NULL, NULL, 0, 0 }, /* 298 = linux_fchownat */

View File

@ -473,7 +473,8 @@
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_NULL STD { int linux_openat(void); }
295 AUE_OPEN_RWTC STD { int linux_openat(l_int dfd, 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); }