From 4cd12ae4adcc6f21e6e9f792cbbffbc84ca3c241 Mon Sep 17 00:00:00 2001 From: cvs2svn Date: Wed, 23 Aug 2000 11:54:11 +0000 Subject: This commit was manufactured by cvs2svn to create branch 'RELENG_4'. --- sys/compat/linux/linux_file.c | 859 +++++++++++++++++++++++++++++++++++++++++ sys/compat/linux/linux_ipc.c | 447 +++++++++++++++++++++ sys/compat/linux/linux_stats.c | 377 ++++++++++++++++++ sys/compat/linux/linux_util.c | 186 +++++++++ 4 files changed, 1869 insertions(+) create mode 100644 sys/compat/linux/linux_file.c create mode 100644 sys/compat/linux/linux_ipc.c create mode 100644 sys/compat/linux/linux_stats.c create mode 100644 sys/compat/linux/linux_util.c (limited to 'sys/compat') diff --git a/sys/compat/linux/linux_file.c b/sys/compat/linux/linux_file.c new file mode 100644 index 000000000000..66e80c60a68b --- /dev/null +++ b/sys/compat/linux/linux_file.c @@ -0,0 +1,859 @@ +/*- + * Copyright (c) 1994-1995 Søren Schmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include "opt_compat.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +int +linux_creat(struct proc *p, struct linux_creat_args *args) +{ + struct open_args /* { + char *path; + int flags; + int mode; + } */ bsd_open_args; + caddr_t sg; + + sg = stackgap_init(); + CHECKALTCREAT(p, &sg, args->path); + +#ifdef DEBUG + printf("Linux-emul(%d): creat(%s, %d)\n", + p->p_pid, args->path, args->mode); +#endif + bsd_open_args.path = args->path; + bsd_open_args.mode = args->mode; + bsd_open_args.flags = O_WRONLY | O_CREAT | O_TRUNC; + return open(p, &bsd_open_args); +} + +int +linux_open(struct proc *p, struct linux_open_args *args) +{ + struct open_args /* { + char *path; + int flags; + int mode; + } */ bsd_open_args; + int error; + caddr_t sg; + + sg = stackgap_init(); + + if (args->flags & LINUX_O_CREAT) + CHECKALTCREAT(p, &sg, args->path); + else + CHECKALTEXIST(p, &sg, args->path); + +#ifdef DEBUG + printf("Linux-emul(%d): open(%s, 0x%x, 0x%x)\n", + p->p_pid, args->path, args->flags, args->mode); +#endif + bsd_open_args.flags = 0; + if (args->flags & LINUX_O_RDONLY) + bsd_open_args.flags |= O_RDONLY; + if (args->flags & LINUX_O_WRONLY) + bsd_open_args.flags |= O_WRONLY; + if (args->flags & LINUX_O_RDWR) + bsd_open_args.flags |= O_RDWR; + if (args->flags & LINUX_O_NDELAY) + bsd_open_args.flags |= O_NONBLOCK; + if (args->flags & LINUX_O_APPEND) + bsd_open_args.flags |= O_APPEND; + if (args->flags & LINUX_O_SYNC) + bsd_open_args.flags |= O_FSYNC; + if (args->flags & LINUX_O_NONBLOCK) + bsd_open_args.flags |= O_NONBLOCK; + if (args->flags & LINUX_FASYNC) + bsd_open_args.flags |= O_ASYNC; + if (args->flags & LINUX_O_CREAT) + bsd_open_args.flags |= O_CREAT; + if (args->flags & LINUX_O_TRUNC) + bsd_open_args.flags |= O_TRUNC; + if (args->flags & LINUX_O_EXCL) + bsd_open_args.flags |= O_EXCL; + if (args->flags & LINUX_O_NOCTTY) + bsd_open_args.flags |= O_NOCTTY; + bsd_open_args.path = args->path; + bsd_open_args.mode = args->mode; + + error = open(p, &bsd_open_args); + if (!error && !(bsd_open_args.flags & O_NOCTTY) && + SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) { + struct filedesc *fdp = p->p_fd; + struct file *fp = fdp->fd_ofiles[p->p_retval[0]]; + + if (fp->f_type == DTYPE_VNODE) + fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0, p); + } +#ifdef DEBUG + printf("Linux-emul(%d): open returns error %d\n", + p->p_pid, error); +#endif + return error; +} + +struct linux_flock { + short l_type; + short l_whence; + linux_off_t l_start; + linux_off_t l_len; + linux_pid_t l_pid; +}; + +static void +linux_to_bsd_flock(struct linux_flock *linux_flock, struct flock *bsd_flock) +{ + switch (linux_flock->l_type) { + case LINUX_F_RDLCK: + bsd_flock->l_type = F_RDLCK; + break; + case LINUX_F_WRLCK: + bsd_flock->l_type = F_WRLCK; + break; + case LINUX_F_UNLCK: + bsd_flock->l_type = F_UNLCK; + break; + default: + bsd_flock->l_type = -1; + break; + } + bsd_flock->l_whence = linux_flock->l_whence; + bsd_flock->l_start = (off_t)linux_flock->l_start; + bsd_flock->l_len = (off_t)linux_flock->l_len; + bsd_flock->l_pid = (pid_t)linux_flock->l_pid; +} + +static void +bsd_to_linux_flock(struct flock *bsd_flock, struct linux_flock *linux_flock) +{ + switch (bsd_flock->l_type) { + case F_RDLCK: + linux_flock->l_type = LINUX_F_RDLCK; + break; + case F_WRLCK: + linux_flock->l_type = LINUX_F_WRLCK; + break; + case F_UNLCK: + linux_flock->l_type = LINUX_F_UNLCK; + break; + } + linux_flock->l_whence = bsd_flock->l_whence; + linux_flock->l_start = (linux_off_t)bsd_flock->l_start; + linux_flock->l_len = (linux_off_t)bsd_flock->l_len; + linux_flock->l_pid = (linux_pid_t)bsd_flock->l_pid; +} + +int +linux_fcntl(struct proc *p, struct linux_fcntl_args *args) +{ + int error, result; + struct fcntl_args /* { + int fd; + int cmd; + int arg; + } */ fcntl_args; + struct linux_flock linux_flock; + struct flock *bsd_flock; + caddr_t sg; + + sg = stackgap_init(); + bsd_flock = (struct flock *)stackgap_alloc(&sg, sizeof(struct flock)); + +#ifdef DEBUG + printf("Linux-emul(%d): fcntl(%d, %08x, *)\n", + p->p_pid, args->fd, args->cmd); +#endif + fcntl_args.fd = args->fd; + + switch (args->cmd) { + case LINUX_F_DUPFD: + fcntl_args.cmd = F_DUPFD; + fcntl_args.arg = args->arg; + return fcntl(p, &fcntl_args); + + case LINUX_F_GETFD: + fcntl_args.cmd = F_GETFD; + return fcntl(p, &fcntl_args); + + case LINUX_F_SETFD: + fcntl_args.cmd = F_SETFD; + fcntl_args.arg = args->arg; + return fcntl(p, &fcntl_args); + + case LINUX_F_GETFL: + fcntl_args.cmd = F_GETFL; + error = fcntl(p, &fcntl_args); + result = p->p_retval[0]; + p->p_retval[0] = 0; + if (result & O_RDONLY) p->p_retval[0] |= LINUX_O_RDONLY; + if (result & O_WRONLY) p->p_retval[0] |= LINUX_O_WRONLY; + if (result & O_RDWR) p->p_retval[0] |= LINUX_O_RDWR; + if (result & O_NDELAY) p->p_retval[0] |= LINUX_O_NONBLOCK; + if (result & O_APPEND) p->p_retval[0] |= LINUX_O_APPEND; + if (result & O_FSYNC) p->p_retval[0] |= LINUX_O_SYNC; + if (result & O_ASYNC) p->p_retval[0] |= LINUX_FASYNC; + return error; + + case LINUX_F_SETFL: + fcntl_args.arg = 0; + if (args->arg & LINUX_O_NDELAY) fcntl_args.arg |= O_NONBLOCK; + if (args->arg & LINUX_O_APPEND) fcntl_args.arg |= O_APPEND; + if (args->arg & LINUX_O_SYNC) fcntl_args.arg |= O_FSYNC; + if (args->arg & LINUX_FASYNC) fcntl_args.arg |= O_ASYNC; + fcntl_args.cmd = F_SETFL; + return fcntl(p, &fcntl_args); + + case LINUX_F_GETLK: + if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock, + sizeof(struct linux_flock)))) + return error; + linux_to_bsd_flock(&linux_flock, bsd_flock); + fcntl_args.cmd = F_GETLK; + fcntl_args.arg = (int)bsd_flock; + error = fcntl(p, &fcntl_args); + if (error) + return error; + bsd_to_linux_flock(bsd_flock, &linux_flock); + return copyout((caddr_t)&linux_flock, (caddr_t)args->arg, + sizeof(struct linux_flock)); + + case LINUX_F_SETLK: + if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock, + sizeof(struct linux_flock)))) + return error; + linux_to_bsd_flock(&linux_flock, bsd_flock); + fcntl_args.cmd = F_SETLK; + fcntl_args.arg = (int)bsd_flock; + return fcntl(p, &fcntl_args); + + case LINUX_F_SETLKW: + if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock, + sizeof(struct linux_flock)))) + return error; + linux_to_bsd_flock(&linux_flock, bsd_flock); + fcntl_args.cmd = F_SETLKW; + fcntl_args.arg = (int)bsd_flock; + return fcntl(p, &fcntl_args); + + case LINUX_F_GETOWN: + fcntl_args.cmd = F_GETOWN; + return fcntl(p, &fcntl_args); + + case LINUX_F_SETOWN: + fcntl_args.cmd = F_SETOWN; + fcntl_args.arg = args->arg; + return fcntl(p, &fcntl_args); + } + return EINVAL; +} + +int +linux_lseek(struct proc *p, struct linux_lseek_args *args) +{ + + struct lseek_args /* { + int fd; + int pad; + off_t offset; + int whence; + } */ tmp_args; + int error; + +#ifdef DEBUG + printf("Linux-emul(%ld): lseek(%d, %ld, %d)\n", + (long)p->p_pid, args->fdes, args->off, args->whence); +#endif + tmp_args.fd = args->fdes; + tmp_args.offset = (off_t)args->off; + tmp_args.whence = args->whence; + error = lseek(p, &tmp_args); + return error; +} + +int +linux_llseek(struct proc *p, struct linux_llseek_args *args) +{ + struct lseek_args bsd_args; + int error; + off_t off; + +#ifdef DEBUG + printf("Linux-emul(%d): llseek(%d, %d:%d, %d)\n", + p->p_pid, args->fd, args->ohigh, args->olow, args->whence); +#endif + off = (args->olow) | (((off_t) args->ohigh) << 32); + + bsd_args.fd = args->fd; + bsd_args.offset = off; + bsd_args.whence = args->whence; + + if ((error = lseek(p, &bsd_args))) + return error; + + if ((error = copyout(p->p_retval, (caddr_t)args->res, sizeof (off_t)))) + return error; + + p->p_retval[0] = 0; + return 0; +} + + +struct linux_dirent { + long dino; + linux_off_t doff; + unsigned short dreclen; + char dname[LINUX_NAME_MAX + 1]; +}; + +#define LINUX_RECLEN(de,namlen) \ + ALIGN((((char *)&(de)->dname - (char *)de) + (namlen) + 1)) + +int +linux_readdir(struct proc *p, struct linux_readdir_args *args) +{ + struct linux_getdents_args lda; + + lda.fd = args->fd; + lda.dent = args->dent; + lda.count = 1; + return linux_getdents(p, &lda); +} + +int +linux_getdents(struct proc *p, struct linux_getdents_args *args) +{ + register struct dirent *bdp; + struct vnode *vp; + caddr_t inp, buf; /* BSD-format */ + int len, reclen; /* BSD-format */ + caddr_t outp; /* Linux-format */ + int resid, linuxreclen=0; /* Linux-format */ + struct file *fp; + struct uio auio; + struct iovec aiov; + struct vattr va; + off_t off; + struct linux_dirent linux_dirent; + int buflen, error, eofflag, nbytes, justone; + u_long *cookies = NULL, *cookiep; + int ncookies; + +#ifdef DEBUG + printf("Linux-emul(%d): getdents(%d, *, %d)\n", + p->p_pid, args->fd, args->count); +#endif + if ((error = getvnode(p->p_fd, args->fd, &fp)) != 0) { + return (error); + } + + if ((fp->f_flag & FREAD) == 0) + return (EBADF); + + vp = (struct vnode *) fp->f_data; + + if (vp->v_type != VDIR) + return (EINVAL); + + if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p))) { + return error; + } + + nbytes = args->count; + if (nbytes == 1) { + nbytes = sizeof (struct linux_dirent); + justone = 1; + } + else + justone = 0; + + off = fp->f_offset; +#define DIRBLKSIZ 512 /* XXX we used to use ufs's DIRBLKSIZ */ + buflen = max(DIRBLKSIZ, nbytes); + buflen = min(buflen, MAXBSIZE); + buf = malloc(buflen, M_TEMP, M_WAITOK); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); +again: + aiov.iov_base = buf; + aiov.iov_len = buflen; + auio.uio_iov = &aiov; + auio.uio_iovcnt = 1; + auio.uio_rw = UIO_READ; + auio.uio_segflg = UIO_SYSSPACE; + auio.uio_procp = p; + auio.uio_resid = buflen; + auio.uio_offset = off; + + if (cookies) { + free(cookies, M_TEMP); + cookies = NULL; + } + + error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, &cookies); + if (error) { + goto out; + } + + inp = buf; + outp = (caddr_t) args->dent; + resid = nbytes; + if ((len = buflen - auio.uio_resid) <= 0) { + goto eof; + } + + cookiep = cookies; + + if (cookies) { + /* + * When using cookies, the vfs has the option of reading from + * a different offset than that supplied (UFS truncates the + * offset to a block boundary to make sure that it never reads + * partway through a directory entry, even if the directory + * has been compacted). + */ + while (len > 0 && ncookies > 0 && *cookiep <= off) { + bdp = (struct dirent *) inp; + len -= bdp->d_reclen; + inp += bdp->d_reclen; + cookiep++; + ncookies--; + } + } + + while (len > 0) { + if (cookiep && ncookies == 0) + break; + bdp = (struct dirent *) inp; + reclen = bdp->d_reclen; + if (reclen & 3) { + printf("linux_readdir: reclen=%d\n", reclen); + error = EFAULT; + goto out; + } + + if (bdp->d_fileno == 0) { + inp += reclen; + if (cookiep) { + off = *cookiep++; + ncookies--; + } else + off += reclen; + len -= reclen; + continue; + } + linuxreclen = LINUX_RECLEN(&linux_dirent, bdp->d_namlen); + if (reclen > len || resid < linuxreclen) { + outp++; + break; + } + linux_dirent.dino = (long) bdp->d_fileno; + if (justone) { + /* + * old linux-style readdir usage. + */ + linux_dirent.doff = (linux_off_t) linuxreclen; + linux_dirent.dreclen = (u_short) bdp->d_namlen; + } else { + linux_dirent.doff = (linux_off_t)(off + reclen); + linux_dirent.dreclen = (u_short) linuxreclen; + } + strcpy(linux_dirent.dname, bdp->d_name); + if ((error = copyout((caddr_t)&linux_dirent, outp, linuxreclen))) { + goto out; + } + inp += reclen; + if (cookiep) { + off = *cookiep++; + ncookies--; + } else + off += reclen; + outp += linuxreclen; + resid -= linuxreclen; + len -= reclen; + if (justone) + break; + } + + if (outp == (caddr_t) args->dent) + goto again; + fp->f_offset = off; + + if (justone) + nbytes = resid + linuxreclen; + +eof: + p->p_retval[0] = nbytes - resid; +out: + if (cookies) + free(cookies, M_TEMP); + VOP_UNLOCK(vp, 0, p); + free(buf, M_TEMP); + return error; +} + +/* + * These exist mainly for hooks for doing /compat/linux translation. + */ + +int +linux_access(struct proc *p, struct linux_access_args *args) +{ + struct access_args bsd; + caddr_t sg; + + sg = stackgap_init(); + CHECKALTEXIST(p, &sg, args->path); + +#ifdef DEBUG + printf("Linux-emul(%d): access(%s, %d)\n", + p->p_pid, args->path, args->flags); +#endif + bsd.path = args->path; + bsd.flags = args->flags; + + return access(p, &bsd); +} + +int +linux_unlink(struct proc *p, struct linux_unlink_args *args) +{ + struct unlink_args bsd; + caddr_t sg; + + sg = stackgap_init(); + CHECKALTEXIST(p, &sg, args->path); + +#ifdef DEBUG + printf("Linux-emul(%d): unlink(%s)\n", + p->p_pid, args->path); +#endif + bsd.path = args->path; + + return unlink(p, &bsd); +} + +int +linux_chdir(struct proc *p, struct linux_chdir_args *args) +{ + struct chdir_args bsd; + caddr_t sg; + + sg = stackgap_init(); + CHECKALTEXIST(p, &sg, args->path); + +#ifdef DEBUG + printf("Linux-emul(%d): chdir(%s)\n", + p->p_pid, args->path); +#endif + bsd.path = args->path; + + return chdir(p, &bsd); +} + +int +linux_chmod(struct proc *p, struct linux_chmod_args *args) +{ + struct chmod_args bsd; + caddr_t sg; + + sg = stackgap_init(); + CHECKALTEXIST(p, &sg, args->path); + +#ifdef DEBUG + printf("Linux-emul(%d): chmod(%s, %d)\n", + p->p_pid, args->path, args->mode); +#endif + bsd.path = args->path; + bsd.mode = args->mode; + + return chmod(p, &bsd); +} + +int +linux_chown(struct proc *p, struct linux_chown_args *args) +{ + struct chown_args bsd; + caddr_t sg; + + sg = stackgap_init(); + CHECKALTEXIST(p, &sg, args->path); + +#ifdef DEBUG + printf("Linux-emul(%d): chown(%s, %d, %d)\n", + p->p_pid, args->path, args->uid, args->gid); +#endif + bsd.path = args->path; + /* XXX size casts here */ + bsd.uid = args->uid; + bsd.gid = args->gid; + + return chown(p, &bsd); +} + +int +linux_lchown(struct proc *p, struct linux_lchown_args *args) +{ + struct lchown_args bsd; + caddr_t sg; + + sg = stackgap_init(); + CHECKALTEXIST(p, &sg, args->path); + +#ifdef DEBUG + printf("Linux-emul(%d): lchown(%s, %d, %d)\n", + p->p_pid, args->path, args->uid, args->gid); +#endif + bsd.path = args->path; + /* XXX size casts here */ + bsd.uid = args->uid; + bsd.gid = args->gid; + + return lchown(p, &bsd); +} + +int +linux_mkdir(struct proc *p, struct linux_mkdir_args *args) +{ + struct mkdir_args bsd; + caddr_t sg; + + sg = stackgap_init(); + CHECKALTCREAT(p, &sg, args->path); + +#ifdef DEBUG + printf("Linux-emul(%d): mkdir(%s, %d)\n", + p->p_pid, args->path, args->mode); +#endif + bsd.path = args->path; + bsd.mode = args->mode; + + return mkdir(p, &bsd); +} + +int +linux_rmdir(struct proc *p, struct linux_rmdir_args *args) +{ + struct rmdir_args bsd; + caddr_t sg; + + sg = stackgap_init(); + CHECKALTEXIST(p, &sg, args->path); + +#ifdef DEBUG + printf("Linux-emul(%d): rmdir(%s)\n", + p->p_pid, args->path); +#endif + bsd.path = args->path; + + return rmdir(p, &bsd); +} + +int +linux_rename(struct proc *p, struct linux_rename_args *args) +{ + struct rename_args bsd; + caddr_t sg; + + sg = stackgap_init(); + CHECKALTEXIST(p, &sg, args->from); + CHECKALTCREAT(p, &sg, args->to); + +#ifdef DEBUG + printf("Linux-emul(%d): rename(%s, %s)\n", + p->p_pid, args->from, args->to); +#endif + bsd.from = args->from; + bsd.to = args->to; + + return rename(p, &bsd); +} + +int +linux_symlink(struct proc *p, struct linux_symlink_args *args) +{ + struct symlink_args bsd; + caddr_t sg; + + sg = stackgap_init(); + CHECKALTEXIST(p, &sg, args->path); + CHECKALTCREAT(p, &sg, args->to); + +#ifdef DEBUG + printf("Linux-emul(%d): symlink(%s, %s)\n", + p->p_pid, args->path, args->to); +#endif + bsd.path = args->path; + bsd.link = args->to; + + return symlink(p, &bsd); +} + +int +linux_readlink(struct proc *p, struct linux_readlink_args *args) +{ + struct readlink_args bsd; + caddr_t sg; + + sg = stackgap_init(); + CHECKALTEXIST(p, &sg, args->name); + +#ifdef DEBUG + printf("Linux-emul(%ld): readlink(%s, %p, %d)\n", + (long)p->p_pid, args->name, (void *)args->buf, args->count); +#endif + bsd.path = args->name; + bsd.buf = args->buf; + bsd.count = args->count; + + return readlink(p, &bsd); +} + +int +linux_truncate(struct proc *p, struct linux_truncate_args *args) +{ + struct truncate_args bsd; + caddr_t sg; + + sg = stackgap_init(); + CHECKALTEXIST(p, &sg, args->path); + +#ifdef DEBUG + printf("Linux-emul(%d): truncate(%s, %ld)\n", + p->p_pid, args->path, args->length); +#endif + bsd.path = args->path; + bsd.length = args->length; + + return truncate(p, &bsd); +} + +int +linux_link(struct proc *p, struct linux_link_args *args) +{ + struct link_args bsd; + caddr_t sg; + + sg = stackgap_init(); + CHECKALTEXIST(p, &sg, args->path); + CHECKALTCREAT(p, &sg, args->to); + +#ifdef DEBUG + printf("Linux-emul(%d): link(%s, %s)\n", p->p_pid, args->path, args->to); +#endif + + bsd.path = args->path; + bsd.link = args->to; + + return link(p, &bsd); +} + +int +linux_getcwd(struct proc *p, struct linux_getcwd_args *args) +{ + struct __getcwd_args bsd; + caddr_t sg; + int error, len; + +#ifdef DEBUG + printf("Linux-emul(%ld): getcwd(%p, %ld)\n", (long)p->p_pid, + args->buf, args->bufsize); +#endif + + sg = stackgap_init(); + bsd.buf = stackgap_alloc(&sg, SPARE_USRSPACE); + bsd.buflen = SPARE_USRSPACE; + error = __getcwd(p, &bsd); + if (!error) { + len = strlen(bsd.buf) + 1; + if (len <= args->bufsize) { + p->p_retval[0] = len; + error = copyout(bsd.buf, args->buf, len); + } + else + error = ERANGE; + } + return (error); +} + +int +linux_fdatasync(p, uap) + struct proc *p; + struct linux_fdatasync_args *uap; +{ + struct fsync_args bsd; + + bsd.fd = uap->fd; + return fsync(p, &bsd); +} + +int +linux_pread(p, uap) + struct proc *p; + struct linux_pread_args *uap; +{ + struct pread_args bsd; + + bsd.fd = uap->fd; + bsd.buf = uap->buf; + bsd.nbyte = uap->nbyte; + bsd.offset = uap->offset; + return pread(p, &bsd); +} + +int +linux_pwrite(p, uap) + struct proc *p; + struct linux_pwrite_args *uap; +{ + struct pwrite_args bsd; + + bsd.fd = uap->fd; + bsd.buf = uap->buf; + bsd.nbyte = uap->nbyte; + bsd.offset = uap->offset; + return pwrite(p, &bsd); +} diff --git a/sys/compat/linux/linux_ipc.c b/sys/compat/linux/linux_ipc.c new file mode 100644 index 000000000000..48e13d578277 --- /dev/null +++ b/sys/compat/linux/linux_ipc.c @@ -0,0 +1,447 @@ +/*- + * Copyright (c) 1994-1995 Søren Schmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +struct linux_ipc_perm { + linux_key_t key; + unsigned short uid; + unsigned short gid; + unsigned short cuid; + unsigned short cgid; + unsigned short mode; + unsigned short seq; +}; + +static void +linux_to_bsd_ipc_perm(struct linux_ipc_perm *lpp, struct ipc_perm *bpp) +{ + bpp->key = lpp->key; + bpp->uid = lpp->uid; + bpp->gid = lpp->gid; + bpp->cuid = lpp->cuid; + bpp->cgid = lpp->cgid; + bpp->mode = lpp->mode; + bpp->seq = lpp->seq; +} + + +static void +bsd_to_linux_ipc_perm(struct ipc_perm *bpp, struct linux_ipc_perm *lpp) +{ + lpp->key = bpp->key; + lpp->uid = bpp->uid; + lpp->gid = bpp->gid; + lpp->cuid = bpp->cuid; + lpp->cgid = bpp->cgid; + lpp->mode = bpp->mode; + lpp->seq = bpp->seq; +} + +struct linux_semid_ds { + struct linux_ipc_perm sem_perm; + linux_time_t sem_otime; + linux_time_t sem_ctime; + void *sem_base; + void *sem_pending; + void *sem_pending_last; + void *undo; + ushort sem_nsems; +}; + +struct linux_shmid_ds { + struct linux_ipc_perm shm_perm; + int shm_segsz; + linux_time_t shm_atime; + linux_time_t shm_dtime; + linux_time_t shm_ctime; + ushort shm_cpid; + ushort shm_lpid; + short shm_nattch; + ushort private1; + void *private2; + void *private3; +}; + +static void +linux_to_bsd_semid_ds(struct linux_semid_ds *lsp, struct semid_ds *bsp) +{ + linux_to_bsd_ipc_perm(&lsp->sem_perm, &bsp->sem_perm); + bsp->sem_otime = lsp->sem_otime; + bsp->sem_ctime = lsp->sem_ctime; + bsp->sem_nsems = lsp->sem_nsems; + bsp->sem_base = lsp->sem_base; +} + +static void +bsd_to_linux_semid_ds(struct semid_ds *bsp, struct linux_semid_ds *lsp) +{ + bsd_to_linux_ipc_perm(&bsp->sem_perm, &lsp->sem_perm); + lsp->sem_otime = bsp->sem_otime; + lsp->sem_ctime = bsp->sem_ctime; + lsp->sem_nsems = bsp->sem_nsems; + lsp->sem_base = bsp->sem_base; +} + +static void +linux_to_bsd_shmid_ds(struct linux_shmid_ds *lsp, struct shmid_ds *bsp) +{ + linux_to_bsd_ipc_perm(&lsp->shm_perm, &bsp->shm_perm); + bsp->shm_segsz = lsp->shm_segsz; + bsp->shm_lpid = lsp->shm_lpid; + bsp->shm_cpid = lsp->shm_cpid; + bsp->shm_nattch = lsp->shm_nattch; + bsp->shm_atime = lsp->shm_atime; + bsp->shm_dtime = lsp->shm_dtime; + bsp->shm_ctime = lsp->shm_ctime; + bsp->shm_internal = lsp->private3; /* this goes (yet) SOS */ +} + +static void +bsd_to_linux_shmid_ds(struct shmid_ds *bsp, struct linux_shmid_ds *lsp) +{ + bsd_to_linux_ipc_perm(&bsp->shm_perm, &lsp->shm_perm); + lsp->shm_segsz = bsp->shm_segsz; + lsp->shm_lpid = bsp->shm_lpid; + lsp->shm_cpid = bsp->shm_cpid; + lsp->shm_nattch = bsp->shm_nattch; + lsp->shm_atime = bsp->shm_atime; + lsp->shm_dtime = bsp->shm_dtime; + lsp->shm_ctime = bsp->shm_ctime; + lsp->private3 = bsp->shm_internal; /* this goes (yet) SOS */ +} + +int +linux_semop(struct proc *p, struct linux_ipc_args *args) +{ + struct semop_args /* { + int semid; + struct sembuf *sops; + int nsops; + } */ bsd_args; + + bsd_args.semid = args->arg1; + bsd_args.sops = (struct sembuf *)args->ptr; + bsd_args.nsops = args->arg2; + return semop(p, &bsd_args); +} + +int +linux_semget(struct proc *p, struct linux_ipc_args *args) +{ + struct semget_args /* { + key_t key; + int nsems; + int semflg; + } */ bsd_args; + + bsd_args.key = args->arg1; + bsd_args.nsems = args->arg2; + bsd_args.semflg = args->arg3; + return semget(p, &bsd_args); +} + +int +linux_semctl(struct proc *p, struct linux_ipc_args *args) +{ + struct linux_semid_ds linux_semid; + struct semid_ds bsd_semid; + struct __semctl_args /* { + int semid; + int semnum; + int cmd; + union semun *arg; + } */ bsd_args; + int error; + caddr_t sg, unptr, dsp, ldsp; + + sg = stackgap_init(); + bsd_args.semid = args->arg1; + bsd_args.semnum = args->arg2; + bsd_args.cmd = args->arg3; + bsd_args.arg = (union semun *)args->ptr; + + switch (args->arg3) { + case LINUX_IPC_RMID: + bsd_args.cmd = IPC_RMID; + break; + case LINUX_GETNCNT: + bsd_args.cmd = GETNCNT; + break; + case LINUX_GETPID: + bsd_args.cmd = GETPID; + break; + case LINUX_GETVAL: + bsd_args.cmd = GETVAL; + break; + case LINUX_GETZCNT: + bsd_args.cmd = GETZCNT; + break; + case LINUX_SETVAL: + bsd_args.cmd = SETVAL; + break; + case LINUX_IPC_SET: + bsd_args.cmd = IPC_SET; + error = copyin(args->ptr, &ldsp, sizeof(ldsp)); + if (error) + return error; + error = copyin(ldsp, (caddr_t)&linux_semid, sizeof(linux_semid)); + if (error) + return error; + linux_to_bsd_semid_ds(&linux_semid, &bsd_semid); + unptr = stackgap_alloc(&sg, sizeof(union semun)); + dsp = stackgap_alloc(&sg, sizeof(struct semid_ds)); + error = copyout((caddr_t)&bsd_semid, dsp, sizeof(bsd_semid)); + if (error) + return error; + error = copyout((caddr_t)&dsp, unptr, sizeof(dsp)); + if (error) + return error; + bsd_args.arg = (union semun *)unptr; + return __semctl(p, &bsd_args); + case LINUX_IPC_STAT: + bsd_args.cmd = IPC_STAT; + unptr = stackgap_alloc(&sg, sizeof(union semun *)); + dsp = stackgap_alloc(&sg, sizeof(struct semid_ds)); + error = copyout((caddr_t)&dsp, unptr, sizeof(dsp)); + if (error) + return error; + bsd_args.arg = (union semun *)unptr; + error = __semctl(p, &bsd_args); + if (error) + return error; + error = copyin(dsp, (caddr_t)&bsd_semid, sizeof(bsd_semid)); + if (error) + return error; + bsd_to_linux_semid_ds(&bsd_semid, &linux_semid); + error = copyin(args->ptr, &ldsp, sizeof(ldsp)); + if (error) + return error; + return copyout((caddr_t)&linux_semid, ldsp, sizeof(linux_semid)); + case LINUX_GETALL: + /* FALLTHROUGH */ + case LINUX_SETALL: + /* FALLTHROUGH */ + default: + uprintf("LINUX: 'ipc' typ=%d not implemented\n", args->what); + return EINVAL; + } + return __semctl(p, &bsd_args); +} + +int +linux_msgsnd(struct proc *p, struct linux_ipc_args *args) +{ + struct msgsnd_args /* { + int msqid; + void *msgp; + size_t msgsz; + int msgflg; + } */ bsd_args; + + bsd_args.msqid = args->arg1; + bsd_args.msgp = args->ptr; + bsd_args.msgsz = args->arg2; + bsd_args.msgflg = args->arg3; + return msgsnd(p, &bsd_args); +} + +int +linux_msgrcv(struct proc *p, struct linux_ipc_args *args) +{ + struct msgrcv_args /* { + int msqid; + void *msgp; + size_t msgsz; + long msgtyp; + int msgflg; + } */ bsd_args; + + bsd_args.msqid = args->arg1; + bsd_args.msgp = args->ptr; + bsd_args.msgsz = args->arg2; + bsd_args.msgtyp = 0; + bsd_args.msgflg = args->arg3; + return msgrcv(p, &bsd_args); +} + +int +linux_msgget(struct proc *p, struct linux_ipc_args *args) +{ + struct msgget_args /* { + key_t key; + int msgflg; + } */ bsd_args; + + bsd_args.key = args->arg1; + bsd_args.msgflg = args->arg2; + return msgget(p, &bsd_args); +} + +int +linux_msgctl(struct proc *p, struct linux_ipc_args *args) +{ + struct msgctl_args /* { + int msqid; + int cmd; + struct msqid_ds *buf; + } */ bsd_args; + int error; + + bsd_args.msqid = args->arg1; + bsd_args.cmd = args->arg2; + bsd_args.buf = (struct msqid_ds *)args->ptr; + error = msgctl(p, &bsd_args); + return ((args->arg2 == LINUX_IPC_RMID && error == EINVAL) ? 0 : error); +} + +int +linux_shmat(struct proc *p, struct linux_ipc_args *args) +{ + struct shmat_args /* { + int shmid; + void *shmaddr; + int shmflg; + } */ bsd_args; + int error; + + bsd_args.shmid = args->arg1; + bsd_args.shmaddr = args->ptr; + bsd_args.shmflg = args->arg2; + if ((error = shmat(p, &bsd_args))) + return error; + if ((error = copyout(p->p_retval, (caddr_t)args->arg3, sizeof(int)))) + return error; + p->p_retval[0] = 0; + return 0; +} + +int +linux_shmdt(struct proc *p, struct linux_ipc_args *args) +{ + struct shmdt_args /* { + void *shmaddr; + } */ bsd_args; + + bsd_args.shmaddr = args->ptr; + return shmdt(p, &bsd_args); +} + +int +linux_shmget(struct proc *p, struct linux_ipc_args *args) +{ + struct shmget_args /* { + key_t key; + int size; + int shmflg; + } */ bsd_args; + + bsd_args.key = args->arg1; + bsd_args.size = args->arg2; + bsd_args.shmflg = args->arg3; + return shmget(p, &bsd_args); +} + +int +linux_shmctl(struct proc *p, struct linux_ipc_args *args) +{ + struct shmid_ds bsd_shmid; + struct linux_shmid_ds linux_shmid; + struct shmctl_args /* { + int shmid; + int cmd; + struct shmid_ds *buf; + } */ bsd_args; + int error; + caddr_t sg = stackgap_init(); + + switch (args->arg2) { + case LINUX_IPC_STAT: + bsd_args.shmid = args->arg1; + bsd_args.cmd = IPC_STAT; + bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds)); + if ((error = shmctl(p, &bsd_args))) + return error; + if ((error = copyin((caddr_t)bsd_args.buf, (caddr_t)&bsd_shmid, + sizeof(struct shmid_ds)))) + return error; + bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid); + return copyout((caddr_t)&linux_shmid, args->ptr, sizeof(linux_shmid)); + + case LINUX_IPC_SET: + if ((error = copyin(args->ptr, (caddr_t)&linux_shmid, + sizeof(linux_shmid)))) + return error; + linux_to_bsd_shmid_ds(&linux_shmid, &bsd_shmid); + bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds)); + if ((error = copyout((caddr_t)&bsd_shmid, (caddr_t)bsd_args.buf, + sizeof(struct shmid_ds)))) + return error; + bsd_args.shmid = args->arg1; + bsd_args.cmd = IPC_SET; + return shmctl(p, &bsd_args); + + case LINUX_IPC_RMID: + bsd_args.shmid = args->arg1; + bsd_args.cmd = IPC_RMID; + if (NULL == args->ptr) + bsd_args.buf = NULL; + else { + if ((error = copyin(args->ptr, (caddr_t)&linux_shmid, + sizeof(linux_shmid)))) + return error; + linux_to_bsd_shmid_ds(&linux_shmid, &bsd_shmid); + bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds)); + if ((error = copyout((caddr_t)&bsd_shmid, (caddr_t)bsd_args.buf, + sizeof(struct shmid_ds)))) + return error; + } + return shmctl(p, &bsd_args); + + case LINUX_IPC_INFO: + case LINUX_SHM_STAT: + case LINUX_SHM_INFO: + case LINUX_SHM_LOCK: + case LINUX_SHM_UNLOCK: + default: + uprintf("LINUX: 'ipc' typ=%d not implemented\n", args->what); + return EINVAL; + } +} diff --git a/sys/compat/linux/linux_stats.c b/sys/compat/linux/linux_stats.c new file mode 100644 index 000000000000..573cd74d251d --- /dev/null +++ b/sys/compat/linux/linux_stats.c @@ -0,0 +1,377 @@ +/*- + * Copyright (c) 1994-1995 Søren Schmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer + * in this position and unchanged. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software withough specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +struct linux_newstat { + u_short stat_dev; + u_short __pad1; + u_long stat_ino; + u_short stat_mode; + u_short stat_nlink; + u_short stat_uid; + u_short stat_gid; + u_short stat_rdev; + u_short __pad2; + u_long stat_size; + u_long stat_blksize; + u_long stat_blocks; + u_long stat_atime; + u_long __unused1; + u_long stat_mtime; + u_long __unused2; + u_long stat_ctime; + u_long __unused3; + u_long __unused4; + u_long __unused5; +}; + +struct linux_ustat +{ + int f_tfree; + u_long f_tinode; + char f_fname[6]; + char f_fpack[6]; +}; + +static int +newstat_copyout(struct stat *buf, void *ubuf) +{ + struct linux_newstat tbuf; + + tbuf.stat_dev = uminor(buf->st_dev) | (umajor(buf->st_dev) << 8); + tbuf.stat_ino = buf->st_ino; + tbuf.stat_mode = buf->st_mode; + tbuf.stat_nlink = buf->st_nlink; + tbuf.stat_uid = buf->st_uid; + tbuf.stat_gid = buf->st_gid; + tbuf.stat_rdev = buf->st_rdev; + tbuf.stat_size = buf->st_size; + tbuf.stat_atime = buf->st_atime; + tbuf.stat_mtime = buf->st_mtime; + tbuf.stat_ctime = buf->st_ctime; + tbuf.stat_blksize = buf->st_blksize; + tbuf.stat_blocks = buf->st_blocks; + + return (copyout(&tbuf, ubuf, sizeof(tbuf))); +} + +int +linux_newstat(struct proc *p, struct linux_newstat_args *args) +{ + struct stat buf; + struct nameidata nd; + int error; + caddr_t sg; + + sg = stackgap_init(); + CHECKALTEXIST(p, &sg, args->path); + +#ifdef DEBUG + printf("Linux-emul(%ld): newstat(%s, *)\n", (long)p->p_pid, + args->path); +#endif + + NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, + args->path, p); + error = namei(&nd); + if (error) + return (error); + NDFREE(&nd, NDF_ONLY_PNBUF); + + error = vn_stat(nd.ni_vp, &buf, p); + vput(nd.ni_vp); + if (error) + return (error); + + return (newstat_copyout(&buf, args->buf)); +} + +/* + * Get file status; this version does not follow links. + */ +int +linux_newlstat(p, uap) + struct proc *p; + struct linux_newlstat_args *uap; +{ + int error; + struct vnode *vp; + struct stat sb; + struct nameidata nd; + caddr_t sg; + + sg = stackgap_init(); + CHECKALTEXIST(p, &sg, uap->path); + +#ifdef DEBUG + printf("Linux-emul(%ld): newlstat(%s, *)\n", (long)p->p_pid, + uap->path); +#endif + + NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE, + uap->path, p); + error = namei(&nd); + if (error) + return (error); + NDFREE(&nd, NDF_ONLY_PNBUF); + + vp = nd.ni_vp; + error = vn_stat(vp, &sb, p); + vput(vp); + if (error) + return (error); + + return (newstat_copyout(&sb, uap->buf)); +} + +int +linux_newfstat(struct proc *p, struct linux_newfstat_args *args) +{ + struct filedesc *fdp; + struct file *fp; + struct stat buf; + int error; + + fdp = p->p_fd; + +#ifdef DEBUG + printf("Linux-emul(%ld): newfstat(%d, *)\n", (long)p->p_pid, args->fd); +#endif + + if ((unsigned)args->fd >= fdp->fd_nfiles || + (fp = fdp->fd_ofiles[args->fd]) == NULL) + return (EBADF); + + error = fo_stat(fp, &buf, p); + if (!error) + error = newstat_copyout(&buf, args->buf); + + return (error); +} + +struct linux_statfs_buf { + long ftype; + long fbsize; + long fblocks; + long fbfree; + long fbavail; + long ffiles; + long fffree; + linux_fsid_t ffsid; + long fnamelen; + long fspare[6]; +}; + +#ifndef VT_NWFS +#define VT_NWFS VT_TFS /* XXX - bug compatibility with sys/nwfs/nwfs_node.h */ +#endif + +#define LINUX_CODA_SUPER_MAGIC 0x73757245L +#define LINUX_EXT2_SUPER_MAGIC 0xEF53L +#define LINUX_HPFS_SUPER_MAGIC 0xf995e849L +#define LINUX_ISOFS_SUPER_MAGIC 0x9660L +#define LINUX_MSDOS_SUPER_MAGIC 0x4d44L +#define LINUX_NCP_SUPER_MAGIC 0x564cL +#define LINUX_NFS_SUPER_MAGIC 0x6969L +#define LINUX_NTFS_SUPER_MAGIC 0x5346544EL +#define LINUX_PROC_SUPER_MAGIC 0x9fa0L +#define LINUX_UFS_SUPER_MAGIC 0x00011954L /* XXX - UFS_MAGIC in Linux */ + +/* + * ext2fs uses the VT_UFS tag. A mounted ext2 filesystem will therefore + * be seen as an ufs/mfs filesystem. + */ +static long +bsd_to_linux_ftype(int tag) +{ + + switch (tag) { + case VT_CODA: + return (LINUX_CODA_SUPER_MAGIC); + case VT_HPFS: + return (LINUX_HPFS_SUPER_MAGIC); + case VT_ISOFS: + return (LINUX_ISOFS_SUPER_MAGIC); + case VT_MFS: + return (LINUX_UFS_SUPER_MAGIC); + case VT_MSDOSFS: + return (LINUX_MSDOS_SUPER_MAGIC); + case VT_NFS: + return (LINUX_NFS_SUPER_MAGIC); + case VT_NTFS: + return (LINUX_NTFS_SUPER_MAGIC); + case VT_NWFS: + return (LINUX_NCP_SUPER_MAGIC); + case VT_PROCFS: + return (LINUX_PROC_SUPER_MAGIC); + case VT_UFS: + return (LINUX_UFS_SUPER_MAGIC); + } + + return (0L); +} + +int +linux_statfs(struct proc *p, struct linux_statfs_args *args) +{ + struct mount *mp; + struct nameidata *ndp; + struct statfs *bsd_statfs; + struct nameidata nd; + struct linux_statfs_buf linux_statfs_buf; + int error; + caddr_t sg; + + sg = stackgap_init(); + CHECKALTEXIST(p, &sg, args->path); + +#ifdef DEBUG + printf("Linux-emul(%d): statfs(%s, *)\n", p->p_pid, args->path); +#endif + ndp = &nd; + NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args->path, curproc); + error = namei(ndp); + if (error) + return error; + NDFREE(ndp, NDF_ONLY_PNBUF); + mp = ndp->ni_vp->v_mount; + bsd_statfs = &mp->mnt_stat; + vrele(ndp->ni_vp); + error = VFS_STATFS(mp, bsd_statfs, p); + if (error) + return error; + bsd_statfs->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; + linux_statfs_buf.ftype = bsd_to_linux_ftype(bsd_statfs->f_type); + linux_statfs_buf.fbsize = bsd_statfs->f_bsize; + linux_statfs_buf.fblocks = bsd_statfs->f_blocks; + linux_statfs_buf.fbfree = bsd_statfs->f_bfree; + linux_statfs_buf.fbavail = bsd_statfs->f_bavail; + linux_statfs_buf.fffree = bsd_statfs->f_ffree; + linux_statfs_buf.ffiles = bsd_statfs->f_files; + linux_statfs_buf.ffsid.val[0] = bsd_statfs->f_fsid.val[0]; + linux_statfs_buf.ffsid.val[1] = bsd_statfs->f_fsid.val[1]; + linux_statfs_buf.fnamelen = MAXNAMLEN; + return copyout((caddr_t)&linux_statfs_buf, (caddr_t)args->buf, + sizeof(struct linux_statfs_buf)); +} + +int +linux_fstatfs(struct proc *p, struct linux_fstatfs_args *args) +{ + struct file *fp; + struct mount *mp; + struct statfs *bsd_statfs; + struct linux_statfs_buf linux_statfs_buf; + int error; + +#ifdef DEBUG + printf("Linux-emul(%d): fstatfs(%d, *)\n", p->p_pid, args->fd); +#endif + error = getvnode(p->p_fd, args->fd, &fp); + if (error) + return error; + mp = ((struct vnode *)fp->f_data)->v_mount; + bsd_statfs = &mp->mnt_stat; + error = VFS_STATFS(mp, bsd_statfs, p); + if (error) + return error; + bsd_statfs->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; + linux_statfs_buf.ftype = bsd_to_linux_ftype(bsd_statfs->f_type); + linux_statfs_buf.fbsize = bsd_statfs->f_bsize; + linux_statfs_buf.fblocks = bsd_statfs->f_blocks; + linux_statfs_buf.fbfree = bsd_statfs->f_bfree; + linux_statfs_buf.fbavail = bsd_statfs->f_bavail; + linux_statfs_buf.fffree = bsd_statfs->f_ffree; + linux_statfs_buf.ffiles = bsd_statfs->f_files; + linux_statfs_buf.ffsid.val[0] = bsd_statfs->f_fsid.val[0]; + linux_statfs_buf.ffsid.val[1] = bsd_statfs->f_fsid.val[1]; + linux_statfs_buf.fnamelen = MAXNAMLEN; + return copyout((caddr_t)&linux_statfs_buf, (caddr_t)args->buf, + sizeof(struct linux_statfs_buf)); +} + +int +linux_ustat(p, uap) + struct proc *p; + struct linux_ustat_args *uap; +{ + struct linux_ustat lu; + dev_t dev; + struct vnode *vp; + struct statfs *stat; + int error; + +#ifdef DEBUG + printf("Linux-emul(%ld): ustat(%d, *)\n", (long)p->p_pid, uap->dev); +#endif + + /* + * lu.f_fname and lu.f_fpack are not used. They are always zeroed. + * lu.f_tinode and lu.f_tfree are set from the device's super block. + */ + bzero(&lu, sizeof(lu)); + + /* + * XXX - Don't return an error if we can't find a vnode for the + * device. Our dev_t is 32-bits whereas Linux only has a 16-bits + * dev_t. The dev_t that is used now may as well be a truncated + * dev_t returned from previous syscalls. Just return a bzeroed + * ustat in that case. + */ + dev = makebdev(uap->dev >> 8, uap->dev & 0xFF); + if (vfinddev(dev, VBLK, &vp)) { + if (vp->v_mount == NULL) + return (EINVAL); + stat = &(vp->v_mount->mnt_stat); + error = VFS_STATFS(vp->v_mount, stat, p); + if (error) + return (error); + + lu.f_tfree = stat->f_bfree; + lu.f_tinode = stat->f_ffree; + } + + return (copyout(&lu, uap->ubuf, sizeof(lu))); +} diff --git a/sys/compat/linux/linux_util.c b/sys/compat/linux/linux_util.c new file mode 100644 index 000000000000..6399805a3037 --- /dev/null +++ b/sys/compat/linux/linux_util.c @@ -0,0 +1,186 @@ +/* + * Copyright (c) 1994 Christos Zoulas + * Copyright (c) 1995 Frank van der Linden + * Copyright (c) 1995 Scott Bartram + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * from: svr4_util.c,v 1.5 1995/01/22 23:44:50 christos Exp + * $FreeBSD$ + */ + +#include +#include +#include +#include +#include +#include + +#include + +const char linux_emul_path[] = "/compat/linux"; + +/* + * Search an alternate path before passing pathname arguments on + * to system calls. Useful for keeping a seperate 'emulation tree'. + * + * If cflag is set, we check if an attempt can be made to create + * the named file, i.e. we check if the directory it should + * be in exists. + */ +int +linux_emul_find(p, sgp, prefix, path, pbuf, cflag) + struct proc *p; + caddr_t *sgp; /* Pointer to stackgap memory */ + const char *prefix; + char *path; + char **pbuf; + int cflag; +{ + struct nameidata nd; + struct nameidata ndroot; + struct vattr vat; + struct vattr vatroot; + int error; + char *ptr, *buf, *cp; + size_t sz, len; + + buf = (char *) malloc(MAXPATHLEN, M_TEMP, M_WAITOK); + *pbuf = path; + + for (ptr = buf; (*ptr = *prefix) != '\0'; ptr++, prefix++) + continue; + + sz = MAXPATHLEN - (ptr - buf); + + /* + * If sgp is not given then the path is already in kernel space + */ + if (sgp == NULL) + error = copystr(path, ptr, sz, &len); + else + error = copyinstr(path, ptr, sz, &len); + + if (error) { + free(buf, M_TEMP); + return error; + } + + if (*ptr != '/') { + free(buf, M_TEMP); + return EINVAL; + } + + /* + * 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 (cflag) { + for (cp = &ptr[len] - 1; *cp != '/'; cp--); + *cp = '\0'; + + NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, buf, p); + + if ((error = namei(&nd)) != 0) { + free(buf, M_TEMP); + return error; + } + + *cp = '/'; + } + else { + NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, buf, p); + + if ((error = namei(&nd)) != 0) { + free(buf, M_TEMP); + return error; + } + + /* + * We now compare the vnode of the linux_root 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, linux_emul_path, + p); + + if ((error = namei(&ndroot)) != 0) { + /* Cannot happen! */ + free(buf, M_TEMP); + NDFREE(&nd, NDF_ONLY_PNBUF); + vrele(nd.ni_vp); + return error; + } + + if ((error = VOP_GETATTR(nd.ni_vp, &vat, p->p_ucred, p)) != 0) { + goto bad; + } + + if ((error = VOP_GETATTR(ndroot.ni_vp, &vatroot, p->p_ucred, p)) + != 0) { + goto bad; + } + + if (vat.va_fsid == vatroot.va_fsid && + vat.va_fileid == vatroot.va_fileid) { + error = ENOENT; + goto bad; + } + + } + if (sgp == NULL) + *pbuf = buf; + else { + sz = &ptr[len] - buf; + *pbuf = stackgap_alloc(sgp, sz + 1); + if (*pbuf != NULL) + error = copyout(buf, *pbuf, sz); + else + error = ENAMETOOLONG; + free(buf, M_TEMP); + } + + NDFREE(&nd, NDF_ONLY_PNBUF); + vrele(nd.ni_vp); + if (!cflag) { + NDFREE(&ndroot, NDF_ONLY_PNBUF); + vrele(ndroot.ni_vp); + } + return error; + +bad: + NDFREE(&ndroot, NDF_ONLY_PNBUF); + vrele(ndroot.ni_vp); + NDFREE(&nd, NDF_ONLY_PNBUF); + vrele(nd.ni_vp); + free(buf, M_TEMP); + return error; +} -- cgit v1.2.3