diff options
author | John Baldwin <jhb@FreeBSD.org> | 2005-02-07 18:44:55 +0000 |
---|---|---|
committer | John Baldwin <jhb@FreeBSD.org> | 2005-02-07 18:44:55 +0000 |
commit | 76951d21d1d37261f8598543d45dc7497183a5de (patch) | |
tree | ff7cc7cc16c891dadf164e579f6845927917f2ef /sys | |
parent | c90110d639ab79b88c15395ccb4e1e257f5a4dde (diff) | |
download | src-76951d21d1d37261f8598543d45dc7497183a5de.tar.gz src-76951d21d1d37261f8598543d45dc7497183a5de.zip |
- Tweak kern_msgctl() to return a copy of the requested message queue id
structure in the struct pointed to by the 3rd argument for IPC_STAT and
get rid of the 4th argument. The old way returned a pointer into the
kernel array that the calling function would then access afterwards
without holding the appropriate locks and doing non-lock-safe things like
copyout() with the data anyways. This change removes that unsafeness and
resulting race conditions as well as simplifying the interface.
- Implement kern_foo wrappers for stat(), lstat(), fstat(), statfs(),
fstatfs(), and fhstatfs(). Use these wrappers to cut out a lot of
code duplication for freebsd4 and netbsd compatability system calls.
- Add a new lookup function kern_alternate_path() that looks up a filename
under an alternate prefix and determines which filename should be used.
This is basically a more general version of linux_emul_convpath() that
can be shared by all the ABIs thus allowing for further reduction of
code duplication.
Notes
Notes:
svn path=/head/; revision=141471
Diffstat (limited to 'sys')
-rw-r--r-- | sys/compat/linux/linux_ipc.c | 5 | ||||
-rw-r--r-- | sys/kern/kern_descrip.c | 36 | ||||
-rw-r--r-- | sys/kern/sysv_msg.c | 12 | ||||
-rw-r--r-- | sys/kern/vfs_extattr.c | 218 | ||||
-rw-r--r-- | sys/kern/vfs_lookup.c | 113 | ||||
-rw-r--r-- | sys/kern/vfs_syscalls.c | 218 | ||||
-rw-r--r-- | sys/sys/syscallsubr.h | 22 |
7 files changed, 346 insertions, 278 deletions
diff --git a/sys/compat/linux/linux_ipc.c b/sys/compat/linux/linux_ipc.c index 8fc338786d2e..ddd4f0e81c62 100644 --- a/sys/compat/linux/linux_ipc.c +++ b/sys/compat/linux/linux_ipc.c @@ -637,7 +637,6 @@ linux_msgctl(struct thread *td, struct linux_msgctl_args *args) int error, bsd_cmd; struct l_msqid_ds linux_msqid; struct msqid_ds bsd_msqid; - struct msqid_ds *bsd_msqptr; error = linux_msqid_pullup(args->cmd & LINUX_IPC_64, &linux_msqid, (caddr_t)PTRIN(args->buf)); @@ -647,13 +646,13 @@ linux_msgctl(struct thread *td, struct linux_msgctl_args *args) if (bsd_cmd == LINUX_IPC_SET) linux_to_bsd_msqid_ds(&linux_msqid, &bsd_msqid); - error = kern_msgctl(td, args->msqid, bsd_cmd, &bsd_msqid, &bsd_msqptr); + error = kern_msgctl(td, args->msqid, bsd_cmd, &bsd_msqid); if (error != 0) if (bsd_cmd != LINUX_IPC_RMID || error != EINVAL) return (error); if (bsd_cmd == LINUX_IPC_STAT) { - bsd_to_linux_msqid_ds(bsd_msqptr, &linux_msqid); + bsd_to_linux_msqid_ds(&bsd_msqid, &linux_msqid); return (linux_msqid_pushdown(args->cmd & LINUX_IPC_64, &linux_msqid, (caddr_t)PTRIN(args->buf))); } diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index 987ccdad8b46..81fead12e0ff 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -1030,20 +1030,15 @@ struct ofstat_args { int ofstat(struct thread *td, struct ofstat_args *uap) { - struct file *fp; - struct stat ub; struct ostat oub; + struct stat ub; int error; - if ((error = fget(td, uap->fd, &fp)) != 0) - goto done2; - error = fo_stat(fp, &ub, td->td_ucred, td); + error = kern_fstat(td, uap->fd, &ub); if (error == 0) { cvtstat(&ub, &oub); error = copyout(&oub, uap->sb, sizeof(oub)); } - fdrop(fp, td); -done2: return (error); } #endif /* COMPAT_43 */ @@ -1064,17 +1059,25 @@ struct fstat_args { int fstat(struct thread *td, struct fstat_args *uap) { - struct file *fp; struct stat ub; int error; - if ((error = fget(td, uap->fd, &fp)) != 0) - goto done2; - error = fo_stat(fp, &ub, td->td_ucred, td); + error = kern_fstat(td, uap->fd, &ub); if (error == 0) error = copyout(&ub, uap->sb, sizeof(ub)); + return (error); +} + +int +kern_fstat(struct thread *td, int fd, struct stat *sbp) +{ + struct file *fp; + int error; + + if ((error = fget(td, fd, &fp)) != 0) + return (error); + error = fo_stat(fp, sbp, td->td_ucred, td); fdrop(fp, td); -done2: return (error); } @@ -1094,20 +1097,15 @@ struct nfstat_args { int nfstat(struct thread *td, struct nfstat_args *uap) { - struct file *fp; - struct stat ub; struct nstat nub; + struct stat ub; int error; - if ((error = fget(td, uap->fd, &fp)) != 0) - goto done2; - error = fo_stat(fp, &ub, td->td_ucred, td); + error = kern_fstat(td, uap->fd, &ub); if (error == 0) { cvtnstat(&ub, &nub); error = copyout(&nub, uap->sb, sizeof(nub)); } - fdrop(fp, td); -done2: return (error); } diff --git a/sys/kern/sysv_msg.c b/sys/kern/sysv_msg.c index efd630e027ce..f1a7122c9529 100644 --- a/sys/kern/sysv_msg.c +++ b/sys/kern/sysv_msg.c @@ -397,26 +397,24 @@ msgctl(td, uap) int msqid = uap->msqid; int cmd = uap->cmd; struct msqid_ds msqbuf; - struct msqid_ds *msqptr; int error; DPRINTF(("call to msgctl(%d, %d, 0x%x)\n", msqid, cmd, uap->buf)); if (cmd == IPC_SET && (error = copyin(uap->buf, &msqbuf, sizeof(msqbuf))) != 0) return (error); - error = kern_msgctl(td, msqid, cmd, &msqbuf, &msqptr); + error = kern_msgctl(td, msqid, cmd, &msqbuf); if (cmd == IPC_STAT && error == 0) - error = copyout(msqptr, uap->buf, sizeof(struct msqid_ds)); + error = copyout(&msqbuf, uap->buf, sizeof(struct msqid_ds)); return (error); } int -kern_msgctl(td, msqid, cmd, msqbuf, msqptr) +kern_msgctl(td, msqid, cmd, msqbuf) struct thread *td; int msqid; int cmd; struct msqid_ds *msqbuf; - struct msqid_ds **msqptr; { int rval, error, msqix; register struct msqid_kernel *msqkptr; @@ -545,7 +543,7 @@ kern_msgctl(td, msqid, cmd, msqbuf, msqptr) DPRINTF(("requester doesn't have read access\n")); goto done2; } - *msqptr = &(msqkptr->u); + *msqbuf = msqkptr->u; break; default: @@ -558,7 +556,7 @@ kern_msgctl(td, msqid, cmd, msqbuf, msqptr) td->td_retval[0] = rval; done2: mtx_unlock(&msq_mtx); - return(error); + return (error); } #ifndef _SYS_SYSPROTO_H_ diff --git a/sys/kern/vfs_extattr.c b/sys/kern/vfs_extattr.c index 0fc6a4ef6961..cfefd08d97ef 100644 --- a/sys/kern/vfs_extattr.c +++ b/sys/kern/vfs_extattr.c @@ -221,13 +221,26 @@ statfs(td, uap) struct statfs *buf; } */ *uap; { + struct statfs sf; + int error; + + error = kern_statfs(td, uap->path, UIO_USERSPACE, &sf); + if (error == 0) + error = copyout(&sf, uap->buf, sizeof(sf)); + return (error); +} + +int +kern_statfs(struct thread *td, char *path, enum uio_seg pathseg, + struct statfs *buf) +{ struct mount *mp; struct statfs *sp, sb; int error; struct nameidata nd; mtx_lock(&Giant); - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td); + NDINIT(&nd, LOOKUP, FOLLOW, pathseg, path, td); if ((error = namei(&nd)) != 0) { mtx_unlock(&Giant); return (error); @@ -258,7 +271,8 @@ statfs(td, uap) sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; sp = &sb; } - return (copyout(sp, uap->buf, sizeof(*sp))); + *buf = *sp; + return (0); } /* @@ -278,12 +292,24 @@ fstatfs(td, uap) struct statfs *buf; } */ *uap; { + struct statfs sf; + int error; + + error = kern_fstatfs(td, uap->fd, &sf); + if (error == 0) + error = copyout(&sf, uap->buf, sizeof(sf)); + return (error); +} + +int +kern_fstatfs(struct thread *td, int fd, struct statfs *buf) +{ struct file *fp; struct mount *mp; struct statfs *sp, sb; int error; - if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0) + if ((error = getvnode(td->td_proc->p_fd, fd, &fp)) != 0) return (error); mtx_lock(&Giant); mp = fp->f_vnode->v_mount; @@ -315,7 +341,8 @@ fstatfs(td, uap) sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; sp = &sb; } - return (copyout(sp, uap->buf, sizeof(*sp))); + *buf = *sp; + return (0); } /* @@ -431,29 +458,14 @@ freebsd4_statfs(td, uap) struct ostatfs *buf; } */ *uap; { - struct mount *mp; - struct statfs *sp; struct ostatfs osb; + struct statfs sf; int error; - struct nameidata nd; - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td); - if ((error = namei(&nd)) != 0) - return (error); - mp = nd.ni_vp->v_mount; - sp = &mp->mnt_stat; - NDFREE(&nd, NDF_ONLY_PNBUF); - vrele(nd.ni_vp); -#ifdef MAC - error = mac_check_mount_stat(td->td_ucred, mp); - if (error) - return (error); -#endif - error = VFS_STATFS(mp, sp, td); + error = kern_statfs(td, uap->path, UIO_USERSPACE, &sf); if (error) return (error); - sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; - cvtstatfs(td, sp, &osb); + cvtstatfs(td, &sf, &osb); return (copyout(&osb, uap->buf, sizeof(osb))); } @@ -474,29 +486,14 @@ freebsd4_fstatfs(td, uap) struct ostatfs *buf; } */ *uap; { - struct file *fp; - struct mount *mp; - struct statfs *sp; struct ostatfs osb; + struct statfs sf; int error; - if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0) - return (error); - mp = fp->f_vnode->v_mount; - fdrop(fp, td); - if (mp == NULL) - return (EBADF); -#ifdef MAC - error = mac_check_mount_stat(td->td_ucred, mp); - if (error) - return (error); -#endif - sp = &mp->mnt_stat; - error = VFS_STATFS(mp, sp, td); + error = kern_fstatfs(td, uap->fd, &sf); if (error) return (error); - sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; - cvtstatfs(td, sp, &osb); + cvtstatfs(td, &sf, &osb); return (copyout(&osb, uap->buf, sizeof(osb))); } @@ -598,34 +595,17 @@ freebsd4_fhstatfs(td, uap) struct ostatfs *buf; } */ *uap; { - struct statfs *sp; - struct mount *mp; - struct vnode *vp; struct ostatfs osb; + struct statfs sf; fhandle_t fh; int error; - error = suser(td); - if (error) - return (error); if ((error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t))) != 0) return (error); - if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) - return (ESTALE); - if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp))) - return (error); - mp = vp->v_mount; - sp = &mp->mnt_stat; - vput(vp); -#ifdef MAC - error = mac_check_mount_stat(td->td_ucred, mp); + error = kern_fhstatfs(td, fh, &sf); if (error) return (error); -#endif - if ((error = VFS_STATFS(mp, sp, td)) != 0) - return (error); - sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; - cvtstatfs(td, sp, &osb); + cvtstatfs(td, &sf, &osb); return (copyout(&osb, uap->buf, sizeof(osb))); } @@ -1972,15 +1952,8 @@ ostat(td, uap) struct stat sb; struct ostat osb; int error; - struct nameidata nd; - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, - uap->path, td); - if ((error = namei(&nd)) != 0) - return (error); - NDFREE(&nd, NDF_ONLY_PNBUF); - error = vn_stat(nd.ni_vp, &sb, td->td_ucred, NOCRED, td); - vput(nd.ni_vp); + error = kern_stat(td, uap->path, UIO_USERSPACE, &sb); if (error) return (error); cvtstat(&sb, &osb); @@ -2005,20 +1978,11 @@ olstat(td, uap) struct ostat *ub; } */ *uap; { - struct vnode *vp; struct stat sb; struct ostat osb; int error; - struct nameidata nd; - NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, - uap->path, td); - if ((error = namei(&nd)) != 0) - return (error); - vp = nd.ni_vp; - error = vn_stat(vp, &sb, td->td_ucred, NOCRED, td); - NDFREE(&nd, NDF_ONLY_PNBUF); - vput(vp); + error = kern_lstat(td, uap->path, UIO_USERSPACE, &sb); if (error) return (error); cvtstat(&sb, &osb); @@ -2075,15 +2039,26 @@ stat(td, uap) { struct stat sb; int error; + + error = kern_stat(td, uap->path, UIO_USERSPACE, &sb); + if (error == 0) + error = copyout(&sb, uap->ub, sizeof (sb)); + return (error); +} + +int +kern_stat(struct thread *td, char *path, enum uio_seg pathseg, struct stat *sbp) +{ struct nameidata nd; - int vfslocked; + struct stat sb; + int error, vfslocked; #ifdef LOOKUP_SHARED NDINIT(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | NOOBJ | MPSAFE, - UIO_USERSPACE, uap->path, td); + pathseg, path, td); #else - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ | MPSAFE, UIO_USERSPACE, - uap->path, td); + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ | MPSAFE, pathseg, path, + td); #endif if ((error = namei(&nd)) != 0) return (error); @@ -2094,8 +2069,8 @@ stat(td, uap) VFS_UNLOCK_GIANT(vfslocked); if (error) return (error); - error = copyout(&sb, uap->ub, sizeof (sb)); - return (error); + *sbp = sb; + return (0); } /* @@ -2115,14 +2090,26 @@ lstat(td, uap) struct stat *ub; } */ *uap; { + struct stat sb; int error; + + error = kern_lstat(td, uap->path, UIO_USERSPACE, &sb); + if (error == 0) + error = copyout(&sb, uap->ub, sizeof (sb)); + return (error); +} + +int +kern_lstat(struct thread *td, char *path, enum uio_seg pathseg, struct stat *sbp) +{ struct vnode *vp; struct stat sb; struct nameidata nd; - int vfslocked; + int error, vfslocked; + /* XXX LOOKUP_SHARED? */ NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ | MPSAFE, - UIO_USERSPACE, uap->path, td); + pathseg, path, td); if ((error = namei(&nd)) != 0) return (error); vfslocked = NDHASGIANT(&nd); @@ -2133,16 +2120,12 @@ lstat(td, uap) VFS_UNLOCK_GIANT(vfslocked); if (error) return (error); - error = copyout(&sb, uap->ub, sizeof (sb)); - return (error); + *sbp = sb; + return (0); } /* - * Implementation of the NetBSD stat() function. - * XXX This should probably be collapsed with the FreeBSD version, - * as the differences are only due to vn_stat() clearing spares at - * the end of the structures. vn_stat could be split to avoid this, - * and thus collapse the following to close to zero code. + * Implementation of the NetBSD [l]stat() functions. */ void cvtnstat(sb, nsb) @@ -2185,18 +2168,8 @@ nstat(td, uap) struct stat sb; struct nstat nsb; int error; - struct nameidata nd; - int vfslocked; - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ | MPSAFE, UIO_USERSPACE, - uap->path, td); - if ((error = namei(&nd)) != 0) - return (error); - vfslocked = NDHASGIANT(&nd); - NDFREE(&nd, NDF_ONLY_PNBUF); - error = vn_stat(nd.ni_vp, &sb, td->td_ucred, NOCRED, td); - vput(nd.ni_vp); - VFS_UNLOCK_GIANT(vfslocked); + error = kern_stat(td, uap->path, UIO_USERSPACE, &sb); if (error) return (error); cvtnstat(&sb, &nsb); @@ -2221,23 +2194,11 @@ nlstat(td, uap) struct nstat *ub; } */ *uap; { - int error; - struct vnode *vp; struct stat sb; struct nstat nsb; - struct nameidata nd; - int vfslocked; + int error; - NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ | MPSAFE, - UIO_USERSPACE, uap->path, td); - if ((error = namei(&nd)) != 0) - return (error); - vfslocked = NDHASGIANT(&nd); - vp = nd.ni_vp; - NDFREE(&nd, NDF_ONLY_PNBUF); - error = vn_stat(vp, &sb, td->td_ucred, NOCRED, td); - vput(vp); - VFS_UNLOCK_GIANT(vfslocked); + error = kern_lstat(td, uap->path, UIO_USERSPACE, &sb); if (error) return (error); cvtnstat(&sb, &nsb); @@ -4234,17 +4195,29 @@ fhstatfs(td, uap) struct statfs *buf; } */ *uap; { + struct statfs sf; + fhandle_t fh; + int error; + + if ((error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t))) != 0) + return (error); + error = kern_fhstatfs(td, fh, &sf); + if (error == 0) + error = copyout(&sf, uap->buf, sizeof(sf)); + return (error); +} + +int +kern_fhstatfs(struct thread *td, fhandle_t fh, struct statfs *buf) +{ struct statfs *sp; struct mount *mp; struct vnode *vp; - fhandle_t fh; int error; error = suser(td); if (error) return (error); - if ((error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t))) != 0) - return (error); if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) return (ESTALE); if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp))) @@ -4265,7 +4238,8 @@ fhstatfs(td, uap) sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; if ((error = VFS_STATFS(mp, sp, td)) != 0) return (error); - return (copyout(sp, uap->buf, sizeof(*sp))); + *buf = *sp; + return (0); } /* diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c index a06480d8a73a..52945a9f5776 100644 --- a/sys/kern/vfs_lookup.c +++ b/sys/kern/vfs_lookup.c @@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$"); #include <sys/mount.h> #include <sys/filedesc.h> #include <sys/proc.h> +#include <sys/syscallsubr.h> #ifdef KTRACE #include <sys/ktrace.h> #endif @@ -807,3 +808,115 @@ bad: *vpp = NULL; return (error); } + +/* + * Determine if there is a suitable alternate filename under the specified + * prefix for the specified path. If the create flag is set, then the + * alternate prefix will be used so long as the parent directory exists. + * This is used by the various compatiblity ABIs so that Linux binaries prefer + * files under /compat/linux for example. The chosen path (whether under + * the prefix or under /) is returned in a kernel malloc'd buffer pointed + * to by pathbuf. The caller is responsible for free'ing the buffer from + * the M_TEMP bucket if one is returned. + */ +int +kern_alternate_path(struct thread *td, const char *prefix, char *path, + enum uio_seg pathseg, char **pathbuf, int create) +{ + struct nameidata nd, ndroot; + char *ptr, *buf, *cp; + size_t len, sz; + int error; + + buf = (char *) malloc(MAXPATHLEN, M_TEMP, M_WAITOK); + *pathbuf = buf; + + /* Copy the prefix into the new pathname as a starting point. */ + len = strlcpy(buf, prefix, MAXPATHLEN); + if (len >= MAXPATHLEN) { + *pathbuf = NULL; + free(buf, M_TEMP); + return (EINVAL); + } + sz = MAXPATHLEN - len; + ptr = buf + len; + + /* Append the filename to the prefix. */ + if (pathseg == UIO_SYSSPACE) + error = copystr(path, ptr, sz, &len); + else + error = copyinstr(path, ptr, sz, &len); + + if (error) { + *pathbuf = NULL; + free(buf, M_TEMP); + return (error); + } + + /* Only use a prefix with absolute pathnames. */ + if (*ptr != '/') { + error = EINVAL; + goto keeporig; + } + + /* XXX: VFS_LOCK_GIANT? */ + mtx_lock(&Giant); + + /* + * We know that there is a / somewhere in this pathname. + * Search backwards for it, to find the file's parent dir + * to see if it exists in the alternate tree. If it does, + * and we want to create a file (cflag is set). We don't + * need to worry about the root comparison in this case. + */ + + if (create) { + for (cp = &ptr[len] - 1; *cp != '/'; cp--); + *cp = '\0'; + + NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, buf, td); + error = namei(&nd); + *cp = '/'; + if (error != 0) + goto nd_failed; + } else { + NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, buf, td); + + error = namei(&nd); + if (error != 0) + goto nd_failed; + + /* + * We now compare the vnode of the prefix to the one + * vnode asked. If they resolve to be the same, then we + * ignore the match so that the real root gets used. + * This avoids the problem of traversing "../.." to find the + * root directory and never finding it, because "/" resolves + * to the emulation root directory. This is expensive :-( + */ + NDINIT(&ndroot, LOOKUP, FOLLOW, UIO_SYSSPACE, prefix, td); + + /* We shouldn't ever get an error from this namei(). */ + error = namei(&ndroot); + if (error == 0) { + if (nd.ni_vp == ndroot.ni_vp) + error = ENOENT; + + NDFREE(&ndroot, NDF_ONLY_PNBUF); + vrele(ndroot.ni_vp); + } + } + + NDFREE(&nd, NDF_ONLY_PNBUF); + vrele(nd.ni_vp); + +nd_failed: + /* XXX: VFS_UNLOCK_GIANT? */ + mtx_unlock(&Giant); + +keeporig: + /* If there was an error, use the original path name. */ + if (error) + bcopy(ptr, buf, len); + return (error); +} diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 0fc6a4ef6961..cfefd08d97ef 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -221,13 +221,26 @@ statfs(td, uap) struct statfs *buf; } */ *uap; { + struct statfs sf; + int error; + + error = kern_statfs(td, uap->path, UIO_USERSPACE, &sf); + if (error == 0) + error = copyout(&sf, uap->buf, sizeof(sf)); + return (error); +} + +int +kern_statfs(struct thread *td, char *path, enum uio_seg pathseg, + struct statfs *buf) +{ struct mount *mp; struct statfs *sp, sb; int error; struct nameidata nd; mtx_lock(&Giant); - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td); + NDINIT(&nd, LOOKUP, FOLLOW, pathseg, path, td); if ((error = namei(&nd)) != 0) { mtx_unlock(&Giant); return (error); @@ -258,7 +271,8 @@ statfs(td, uap) sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; sp = &sb; } - return (copyout(sp, uap->buf, sizeof(*sp))); + *buf = *sp; + return (0); } /* @@ -278,12 +292,24 @@ fstatfs(td, uap) struct statfs *buf; } */ *uap; { + struct statfs sf; + int error; + + error = kern_fstatfs(td, uap->fd, &sf); + if (error == 0) + error = copyout(&sf, uap->buf, sizeof(sf)); + return (error); +} + +int +kern_fstatfs(struct thread *td, int fd, struct statfs *buf) +{ struct file *fp; struct mount *mp; struct statfs *sp, sb; int error; - if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0) + if ((error = getvnode(td->td_proc->p_fd, fd, &fp)) != 0) return (error); mtx_lock(&Giant); mp = fp->f_vnode->v_mount; @@ -315,7 +341,8 @@ fstatfs(td, uap) sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0; sp = &sb; } - return (copyout(sp, uap->buf, sizeof(*sp))); + *buf = *sp; + return (0); } /* @@ -431,29 +458,14 @@ freebsd4_statfs(td, uap) struct ostatfs *buf; } */ *uap; { - struct mount *mp; - struct statfs *sp; struct ostatfs osb; + struct statfs sf; int error; - struct nameidata nd; - NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td); - if ((error = namei(&nd)) != 0) - return (error); - mp = nd.ni_vp->v_mount; - sp = &mp->mnt_stat; - NDFREE(&nd, NDF_ONLY_PNBUF); - vrele(nd.ni_vp); -#ifdef MAC - error = mac_check_mount_stat(td->td_ucred, mp); - if (error) - return (error); -#endif - error = VFS_STATFS(mp, sp, td); + error = kern_statfs(td, uap->path, UIO_USERSPACE, &sf); if (error) return (error); - sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; - cvtstatfs(td, sp, &osb); + cvtstatfs(td, &sf, &osb); return (copyout(&osb, uap->buf, sizeof(osb))); } @@ -474,29 +486,14 @@ freebsd4_fstatfs(td, uap) struct ostatfs *buf; } */ *uap; { - struct file *fp; - struct mount *mp; - struct statfs *sp; struct ostatfs osb; + struct statfs sf; int error; - if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0) - return (error); - mp = fp->f_vnode->v_mount; - fdrop(fp, td); - if (mp == NULL) - return (EBADF); -#ifdef MAC - error = mac_check_mount_stat(td->td_ucred, mp); - if (error) - return (error); -#endif - sp = &mp->mnt_stat; - error = VFS_STATFS(mp, sp, td); + error = kern_fstatfs(td, uap->fd, &sf); if (error) return (error); - sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; - cvtstatfs(td, sp, &osb); + cvtstatfs(td, &sf, &osb); return (copyout(&osb, uap->buf, sizeof(osb))); } @@ -598,34 +595,17 @@ freebsd4_fhstatfs(td, uap) struct ostatfs *buf; } */ *uap; { - struct statfs *sp; - struct mount *mp; - struct vnode *vp; struct ostatfs osb; + struct statfs sf; fhandle_t fh; int error; - error = suser(td); - if (error) - return (error); if ((error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t))) != 0) return (error); - if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) - return (ESTALE); - if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp))) - return (error); - mp = vp->v_mount; - sp = &mp->mnt_stat; - vput(vp); -#ifdef MAC - error = mac_check_mount_stat(td->td_ucred, mp); + error = kern_fhstatfs(td, fh, &sf); if (error) return (error); -#endif - if ((error = VFS_STATFS(mp, sp, td)) != 0) - return (error); - sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; - cvtstatfs(td, sp, &osb); + cvtstatfs(td, &sf, &osb); return (copyout(&osb, uap->buf, sizeof(osb))); } @@ -1972,15 +1952,8 @@ ostat(td, uap) struct stat sb; struct ostat osb; int error; - struct nameidata nd; - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, - uap->path, td); - if ((error = namei(&nd)) != 0) - return (error); - NDFREE(&nd, NDF_ONLY_PNBUF); - error = vn_stat(nd.ni_vp, &sb, td->td_ucred, NOCRED, td); - vput(nd.ni_vp); + error = kern_stat(td, uap->path, UIO_USERSPACE, &sb); if (error) return (error); cvtstat(&sb, &osb); @@ -2005,20 +1978,11 @@ olstat(td, uap) struct ostat *ub; } */ *uap; { - struct vnode *vp; struct stat sb; struct ostat osb; int error; - struct nameidata nd; - NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, - uap->path, td); - if ((error = namei(&nd)) != 0) - return (error); - vp = nd.ni_vp; - error = vn_stat(vp, &sb, td->td_ucred, NOCRED, td); - NDFREE(&nd, NDF_ONLY_PNBUF); - vput(vp); + error = kern_lstat(td, uap->path, UIO_USERSPACE, &sb); if (error) return (error); cvtstat(&sb, &osb); @@ -2075,15 +2039,26 @@ stat(td, uap) { struct stat sb; int error; + + error = kern_stat(td, uap->path, UIO_USERSPACE, &sb); + if (error == 0) + error = copyout(&sb, uap->ub, sizeof (sb)); + return (error); +} + +int +kern_stat(struct thread *td, char *path, enum uio_seg pathseg, struct stat *sbp) +{ struct nameidata nd; - int vfslocked; + struct stat sb; + int error, vfslocked; #ifdef LOOKUP_SHARED NDINIT(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | NOOBJ | MPSAFE, - UIO_USERSPACE, uap->path, td); + pathseg, path, td); #else - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ | MPSAFE, UIO_USERSPACE, - uap->path, td); + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ | MPSAFE, pathseg, path, + td); #endif if ((error = namei(&nd)) != 0) return (error); @@ -2094,8 +2069,8 @@ stat(td, uap) VFS_UNLOCK_GIANT(vfslocked); if (error) return (error); - error = copyout(&sb, uap->ub, sizeof (sb)); - return (error); + *sbp = sb; + return (0); } /* @@ -2115,14 +2090,26 @@ lstat(td, uap) struct stat *ub; } */ *uap; { + struct stat sb; int error; + + error = kern_lstat(td, uap->path, UIO_USERSPACE, &sb); + if (error == 0) + error = copyout(&sb, uap->ub, sizeof (sb)); + return (error); +} + +int +kern_lstat(struct thread *td, char *path, enum uio_seg pathseg, struct stat *sbp) +{ struct vnode *vp; struct stat sb; struct nameidata nd; - int vfslocked; + int error, vfslocked; + /* XXX LOOKUP_SHARED? */ NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ | MPSAFE, - UIO_USERSPACE, uap->path, td); + pathseg, path, td); if ((error = namei(&nd)) != 0) return (error); vfslocked = NDHASGIANT(&nd); @@ -2133,16 +2120,12 @@ lstat(td, uap) VFS_UNLOCK_GIANT(vfslocked); if (error) return (error); - error = copyout(&sb, uap->ub, sizeof (sb)); - return (error); + *sbp = sb; + return (0); } /* - * Implementation of the NetBSD stat() function. - * XXX This should probably be collapsed with the FreeBSD version, - * as the differences are only due to vn_stat() clearing spares at - * the end of the structures. vn_stat could be split to avoid this, - * and thus collapse the following to close to zero code. + * Implementation of the NetBSD [l]stat() functions. */ void cvtnstat(sb, nsb) @@ -2185,18 +2168,8 @@ nstat(td, uap) struct stat sb; struct nstat nsb; int error; - struct nameidata nd; - int vfslocked; - NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ | MPSAFE, UIO_USERSPACE, - uap->path, td); - if ((error = namei(&nd)) != 0) - return (error); - vfslocked = NDHASGIANT(&nd); - NDFREE(&nd, NDF_ONLY_PNBUF); - error = vn_stat(nd.ni_vp, &sb, td->td_ucred, NOCRED, td); - vput(nd.ni_vp); - VFS_UNLOCK_GIANT(vfslocked); + error = kern_stat(td, uap->path, UIO_USERSPACE, &sb); if (error) return (error); cvtnstat(&sb, &nsb); @@ -2221,23 +2194,11 @@ nlstat(td, uap) struct nstat *ub; } */ *uap; { - int error; - struct vnode *vp; struct stat sb; struct nstat nsb; - struct nameidata nd; - int vfslocked; + int error; - NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ | MPSAFE, - UIO_USERSPACE, uap->path, td); - if ((error = namei(&nd)) != 0) - return (error); - vfslocked = NDHASGIANT(&nd); - vp = nd.ni_vp; - NDFREE(&nd, NDF_ONLY_PNBUF); - error = vn_stat(vp, &sb, td->td_ucred, NOCRED, td); - vput(vp); - VFS_UNLOCK_GIANT(vfslocked); + error = kern_lstat(td, uap->path, UIO_USERSPACE, &sb); if (error) return (error); cvtnstat(&sb, &nsb); @@ -4234,17 +4195,29 @@ fhstatfs(td, uap) struct statfs *buf; } */ *uap; { + struct statfs sf; + fhandle_t fh; + int error; + + if ((error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t))) != 0) + return (error); + error = kern_fhstatfs(td, fh, &sf); + if (error == 0) + error = copyout(&sf, uap->buf, sizeof(sf)); + return (error); +} + +int +kern_fhstatfs(struct thread *td, fhandle_t fh, struct statfs *buf) +{ struct statfs *sp; struct mount *mp; struct vnode *vp; - fhandle_t fh; int error; error = suser(td); if (error) return (error); - if ((error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t))) != 0) - return (error); if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL) return (ESTALE); if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp))) @@ -4265,7 +4238,8 @@ fhstatfs(td, uap) sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; if ((error = VFS_STATFS(mp, sp, td)) != 0) return (error); - return (copyout(sp, uap->buf, sizeof(*sp))); + *buf = *sp; + return (0); } /* diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h index 57bed2c50ac3..74ee11eb21a3 100644 --- a/sys/sys/syscallsubr.h +++ b/sys/sys/syscallsubr.h @@ -32,20 +32,24 @@ #include <sys/uio.h> #include <sys/socket.h> #include <sys/mac.h> +#include <sys/mount.h> +struct itimerval; +struct image_args; struct mbuf; struct msghdr; +struct msqid_ds; struct rlimit; struct rusage; struct sockaddr; -struct itimerval; -struct msqid_ds; -struct image_args; +struct stat; int kern___getcwd(struct thread *td, u_char *buf, enum uio_seg bufseg, u_int buflen); int kern_access(struct thread *td, char *path, enum uio_seg pathseg, int flags); +int kern_alternate_path(struct thread *td, const char *prefix, char *path, + enum uio_seg pathseg, char **pathbuf, int create); int kern_bind(struct thread *td, int fd, struct sockaddr *sa); int kern_chdir(struct thread *td, char *path, enum uio_seg pathseg); int kern_chmod(struct thread *td, char *path, enum uio_seg pathseg, @@ -56,6 +60,9 @@ int kern_connect(struct thread *td, int fd, struct sockaddr *sa); int kern_execve(struct thread *td, struct image_args *args, struct mac *mac_p); int kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg); +int kern_fhstatfs(struct thread *td, fhandle_t fh, struct statfs *buf); +int kern_fstat(struct thread *td, int fd, struct stat *sbp); +int kern_fstatfs(struct thread *td, int fd, struct statfs *buf); int kern_futimes(struct thread *td, int fd, struct timeval *tptr, enum uio_seg tptrseg); int kern_getitimer(struct thread *, u_int, struct itimerval *); @@ -66,6 +73,8 @@ int kern_lchown(struct thread *td, char *path, enum uio_seg pathseg, int uid, int gid); int kern_link(struct thread *td, char *path, char *link, enum uio_seg segflg); +int kern_lstat(struct thread *td, char *path, enum uio_seg pathseg, + struct stat *sbp); int kern_lutimes(struct thread *td, char *path, enum uio_seg pathseg, struct timeval *tptr, enum uio_seg tptrseg); int kern_mkdir(struct thread *td, char *path, enum uio_seg segflg, @@ -74,8 +83,7 @@ int kern_mkfifo(struct thread *td, char *path, enum uio_seg pathseg, int mode); int kern_mknod(struct thread *td, char *path, enum uio_seg pathseg, int mode, int dev); -int kern_msgctl(struct thread *, int, int, struct msqid_ds *, - struct msqid_ds **); +int kern_msgctl(struct thread *, int, int, struct msqid_ds *); int kern_nanosleep(struct thread *td, struct timespec *rqt, struct timespec *rmt); int kern_open(struct thread *td, char *path, enum uio_seg pathseg, @@ -106,6 +114,10 @@ int kern_sigaltstack(struct thread *td, stack_t *ss, stack_t *oss); int kern_sigprocmask(struct thread *td, int how, sigset_t *set, sigset_t *oset, int old); int kern_sigsuspend(struct thread *td, sigset_t mask); +int kern_stat(struct thread *td, char *path, enum uio_seg pathseg, + struct stat *sbp); +int kern_statfs(struct thread *td, char *path, enum uio_seg pathseg, + struct statfs *buf); int kern_symlink(struct thread *td, char *path, char *link, enum uio_seg segflg); int kern_truncate(struct thread *td, char *path, enum uio_seg pathseg, |