summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorjulian <julian@FreeBSD.org>2007-03-29 02:11:46 +0000
committerjulian <julian@FreeBSD.org>2007-03-29 02:11:46 +0000
commit93fc8e768e49d2737c73c10e780d085f9fe2de7d (patch)
treef48ac269cb2bbda7e0d9278c796db1a7d0a2cb59 /sys
parentfdf75b902074d70bcb83a0421e1e7a1ef8f5bed5 (diff)
downloadFreeBSD-src-93fc8e768e49d2737c73c10e780d085f9fe2de7d.zip
FreeBSD-src-93fc8e768e49d2737c73c10e780d085f9fe2de7d.tar.gz
Implement the openat() linux syscall
Submitted by: Roman Divacky (rdivacky@) MFC after: 2 weeks
Diffstat (limited to 'sys')
-rw-r--r--sys/amd64/linux32/linux.h3
-rw-r--r--sys/amd64/linux32/linux32_dummy.c1
-rw-r--r--sys/amd64/linux32/linux32_proto.h7
-rw-r--r--sys/amd64/linux32/linux32_sysent.c2
-rw-r--r--sys/amd64/linux32/syscalls.master3
-rw-r--r--sys/compat/linux/linux_file.c168
-rw-r--r--sys/compat/linux/linux_util.h7
-rw-r--r--sys/i386/linux/linux.h3
-rw-r--r--sys/i386/linux/linux_dummy.c1
-rw-r--r--sys/i386/linux/linux_proto.h7
-rw-r--r--sys/i386/linux/linux_sysent.c2
-rw-r--r--sys/i386/linux/syscalls.master3
12 files changed, 164 insertions, 43 deletions
diff --git a/sys/amd64/linux32/linux.h b/sys/amd64/linux32/linux.h
index cf9b14c..b998402 100644
--- a/sys/amd64/linux32/linux.h
+++ b/sys/amd64/linux32/linux.h
@@ -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
*/
diff --git a/sys/amd64/linux32/linux32_dummy.c b/sys/amd64/linux32/linux32_dummy.c
index 5babd4c..5f4b797 100644
--- a/sys/amd64/linux32/linux32_dummy.c
+++ b/sys/amd64/linux32/linux32_dummy.c
@@ -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);
diff --git a/sys/amd64/linux32/linux32_proto.h b/sys/amd64/linux32/linux32_proto.h
index e8a5b10..0ad4576 100644
--- a/sys/amd64/linux32/linux32_proto.h
+++ b/sys/amd64/linux32/linux32_proto.h
@@ -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
diff --git a/sys/amd64/linux32/linux32_sysent.c b/sys/amd64/linux32/linux32_sysent.c
index 3bd1885..19c86ce 100644
--- a/sys/amd64/linux32/linux32_sysent.c
+++ b/sys/amd64/linux32/linux32_sysent.c
@@ -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 */
diff --git a/sys/amd64/linux32/syscalls.master b/sys/amd64/linux32/syscalls.master
index 9c3ee1e..9fc4cb0 100644
--- a/sys/amd64/linux32/syscalls.master
+++ b/sys/amd64/linux32/syscalls.master
@@ -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); }
diff --git a/sys/compat/linux/linux_file.c b/sys/compat/linux/linux_file.c
index e09f915..ae99416 100644
--- a/sys/compat/linux/linux_file.c
+++ b/sys/compat/linux/linux_file.c
@@ -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)
{
diff --git a/sys/compat/linux/linux_util.h b/sys/compat/linux/linux_util.h
index ee47baf..5264766 100644
--- a/sys/compat/linux/linux_util.h
+++ b/sys/compat/linux/linux_util.h
@@ -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)
diff --git a/sys/i386/linux/linux.h b/sys/i386/linux/linux.h
index c7219ba..ef41399 100644
--- a/sys/i386/linux/linux.h
+++ b/sys/i386/linux/linux.h
@@ -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
*/
diff --git a/sys/i386/linux/linux_dummy.c b/sys/i386/linux/linux_dummy.c
index cd2c615..fec4f65 100644
--- a/sys/i386/linux/linux_dummy.c
+++ b/sys/i386/linux/linux_dummy.c
@@ -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);
diff --git a/sys/i386/linux/linux_proto.h b/sys/i386/linux/linux_proto.h
index f828447..53b0520 100644
--- a/sys/i386/linux/linux_proto.h
+++ b/sys/i386/linux/linux_proto.h
@@ -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
diff --git a/sys/i386/linux/linux_sysent.c b/sys/i386/linux/linux_sysent.c
index b961a25..a38e54a 100644
--- a/sys/i386/linux/linux_sysent.c
+++ b/sys/i386/linux/linux_sysent.c
@@ -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 */
diff --git a/sys/i386/linux/syscalls.master b/sys/i386/linux/syscalls.master
index fa9d444..43946f2 100644
--- a/sys/i386/linux/syscalls.master
+++ b/sys/i386/linux/syscalls.master
@@ -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); }
OpenPOWER on IntegriCloud