From 83a117749843d33523df606c97a6b43b20aa6427 Mon Sep 17 00:00:00 2001 From: Nicolas Thery Date: Sat, 25 Jul 2009 09:12:09 +0200 Subject: [PATCH] add openat(2) system call Dragonfly-bug: Reviewed-by: dillon@ --- lib/libc_r/uthread/uthread_open.c | 53 ++++++++++++++++++++++++++ lib/libthread_xu/thread/thr_syscalls.c | 29 ++++++++++++++ sys/kern/init_sysent.c | 1 + sys/kern/syscalls.c | 1 + sys/kern/syscalls.master | 4 ++ sys/kern/vfs_syscalls.c | 42 ++++++++++++++++++++ sys/sys/fcntl.h | 7 ++++ sys/sys/syscall-hide.h | 1 + sys/sys/syscall.h | 3 +- sys/sys/syscall.mk | 3 +- sys/sys/sysproto.h | 10 +++++ sys/sys/sysunion.h | 1 + 12 files changed, 153 insertions(+), 2 deletions(-) diff --git a/lib/libc_r/uthread/uthread_open.c b/lib/libc_r/uthread/uthread_open.c index 691fd916f0..24ce366d88 100644 --- a/lib/libc_r/uthread/uthread_open.c +++ b/lib/libc_r/uthread/uthread_open.c @@ -93,3 +93,56 @@ open(const char *path, int flags,...) return ret; } + +int +_openat(int fdbase, const char *path, int flags,...) +{ + int fd; + int mode = 0; + va_list ap; + + /* Check if the file is being created: */ + if (flags & O_CREAT) { + /* Get the creation mode: */ + va_start(ap, flags); + mode = va_arg(ap, int); + va_end(ap); + } + /* Open the file: */ + if ((fd = __sys_openat(fdbase, path, flags, mode)) < 0) { + } + /* Initialise the file descriptor table entry: */ + else if (_thread_fd_table_init(fd) != 0) { + /* Quietly close the file: */ + __sys_close(fd); + + /* Reset the file descriptor: */ + fd = -1; + } + + /* Return the file descriptor or -1 on error: */ + return (fd); +} + +int +openat(int fd, const char *path, int flags,...) +{ + int ret; + int mode = 0; + va_list ap; + + _thread_enter_cancellation_point(); + + /* Check if the file is being created: */ + if (flags & O_CREAT) { + /* Get the creation mode: */ + va_start(ap, flags); + mode = va_arg(ap, int); + va_end(ap); + } + + ret = _openat(fd, path, flags, mode); + _thread_leave_cancellation_point(); + + return ret; +} diff --git a/lib/libthread_xu/thread/thr_syscalls.c b/lib/libthread_xu/thread/thr_syscalls.c index fcb69064e3..de0f231411 100644 --- a/lib/libthread_xu/thread/thr_syscalls.c +++ b/lib/libthread_xu/thread/thr_syscalls.c @@ -132,6 +132,7 @@ int __fsync(int); int __msync(void *, size_t, int); int __nanosleep(const struct timespec *, struct timespec *); int __open(const char *, int,...); +int __openat(int fd, const char *, int,...); int __poll(struct pollfd *, unsigned int, int); ssize_t __read(int, void *buf, size_t); ssize_t __readv(int, const struct iovec *, int); @@ -351,6 +352,34 @@ __open(const char *path, int flags,...) __strong_reference(__open, open); +int +__openat(int fd, const char *path, int flags,...) +{ + struct pthread *curthread = tls_get_curthread(); + int oldcancel; + int ret; + int mode = 0; + va_list ap; + + oldcancel = _thr_cancel_enter(curthread); + + /* Check if the file is being created: */ + if (flags & O_CREAT) { + /* Get the creation mode: */ + va_start(ap, flags); + mode = va_arg(ap, int); + va_end(ap); + } + + ret = __sys_openat(fd, path, flags, mode); + + _thr_cancel_leave(curthread, oldcancel); + + return ret; +} + +__strong_reference(__openat, openat); + int _pause(void) { diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c index 20b33f648d..d66ef2fac1 100644 --- a/sys/kern/init_sysent.c +++ b/sys/kern/init_sysent.c @@ -537,4 +537,5 @@ struct sysent sysent[] = { { AS(fstatvfs_args), (sy_call_t *)sys_fstatvfs }, /* 501 = fstatvfs */ { AS(fhstatvfs_args), (sy_call_t *)sys_fhstatvfs }, /* 502 = fhstatvfs */ { AS(getvfsstat_args), (sy_call_t *)sys_getvfsstat }, /* 503 = getvfsstat */ + { AS(openat_args), (sy_call_t *)sys_openat }, /* 504 = openat */ }; diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c index 817e44bcd5..5664413a59 100644 --- a/sys/kern/syscalls.c +++ b/sys/kern/syscalls.c @@ -511,4 +511,5 @@ char *syscallnames[] = { "fstatvfs", /* 501 = fstatvfs */ "fhstatvfs", /* 502 = fhstatvfs */ "getvfsstat", /* 503 = getvfsstat */ + "openat", /* 504 = openat */ }; diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index 3b2672e7d5..8527373935 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -688,3 +688,7 @@ 502 STD BSD { int fhstatvfs(const struct fhandle *u_fhp, struct statvfs *buf); } 503 STD BSD { int getvfsstat(struct statfs *buf, \ struct statvfs *vbuf, long vbufsize, int flags); } +504 STD BSD { int openat(int fd, char *path, int flags, int mode); } +; XXX should be { int openat(int fd, const char *path, int flags, ...);} +; but we're not ready for `const' or varargs. +; XXX man page says `mode_t mode'. diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 27b766c9c5..8a87f334d8 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -1837,6 +1837,48 @@ sys_open(struct open_args *uap) return (error); } +/* + * openat_args(int fd, char *path, int flags, int mode) + */ +int +sys_openat(struct openat_args *uap) +{ + struct thread *td = curthread; + struct proc *p = td->td_proc; + struct file* fp = NULL; + struct vnode *vp; + struct nlookupdata nd; + int error; + + error = nlookup_init(&nd, uap->path, UIO_USERSPACE, 0); + if (error != 0) + goto cleanup; + + if (nd.nl_path[0] != '/' && uap->fd != AT_FDCWD) { + /* + * Use dir pointed to by fd as lookup starting point instead + * of current dir. + */ + if ((error = holdvnode(p->p_fd, uap->fd, &fp)) != 0) + goto cleanup; + vp = (struct vnode*)fp->f_data; + if (vp->v_type != VDIR || fp->f_nchandle.ncp == NULL) { + error = ENOTDIR; + goto cleanup; + } + cache_drop(&nd.nl_nch); + cache_copy(&fp->f_nchandle, &nd.nl_nch); + } + + error = kern_open(&nd, uap->flags, uap->mode, &uap->sysmsg_result); + +cleanup: + if (fp != NULL) + fdrop(fp); + nlookup_done(&nd); + return (error); +} + int kern_mknod(struct nlookupdata *nd, int mode, int rmajor, int rminor) { diff --git a/sys/sys/fcntl.h b/sys/sys/fcntl.h index 7593dbb6ab..7b3384d065 100644 --- a/sys/sys/fcntl.h +++ b/sys/sys/fcntl.h @@ -165,6 +165,11 @@ #define FPOSIXSHM O_NOFOLLOW #endif +/* + * Constant used by openat() + */ +#define AT_FDCWD 0xFFFAFDCD /* must be invalid file descriptor */ + /* * Constants used for fcntl(2) */ @@ -197,6 +202,7 @@ #define F_NOEND 0x080 /* l_len = 0, internally used */ #endif + /* * Advisory file segment locking data type - * information passed to system by user @@ -233,6 +239,7 @@ union fcntl_dat { __BEGIN_DECLS int open (const char *, int, ...); +int openat (int, const char *, int, ...); int creat (const char *, mode_t); int fcntl (int, int, ...); #ifndef _POSIX_SOURCE diff --git a/sys/sys/syscall-hide.h b/sys/sys/syscall-hide.h index 0e57ae0174..6ef21fc067 100644 --- a/sys/sys/syscall-hide.h +++ b/sys/sys/syscall-hide.h @@ -334,3 +334,4 @@ HIDE_BSD(statvfs) HIDE_BSD(fstatvfs) HIDE_BSD(fhstatvfs) HIDE_BSD(getvfsstat) +HIDE_BSD(openat) diff --git a/sys/sys/syscall.h b/sys/sys/syscall.h index 38f0fc1c33..3f5d863c23 100644 --- a/sys/sys/syscall.h +++ b/sys/sys/syscall.h @@ -345,4 +345,5 @@ #define SYS_fstatvfs 501 #define SYS_fhstatvfs 502 #define SYS_getvfsstat 503 -#define SYS_MAXSYSCALL 504 +#define SYS_openat 504 +#define SYS_MAXSYSCALL 505 diff --git a/sys/sys/syscall.mk b/sys/sys/syscall.mk index c1598a80df..4fa37c8908 100644 --- a/sys/sys/syscall.mk +++ b/sys/sys/syscall.mk @@ -285,4 +285,5 @@ MIASM = \ statvfs.o \ fstatvfs.o \ fhstatvfs.o \ - getvfsstat.o + getvfsstat.o \ + openat.o diff --git a/sys/sys/sysproto.h b/sys/sys/sysproto.h index 6d72e288ea..7395548436 100644 --- a/sys/sys/sysproto.h +++ b/sys/sys/sysproto.h @@ -2159,6 +2159,15 @@ struct getvfsstat_args { long vbufsize; char vbufsize_[PAD_(long)]; int flags; char flags_[PAD_(int)]; }; +struct openat_args { +#ifdef _KERNEL + struct sysmsg sysmsg; +#endif + int fd; char fd_[PAD_(int)]; + char * path; char path_[PAD_(char *)]; + int flags; char flags_[PAD_(int)]; + int mode; char mode_[PAD_(int)]; +}; #ifdef COMPAT_43 @@ -2745,6 +2754,7 @@ int sys_statvfs (struct statvfs_args *); int sys_fstatvfs (struct fstatvfs_args *); int sys_fhstatvfs (struct fhstatvfs_args *); int sys_getvfsstat (struct getvfsstat_args *); +int sys_openat (struct openat_args *); #endif /* !_SYS_SYSPROTO_H_ */ #undef PAD_ diff --git a/sys/sys/sysunion.h b/sys/sys/sysunion.h index 2aaa1d8186..fe50bbdf52 100644 --- a/sys/sys/sysunion.h +++ b/sys/sys/sysunion.h @@ -390,4 +390,5 @@ union sysunion { struct fstatvfs_args fstatvfs; struct fhstatvfs_args fhstatvfs; struct getvfsstat_args getvfsstat; + struct openat_args openat; }; -- 2.41.0