Date: Sat, 14 Apr 2007 11:18:12 GMT From: Roman Divacky <rdivacky@FreeBSD.org> To: Perforce Change Reviews <perforce@FreeBSD.org> Subject: PERFORCE change 118086 for review Message-ID: <200704141118.l3EBICLn037053@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=118086 Change 118086 by rdivacky@rdivacky_witten on 2007/04/14 11:17:28 Implement linux_openat(), linux_fstatat64() and linux_faccessat(): o extend struct nameidata to incorporate vdir param o add NDINIT_AT that fills in vdir, NDINIT always fills in NULL o change namei to use vdir as its starting dir if its non-NULL o create kern_openat and kern_accessat o add AT_FDCWD define that specifies CWD as dfd The names will probably change and the place for AT_FDCWD might change as well. Note that I saw a panic when starting X with this patch but I cannot reproduce it so its hard to say whether its related but I don't think so. Suggested by: rwatson Affected files ... .. //depot/projects/soc2007/rdivacky/linux_at/sys/amd64/linux32/linux32_dummy.c#2 edit .. //depot/projects/soc2007/rdivacky/linux_at/sys/amd64/linux32/linux32_proto.h#2 edit .. //depot/projects/soc2007/rdivacky/linux_at/sys/amd64/linux32/linux32_syscall.h#2 edit .. //depot/projects/soc2007/rdivacky/linux_at/sys/amd64/linux32/linux32_sysent.c#2 edit .. //depot/projects/soc2007/rdivacky/linux_at/sys/amd64/linux32/syscalls.master#2 edit .. //depot/projects/soc2007/rdivacky/linux_at/sys/compat/linux/linux_file.c#2 edit .. //depot/projects/soc2007/rdivacky/linux_at/sys/compat/linux/linux_stats.c#2 edit .. //depot/projects/soc2007/rdivacky/linux_at/sys/i386/linux/linux_dummy.c#2 edit .. //depot/projects/soc2007/rdivacky/linux_at/sys/i386/linux/linux_proto.h#2 edit .. //depot/projects/soc2007/rdivacky/linux_at/sys/i386/linux/linux_syscall.h#2 edit .. //depot/projects/soc2007/rdivacky/linux_at/sys/i386/linux/linux_sysent.c#2 edit .. //depot/projects/soc2007/rdivacky/linux_at/sys/i386/linux/syscalls.master#2 edit .. //depot/projects/soc2007/rdivacky/linux_at/sys/kern/vfs_lookup.c#2 edit .. //depot/projects/soc2007/rdivacky/linux_at/sys/kern/vfs_syscalls.c#2 edit .. //depot/projects/soc2007/rdivacky/linux_at/sys/sys/fcntl.h#2 edit .. //depot/projects/soc2007/rdivacky/linux_at/sys/sys/namei.h#2 edit .. //depot/projects/soc2007/rdivacky/linux_at/sys/sys/syscallsubr.h#2 edit Differences ... ==== //depot/projects/soc2007/rdivacky/linux_at/sys/amd64/linux32/linux32_dummy.c#2 (text+ko) ==== @@ -101,14 +101,12 @@ 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); ==== //depot/projects/soc2007/rdivacky/linux_at/sys/amd64/linux32/linux32_proto.h#2 (text+ko) ==== @@ -2,7 +2,7 @@ * System call prototypes. * * DO NOT EDIT-- this file is automatically generated. - * $FreeBSD: src/sys/amd64/linux32/linux32_proto.h,v 1.31 2007/03/30 00:08:21 jkim Exp $ + * $FreeBSD$ * created from FreeBSD: src/sys/amd64/linux32/syscalls.master,v 1.28 2007/03/30 00:06:21 jkim Exp */ @@ -892,7 +892,10 @@ register_t dummy; }; struct linux_fstatat64_args { - register_t dummy; + char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; + char pathname_l_[PADL_(char *)]; char * pathname; char pathname_r_[PADR_(char *)]; + char statbuf_l_[PADL_(struct l_stat64 *)]; struct l_stat64 * statbuf; char statbuf_r_[PADR_(struct l_stat64 *)]; + char flag_l_[PADL_(l_int)]; l_int flag; char flag_r_[PADR_(l_int)]; }; struct linux_unlinkat_args { register_t dummy; @@ -913,7 +916,9 @@ register_t dummy; }; struct linux_faccessat_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 mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)]; }; struct linux_pselect6_args { register_t dummy; ==== //depot/projects/soc2007/rdivacky/linux_at/sys/amd64/linux32/linux32_syscall.h#2 (text+ko) ==== @@ -2,7 +2,7 @@ * System call numbers. * * DO NOT EDIT-- this file is automatically generated. - * $FreeBSD: src/sys/amd64/linux32/linux32_syscall.h,v 1.31 2007/03/30 00:08:21 jkim Exp $ + * $FreeBSD$ * created from FreeBSD: src/sys/amd64/linux32/syscalls.master,v 1.28 2007/03/30 00:06:21 jkim Exp */ ==== //depot/projects/soc2007/rdivacky/linux_at/sys/amd64/linux32/linux32_sysent.c#2 (text+ko) ==== @@ -2,7 +2,7 @@ * System call switch table. * * DO NOT EDIT-- this file is automatically generated. - * $FreeBSD: src/sys/amd64/linux32/linux32_sysent.c,v 1.31 2007/03/30 00:08:21 jkim Exp $ + * $FreeBSD$ * created from FreeBSD: src/sys/amd64/linux32/syscalls.master,v 1.28 2007/03/30 00:06:21 jkim Exp */ @@ -320,14 +320,14 @@ { 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_futimesat, AUE_NULL, NULL, 0, 0 }, /* 299 = linux_futimesat */ - { 0, (sy_call_t *)linux_fstatat64, AUE_NULL, NULL, 0, 0 }, /* 300 = linux_fstatat64 */ + { AS(linux_fstatat64_args), (sy_call_t *)linux_fstatat64, AUE_NULL, NULL, 0, 0 }, /* 300 = linux_fstatat64 */ { 0, (sy_call_t *)linux_unlinkat, AUE_NULL, NULL, 0, 0 }, /* 301 = linux_unlinkat */ { 0, (sy_call_t *)linux_renameat, AUE_NULL, NULL, 0, 0 }, /* 302 = linux_renameat */ { 0, (sy_call_t *)linux_linkat, AUE_NULL, NULL, 0, 0 }, /* 303 = linux_linkat */ { 0, (sy_call_t *)linux_symlinkat, AUE_NULL, NULL, 0, 0 }, /* 304 = linux_symlinkat */ { 0, (sy_call_t *)linux_readlinkat, AUE_NULL, NULL, 0, 0 }, /* 305 = linux_readlinkat */ { 0, (sy_call_t *)linux_fchmodat, AUE_NULL, NULL, 0, 0 }, /* 306 = linux_fchmodat */ - { 0, (sy_call_t *)linux_faccessat, AUE_NULL, NULL, 0, 0 }, /* 307 = linux_faccessat */ + { AS(linux_faccessat_args), (sy_call_t *)linux_faccessat, AUE_NULL, NULL, 0, 0 }, /* 307 = linux_faccessat */ { 0, (sy_call_t *)linux_pselect6, AUE_NULL, NULL, 0, 0 }, /* 308 = linux_pselect6 */ { 0, (sy_call_t *)linux_ppoll, AUE_NULL, NULL, 0, 0 }, /* 309 = linux_ppoll */ { 0, (sy_call_t *)linux_unshare, AUE_NULL, NULL, 0, 0 }, /* 310 = linux_unshare */ ==== //depot/projects/soc2007/rdivacky/linux_at/sys/amd64/linux32/syscalls.master#2 (text+ko) ==== @@ -469,14 +469,15 @@ 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); } +300 AUE_NULL STD { int linux_fstatat64(l_int dfd, char *pathname, \ + struct l_stat64 *statbuf, l_int flag); } 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); } +307 AUE_NULL STD { int linux_faccessat(l_int dfd, 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); } ==== //depot/projects/soc2007/rdivacky/linux_at/sys/compat/linux/linux_file.c#2 (text+ko) ==== @@ -88,7 +88,7 @@ static int -linux_common_open(struct thread *td, char *path, int l_flags, int mode, int openat) +linux_common_open(struct thread *td, char *path, int l_flags, int mode, int dirfd) { struct proc *p = td->td_proc; struct file *fp; @@ -130,7 +130,10 @@ 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, path, UIO_SYSSPACE, bsd_flags, mode, dirfd); + else + error = kern_open(td, path, UIO_SYSSPACE, bsd_flags, mode); if (!error) { fd = td->td_retval[0]; /* @@ -172,113 +175,36 @@ if (ldebug(open)) printf(LMSG("open returns error %d"), error); #endif - if (!openat) - LFREEPATH(path); + 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); - } - vfslocked = VFS_LOCK_GIANT(dvp->v_mount); - vrele(dvp); - VFS_UNLOCK_GIANT(vfslocked); - return (error); -} - int linux_openat(struct thread *td, struct linux_openat_args *args) { - char *newpath, *oldpath, *freebuf = NULL, *path; - int error; + char *newpath, *path; + int error, dirfd; + + path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); + error = copyinstr(args->filename, path, MAXPATHLEN, NULL); - oldpath = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); - error = copyinstr(args->filename, oldpath, MAXPATHLEN, NULL); + if (args->flags & LINUX_O_CREAT) + LCONVPATH_SEG(td, path, &newpath, 1, UIO_SYSSPACE); + else + LCONVPATH_SEG(td, path, &newpath, 0, UIO_SYSSPACE); + free(path, M_TEMP); #ifdef DEBUG if (ldebug(openat)) printf(ARGS(openat, "%i, %s, 0x%x, 0x%x"), args->dfd, - oldpath, args->flags, args->mode); + newpath, args->flags, args->mode); #endif + if (args->dfd == LINUX_AT_FDCWD) + dirfd = AT_FDCWD; + else + dirfd = args->dfd; - 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); + return linux_common_open(td, path, args->flags, args->mode, dirfd); } int @@ -297,7 +223,7 @@ path, args->flags, args->mode); #endif - return linux_common_open(td, path, args->flags, args->mode, 0); + return linux_common_open(td, path, args->flags, args->mode, -1); } int @@ -647,6 +573,34 @@ } 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); + + LCONVPATHEXIST(td, args->filename, &path); + +#ifdef DEBUG + if (ldebug(access)) + printf(ARGS(access, "%s, %d"), path, args->mode); +#endif + + if (args->dfd == LINUX_AT_FDCWD) + dfd = -1; + else + dfd = args->dfd; + + error = kern_accessat(td, path, UIO_SYSSPACE, args->mode, dfd); + LFREEPATH(path); + + return (error); +} + +int linux_unlink(struct thread *td, struct linux_unlink_args *args) { char *path; ==== //depot/projects/soc2007/rdivacky/linux_at/sys/compat/linux/linux_stats.c#2 (text+ko) ==== @@ -578,4 +578,56 @@ return (error); } +/* XXX: racy? */ +int +linux_fstatat64(struct thread *td, struct linux_fstatat64_args *args) +{ + int error; + char *path, *newpath; + int fd, dfd; + struct stat buf; + + /* open the file */ + path = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); + error = copyinstr(args->pathname, path, MAXPATHLEN, NULL); + if (error) { + free(path, M_TEMP); + return (EFAULT); + } + + LCONVPATH_SEG(td, path, &newpath, 0, UIO_SYSSPACE); + free(path, M_TEMP); + +#ifdef DEBUG + if (ldebug(fstatat64)) + printf(ARGS(fstatat64, "%i, %s, %i"), args->dfd, newpath, args->flag); +#endif + + if (args->dfd == LINUX_AT_FDCWD) + dfd = AT_FDCWD; + else + dfd = args->dfd; + + error = kern_openat(td, newpath, UIO_SYSSPACE, O_RDONLY, 0, dfd); + if (error) { + LFREEPATH(newpath); + return (error); + } + /* file opened */ + fd = td->td_retval[0]; + td->td_retval[0] = 0; + + /* do the actual fstat */ + + error = kern_fstat(td, fd, &buf); + translate_fd_major_minor(td, fd, &buf); + if (!error) + error = stat64_copyout(&buf, args->statbuf); + + /* close the opened file */ + kern_close(td, fd); + LFREEPATH(newpath); + return (0); +} + #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */ ==== //depot/projects/soc2007/rdivacky/linux_at/sys/i386/linux/linux_dummy.c#2 (text+ko) ==== @@ -91,14 +91,12 @@ 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); ==== //depot/projects/soc2007/rdivacky/linux_at/sys/i386/linux/linux_proto.h#2 (text+ko) ==== @@ -2,8 +2,8 @@ * System call prototypes. * * DO NOT EDIT-- this file is automatically generated. - * $FreeBSD: src/sys/i386/linux/linux_proto.h,v 1.92 2007/03/29 02:11:46 julian Exp $ - * created from FreeBSD: src/sys/i386/linux/syscalls.master,v 1.86 2007/02/15 00:54:40 jkim Exp + * $FreeBSD$ + * created from FreeBSD: src/sys/i386/linux/syscalls.master,v 1.87 2007/03/29 02:11:46 julian Exp */ #ifndef _LINUX_SYSPROTO_H_ @@ -911,7 +911,10 @@ register_t dummy; }; struct linux_fstatat64_args { - register_t dummy; + char dfd_l_[PADL_(l_int)]; l_int dfd; char dfd_r_[PADR_(l_int)]; + char pathname_l_[PADL_(char *)]; char * pathname; char pathname_r_[PADR_(char *)]; + char statbuf_l_[PADL_(struct l_stat64 *)]; struct l_stat64 * statbuf; char statbuf_r_[PADR_(struct l_stat64 *)]; + char flag_l_[PADL_(l_int)]; l_int flag; char flag_r_[PADR_(l_int)]; }; struct linux_unlinkat_args { register_t dummy; @@ -932,7 +935,9 @@ register_t dummy; }; struct linux_faccessat_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 mode_l_[PADL_(l_int)]; l_int mode; char mode_r_[PADR_(l_int)]; }; struct linux_pselect6_args { register_t dummy; ==== //depot/projects/soc2007/rdivacky/linux_at/sys/i386/linux/linux_syscall.h#2 (text+ko) ==== @@ -2,8 +2,8 @@ * System call numbers. * * DO NOT EDIT-- this file is automatically generated. - * $FreeBSD: src/sys/i386/linux/linux_syscall.h,v 1.85 2007/03/29 02:11:46 julian Exp $ - * created from FreeBSD: src/sys/i386/linux/syscalls.master,v 1.86 2007/02/15 00:54:40 jkim Exp + * $FreeBSD$ + * created from FreeBSD: src/sys/i386/linux/syscalls.master,v 1.87 2007/03/29 02:11:46 julian Exp */ #define LINUX_SYS_exit 1 ==== //depot/projects/soc2007/rdivacky/linux_at/sys/i386/linux/linux_sysent.c#2 (text+ko) ==== @@ -2,8 +2,8 @@ * System call switch table. * * DO NOT EDIT-- this file is automatically generated. - * $FreeBSD: src/sys/i386/linux/linux_sysent.c,v 1.92 2007/03/29 02:11:46 julian Exp $ - * created from FreeBSD: src/sys/i386/linux/syscalls.master,v 1.86 2007/02/15 00:54:40 jkim Exp + * $FreeBSD$ + * created from FreeBSD: src/sys/i386/linux/syscalls.master,v 1.87 2007/03/29 02:11:46 julian Exp */ #include <bsm/audit_kevents.h> @@ -319,14 +319,14 @@ { 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_futimesat, AUE_NULL, NULL, 0, 0 }, /* 299 = linux_futimesat */ - { 0, (sy_call_t *)linux_fstatat64, AUE_NULL, NULL, 0, 0 }, /* 300 = linux_fstatat64 */ + { AS(linux_fstatat64_args), (sy_call_t *)linux_fstatat64, AUE_NULL, NULL, 0, 0 }, /* 300 = linux_fstatat64 */ { 0, (sy_call_t *)linux_unlinkat, AUE_NULL, NULL, 0, 0 }, /* 301 = linux_unlinkat */ { 0, (sy_call_t *)linux_renameat, AUE_NULL, NULL, 0, 0 }, /* 302 = linux_renameat */ { 0, (sy_call_t *)linux_linkat, AUE_NULL, NULL, 0, 0 }, /* 303 = linux_linkat */ { 0, (sy_call_t *)linux_symlinkat, AUE_NULL, NULL, 0, 0 }, /* 304 = linux_symlinkat */ { 0, (sy_call_t *)linux_readlinkat, AUE_NULL, NULL, 0, 0 }, /* 305 = linux_readlinkat */ { 0, (sy_call_t *)linux_fchmodat, AUE_NULL, NULL, 0, 0 }, /* 306 = linux_fchmodat */ - { 0, (sy_call_t *)linux_faccessat, AUE_NULL, NULL, 0, 0 }, /* 307 = linux_faccessat */ + { AS(linux_faccessat_args), (sy_call_t *)linux_faccessat, AUE_NULL, NULL, 0, 0 }, /* 307 = linux_faccessat */ { 0, (sy_call_t *)linux_pselect6, AUE_NULL, NULL, 0, 0 }, /* 308 = linux_pselect6 */ { 0, (sy_call_t *)linux_ppoll, AUE_NULL, NULL, 0, 0 }, /* 309 = linux_ppoll */ { 0, (sy_call_t *)linux_unshare, AUE_NULL, NULL, 0, 0 }, /* 310 = linux_unshare */ ==== //depot/projects/soc2007/rdivacky/linux_at/sys/i386/linux/syscalls.master#2 (text+ko) ==== @@ -479,14 +479,15 @@ 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); } +300 AUE_NULL STD { int linux_fstatat64(l_int dfd, char *pathname, \ + struct l_stat64 *statbuf, l_int flag); } 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); } +307 AUE_NULL STD { int linux_faccessat(l_int dfd, 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); } ==== //depot/projects/soc2007/rdivacky/linux_at/sys/kern/vfs_lookup.c#2 (text+ko) ==== @@ -192,7 +192,10 @@ ndp->ni_rootdir = fdp->fd_rdir; ndp->ni_topdir = fdp->fd_jdir; - dp = fdp->fd_cdir; + if (ndp->ni_vdir) + dp = ndp->ni_vdir; + else + dp = fdp->fd_cdir; vfslocked = VFS_LOCK_GIANT(dp->v_mount); VREF(dp); FILEDESC_SUNLOCK(fdp); ==== //depot/projects/soc2007/rdivacky/linux_at/sys/kern/vfs_syscalls.c#2 (text+ko) ==== @@ -87,6 +87,10 @@ const struct timespec *, int, int); static int vn_access(struct vnode *vp, int user_flags, struct ucred *cred, struct thread *td); +static int kern_common_open(struct thread *td, char *path, enum uio_seg pathseg, + int flags, int mode, struct nameidata *nd); +static int kern_common_access(struct thread *td, char *path, enum uio_seg pathseg, + int flags, struct nameidata *nd); /* * The module initialization routine for POSIX asynchronous I/O will @@ -958,6 +962,47 @@ kern_open(struct thread *td, char *path, enum uio_seg pathseg, int flags, int mode) { + struct nameidata nd; + + AUDIT_ARG(fflags, flags); + AUDIT_ARG(mode, mode); + NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1 | MPSAFE, pathseg, path, td); + + return kern_common_open(td, path, pathseg, flags, mode, &nd); +} + +int +kern_openat(struct thread *td, char *path, enum uio_seg pathseg, int flags, + int mode, int dirfd) +{ + int error; + struct nameidata nd; + struct vnode *dir_vn; + + AUDIT_ARG(fflags, flags); + AUDIT_ARG(mode, mode); + /* XXX: audit dirfd */ + + if (dirfd == AT_FDCWD) + dir_vn = NULL; + else { + error = fgetvp(td, dirfd, &dir_vn); + if (error) + return (error); + } + + NDINIT_AT(&nd, LOOKUP, FOLLOW | AUDITVNODE1 | MPSAFE, pathseg, path, td, dir_vn); + + error = kern_common_open(td, path, pathseg, flags, mode, &nd); + if (dirfd != AT_FDCWD) + vrele(dir_vn); + return (error); +} + +static int +kern_common_open(struct thread *td, char *path, enum uio_seg pathseg, int flags, + int mode, struct nameidata *nd) +{ struct proc *p = td->td_proc; struct filedesc *fdp = p->p_fd; struct file *fp; @@ -968,23 +1013,20 @@ struct file *nfp; int type, indx, error; struct flock lf; - struct nameidata nd; int vfslocked; - AUDIT_ARG(fflags, flags); - AUDIT_ARG(mode, mode); if ((flags & O_ACCMODE) == O_ACCMODE) return (EINVAL); flags = FFLAGS(flags); + error = falloc(td, &nfp, &indx); if (error) return (error); /* An extra reference on `nfp' has been held for us by falloc(). */ fp = nfp; cmode = ((mode &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT; - NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1 | MPSAFE, pathseg, path, td); td->td_dupfd = -1; /* XXX check for fdopen */ - error = vn_open(&nd, &flags, cmode, indx); + error = vn_open(nd, &flags, cmode, indx); if (error) { /* * If the vn_open replaced the method vector, something @@ -1022,9 +1064,9 @@ return (error); } td->td_dupfd = 0; - vfslocked = NDHASGIANT(&nd); - NDFREE(&nd, NDF_ONLY_PNBUF); - vp = nd.ni_vp; + vfslocked = NDHASGIANT(nd); + NDFREE(nd, NDF_ONLY_PNBUF); + vp = nd->ni_vp; FILE_LOCK(fp); fp->f_vnode = vp; @@ -1855,9 +1897,44 @@ int kern_access(struct thread *td, char *path, enum uio_seg pathseg, int flags) { + struct nameidata nd; + + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1, + pathseg, path, td); + + return kern_common_access(td, path, pathseg, flags, &nd); +} + +int +kern_accessat(struct thread *td, char *path, enum uio_seg pathseg, int flags, int dirfd) +{ + int error; + struct nameidata nd; + struct vnode *dir_vn; + + if (dirfd == AT_FDCWD) + dir_vn = NULL; + else { + error = fgetvp(td, dirfd, &dir_vn); + if (error) + return (error); + } + + NDINIT_AT(&nd, LOOKUP, FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1, + pathseg, path, td, dir_vn); + + error = kern_common_access(td, path, pathseg, flags, &nd); + if (dirfd != AT_FDCWD) + vrele(dir_vn); + return (error); +} + +static int +kern_common_access(struct thread *td, char *path, enum uio_seg pathseg, int flags, + struct nameidata *nd) +{ struct ucred *cred, *tmpcred; - register struct vnode *vp; - struct nameidata nd; + struct vnode *vp; int vfslocked; int error; @@ -1871,15 +1948,13 @@ tmpcred->cr_uid = cred->cr_ruid; tmpcred->cr_groups[0] = cred->cr_rgid; td->td_ucred = tmpcred; - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1, - pathseg, path, td); - if ((error = namei(&nd)) != 0) + if ((error = namei(nd)) != 0) goto out1; - vfslocked = NDHASGIANT(&nd); - vp = nd.ni_vp; + vfslocked = NDHASGIANT(nd); + vp = nd->ni_vp; error = vn_access(vp, flags, tmpcred, td); - NDFREE(&nd, NDF_ONLY_PNBUF); + NDFREE(nd, NDF_ONLY_PNBUF); vput(vp); VFS_UNLOCK_GIANT(vfslocked); out1: ==== //depot/projects/soc2007/rdivacky/linux_at/sys/sys/fcntl.h#2 (text+ko) ==== @@ -105,6 +105,9 @@ #ifdef _KERNEL #define FHASLOCK 0x4000 /* descriptor holds advisory lock */ #endif +#ifdef __BSD_VISIBLE +#define AT_FDCWD -100 /* just like Linux */ +#endif /* Defined by POSIX 1003.1; BSD default, but must be distinct from O_RDONLY. */ #define O_NOCTTY 0x8000 /* don't assign controlling terminal */ ==== //depot/projects/soc2007/rdivacky/linux_at/sys/sys/namei.h#2 (text+ko) ==== @@ -63,6 +63,7 @@ */ const char *ni_dirp; /* pathname pointer */ enum uio_seg ni_segflg; /* location of pathname */ + struct vnode *ni_vdir; /* relative directory */ /* * Arguments to lookup. */ @@ -148,8 +149,6 @@ /* * Initialization of a nameidata structure. */ -static void NDINIT(struct nameidata *, u_long, u_long, enum uio_seg, - const char *, struct thread *); static __inline void NDINIT(struct nameidata *ndp, u_long op, u_long flags, @@ -162,6 +161,23 @@ ndp->ni_segflg = segflg; ndp->ni_dirp = namep; ndp->ni_cnd.cn_thread = td; + ndp->ni_vdir = NULL; +} + +static __inline void +NDINIT_AT(struct nameidata *ndp, + u_long op, u_long flags, + enum uio_seg segflg, + const char *namep, + struct thread *td, + struct vnode *dvp) +{ + ndp->ni_cnd.cn_nameiop = op; + ndp->ni_cnd.cn_flags = flags; + ndp->ni_segflg = segflg; + ndp->ni_dirp = namep; + ndp->ni_cnd.cn_thread = td; + ndp->ni_vdir = dvp; } #define NDF_NO_DVP_RELE 0x00000001 ==== //depot/projects/soc2007/rdivacky/linux_at/sys/sys/syscallsubr.h#2 (text+ko) ==== @@ -55,6 +55,8 @@ socklen_t *namelen, struct file **fp); int kern_access(struct thread *td, char *path, enum uio_seg pathseg, int flags); +int kern_accessat(struct thread *td, char *path, enum uio_seg pathseg, + int flags, int dirfd); int kern_adjtime(struct thread *td, struct timeval *delta, struct timeval *olddelta); int kern_alternate_path(struct thread *td, const char *prefix, char *path, @@ -120,6 +122,8 @@ struct timespec *rmt); int kern_open(struct thread *td, char *path, enum uio_seg pathseg, int flags, int mode); +int kern_openat(struct thread *td, char *path, enum uio_seg pathseg, + int flags, int mode, int dirfd); int kern_pathconf(struct thread *td, char *path, enum uio_seg pathseg, int name); int kern_preadv(struct thread *td, int fd, struct uio *auio, off_t offset);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200704141118.l3EBICLn037053>