Implement the openat() linux syscall

Submitted by:	Roman Divacky (rdivacky@)
MFC after:	2 weeks
This commit is contained in:
julian 2007-03-29 02:11:46 +00:00
parent fdf75b9020
commit 93fc8e768e
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_RDONLY 00000000
#define LINUX_O_WRONLY 00000001 #define LINUX_O_WRONLY 00000001
#define LINUX_O_RDWR 00000002 #define LINUX_O_RDWR 00000002
#define LINUX_O_ACCMODE 00000003
#define LINUX_O_CREAT 00000100 #define LINUX_O_CREAT 00000100
#define LINUX_O_EXCL 00000200 #define LINUX_O_EXCL 00000200
#define LINUX_O_NOCTTY 00000400 #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_WRLCK 1
#define LINUX_F_UNLCK 2 #define LINUX_F_UNLCK 2
#define LINUX_AT_FDCWD -100
/* /*
* mount flags * mount flags
*/ */

View File

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

View File

@ -871,7 +871,10 @@ struct linux_migrate_pages_args {
register_t dummy; register_t dummy;
}; };
struct linux_openat_args { 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 { struct linux_mkdirat_args {
register_t dummy; 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_add_watch AUE_NULL
#define LINUX_SYS_AUE_linux_inotify_rm_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_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_mkdirat AUE_NULL
#define LINUX_SYS_AUE_linux_mknodat AUE_NULL #define LINUX_SYS_AUE_linux_mknodat AUE_NULL
#define LINUX_SYS_AUE_linux_fchownat 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_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_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_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_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_mknodat, AUE_NULL, NULL, 0, 0 }, /* 297 = linux_mknodat */
{ 0, (sy_call_t *)linux_fchownat, AUE_NULL, NULL, 0, 0 }, /* 298 = linux_fchownat */ { 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); } 292 AUE_NULL STD { int linux_inotify_add_watch(void); }
293 AUE_NULL STD { int linux_inotify_rm_watch(void); } 293 AUE_NULL STD { int linux_inotify_rm_watch(void); }
294 AUE_NULL STD { int linux_migrate_pages(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); } 296 AUE_NULL STD { int linux_mkdirat(void); }
297 AUE_NULL STD { int linux_mknodat(void); } 297 AUE_NULL STD { int linux_mknodat(void); }
298 AUE_NULL STD { int linux_fchownat(void); } 298 AUE_NULL STD { int linux_fchownat(void); }

View File

@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$");
#include <sys/malloc.h> #include <sys/malloc.h>
#include <sys/mount.h> #include <sys/mount.h>
#include <sys/mutex.h> #include <sys/mutex.h>
#include <sys/namei.h>
#include <sys/proc.h> #include <sys/proc.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/sx.h> #include <sys/sx.h>
@ -85,57 +86,51 @@ linux_creat(struct thread *td, struct linux_creat_args *args)
return (error); 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 proc *p = td->td_proc;
struct file *fp; struct file *fp;
int fd; int fd;
char *path;
int bsd_flags, error; 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; bsd_flags = 0;
if (args->flags & LINUX_O_RDONLY) switch (l_flags & LINUX_O_ACCMODE) {
bsd_flags |= O_RDONLY; case LINUX_O_WRONLY:
if (args->flags & LINUX_O_WRONLY)
bsd_flags |= O_WRONLY; bsd_flags |= O_WRONLY;
if (args->flags & LINUX_O_RDWR) break;
case LINUX_O_RDWR:
bsd_flags |= 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; bsd_flags |= O_NONBLOCK;
if (args->flags & LINUX_O_APPEND) if (l_flags & LINUX_O_APPEND)
bsd_flags |= O_APPEND; bsd_flags |= O_APPEND;
if (args->flags & LINUX_O_SYNC) if (l_flags & LINUX_O_SYNC)
bsd_flags |= O_FSYNC; bsd_flags |= O_FSYNC;
if (args->flags & LINUX_O_NONBLOCK) if (l_flags & LINUX_O_NONBLOCK)
bsd_flags |= O_NONBLOCK; bsd_flags |= O_NONBLOCK;
if (args->flags & LINUX_FASYNC) if (l_flags & LINUX_FASYNC)
bsd_flags |= O_ASYNC; bsd_flags |= O_ASYNC;
if (args->flags & LINUX_O_CREAT) if (l_flags & LINUX_O_CREAT)
bsd_flags |= O_CREAT; bsd_flags |= O_CREAT;
if (args->flags & LINUX_O_TRUNC) if (l_flags & LINUX_O_TRUNC)
bsd_flags |= O_TRUNC; bsd_flags |= O_TRUNC;
if (args->flags & LINUX_O_EXCL) if (l_flags & LINUX_O_EXCL)
bsd_flags |= O_EXCL; bsd_flags |= O_EXCL;
if (args->flags & LINUX_O_NOCTTY) if (l_flags & LINUX_O_NOCTTY)
bsd_flags |= O_NOCTTY; bsd_flags |= O_NOCTTY;
if (args->flags & LINUX_O_DIRECT) if (l_flags & LINUX_O_DIRECT)
bsd_flags |= O_DIRECT; bsd_flags |= O_DIRECT;
if (args->flags & LINUX_O_NOFOLLOW) if (l_flags & LINUX_O_NOFOLLOW)
bsd_flags |= O_NOFOLLOW; bsd_flags |= O_NOFOLLOW;
/* XXX LINUX_O_NOATIME: unable to be easily implemented. */ /* 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) { if (!error) {
fd = td->td_retval[0]; fd = td->td_retval[0];
/* /*
@ -158,7 +153,7 @@ linux_open(struct thread *td, struct linux_open_args *args)
PROC_UNLOCK(p); PROC_UNLOCK(p);
sx_sunlock(&proctree_lock); sx_sunlock(&proctree_lock);
} }
if (args->flags & LINUX_O_DIRECTORY) { if (l_flags & LINUX_O_DIRECTORY) {
if (fp->f_type != DTYPE_VNODE || if (fp->f_type != DTYPE_VNODE ||
fp->f_vnode->v_type != VDIR) { fp->f_vnode->v_type != VDIR) {
error = ENOTDIR; error = ENOTDIR;
@ -177,10 +172,121 @@ linux_open(struct thread *td, struct linux_open_args *args)
if (ldebug(open)) if (ldebug(open))
printf(LMSG("open returns error %d"), error); printf(LMSG("open returns error %d"), error);
#endif #endif
LFREEPATH(path); if (!openat)
LFREEPATH(path);
return error; 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 int
linux_lseek(struct thread *td, struct linux_lseek_args *args) 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); 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 { \ do { \
int _error; \ int _error; \
\ \
_error = linux_emul_convpath(td, upath, UIO_USERSPACE, \ _error = linux_emul_convpath(td, upath, seg, \
pathp, i); \ pathp, i); \
if (*(pathp) == NULL) \ if (*(pathp) == NULL) \
return (_error); \ return (_error); \
} while (0) } 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 LCONVPATHEXIST(td, upath, pathp) LCONVPATH(td, upath, pathp, 0)
#define LCONVPATHCREAT(td, upath, pathp) LCONVPATH(td, upath, pathp, 1) #define LCONVPATHCREAT(td, upath, pathp) LCONVPATH(td, upath, pathp, 1)
#define LFREEPATH(path) free(path, M_TEMP) #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_RDONLY 00000000
#define LINUX_O_WRONLY 00000001 #define LINUX_O_WRONLY 00000001
#define LINUX_O_RDWR 00000002 #define LINUX_O_RDWR 00000002
#define LINUX_O_ACCMODE 00000003
#define LINUX_O_CREAT 00000100 #define LINUX_O_CREAT 00000100
#define LINUX_O_EXCL 00000200 #define LINUX_O_EXCL 00000200
#define LINUX_O_NOCTTY 00000400 #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_WRLCK 1
#define LINUX_F_UNLCK 2 #define LINUX_F_UNLCK 2
#define LINUX_AT_FDCWD -100
/* /*
* mount flags * mount flags
*/ */

View File

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

View File

@ -893,7 +893,10 @@ struct linux_migrate_pages_args {
register_t dummy; register_t dummy;
}; };
struct linux_openat_args { 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 { struct linux_mkdirat_args {
register_t dummy; 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_add_watch AUE_NULL
#define LINUX_SYS_AUE_linux_inotify_rm_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_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_mkdirat AUE_NULL
#define LINUX_SYS_AUE_linux_mknodat AUE_NULL #define LINUX_SYS_AUE_linux_mknodat AUE_NULL
#define LINUX_SYS_AUE_linux_fchownat 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_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_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_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_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_mknodat, AUE_NULL, NULL, 0, 0 }, /* 297 = linux_mknodat */
{ 0, (sy_call_t *)linux_fchownat, AUE_NULL, NULL, 0, 0 }, /* 298 = linux_fchownat */ { 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); } 292 AUE_NULL STD { int linux_inotify_add_watch(void); }
293 AUE_NULL STD { int linux_inotify_rm_watch(void); } 293 AUE_NULL STD { int linux_inotify_rm_watch(void); }
294 AUE_NULL STD { int linux_migrate_pages(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); } 296 AUE_NULL STD { int linux_mkdirat(void); }
297 AUE_NULL STD { int linux_mknodat(void); } 297 AUE_NULL STD { int linux_mknodat(void); }
298 AUE_NULL STD { int linux_fchownat(void); } 298 AUE_NULL STD { int linux_fchownat(void); }