From f14ea10694ed07a2d0627c9efa2b79c03b19639d Mon Sep 17 00:00:00 2001 From: sos Date: Sun, 25 Jun 1995 17:32:43 +0000 Subject: First incarnation of our Linux emulator or rather compatibility code. This first shot only incorporaties so much functionality that DOOM can run (the X version), signal handling is VERY weak, so is many other things. But it meets my milestone number one (you guessed it - running DOOM). Uses /compat/linux as prefix for loading shared libs, so it won't conflict with our own libs. Kernel must be compiled with "options COMPAT_LINUX" for this to work. --- sys/compat/linux/linux_file.c | 436 ++++++++++++++++++++++++++ sys/compat/linux/linux_ioctl.c | 495 ++++++++++++++++++++++++++++++ sys/compat/linux/linux_ipc.c | 308 +++++++++++++++++++ sys/compat/linux/linux_misc.c | 660 ++++++++++++++++++++++++++++++++++++++++ sys/compat/linux/linux_signal.c | 259 ++++++++++++++++ sys/compat/linux/linux_socket.c | 595 ++++++++++++++++++++++++++++++++++++ sys/compat/linux/linux_stats.c | 273 +++++++++++++++++ 7 files changed, 3026 insertions(+) create mode 100644 sys/compat/linux/linux_file.c create mode 100644 sys/compat/linux/linux_ioctl.c create mode 100644 sys/compat/linux/linux_ipc.c create mode 100644 sys/compat/linux/linux_misc.c create mode 100644 sys/compat/linux/linux_signal.c create mode 100644 sys/compat/linux/linux_socket.c create mode 100644 sys/compat/linux/linux_stats.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 0000000..b846068 --- /dev/null +++ b/sys/compat/linux/linux_file.c @@ -0,0 +1,436 @@ +/*- + * 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. + * + * $Id: linux_file.c,v 1.2 1995/06/07 21:27:57 sos Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +struct linux_creat_args { + char *path; + int mode; +}; + +int +linux_creat(struct proc *p, struct linux_creat_args *args, int *retval) +{ + struct { + char *path; + int flags; + int mode; + } bsd_open_args; + +#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, retval); +} + +struct linux_open_args { + char *path; + int flags; + int mode; +}; + +int +linux_open(struct proc *p, struct linux_open_args *args, int *retval) +{ + struct { + char *path; + int flags; + int mode; + } bsd_open_args; + int error; + +#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, retval); + 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[*retval]; + + if (fp->f_type == DTYPE_VNODE) + (fp->f_ops->fo_ioctl)(fp, TIOCSCTTY, (caddr_t) 0, p); + } + 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; + } + 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; +} + +struct linux_fcntl_args { + int fd; + int cmd; + int arg; +}; + +int +linux_fcntl(struct proc *p, struct linux_fcntl_args *args, int *retval) +{ + int error, result; + struct fcntl_args { + int fd; + int cmd; + int arg; + } fcntl_args; + struct linux_flock linux_flock; + struct flock *bsd_flock = + (struct flock *)ua_alloc_init(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; + fcntl_args.arg = 0; + + switch (args->cmd) { + case LINUX_F_DUPFD: + fcntl_args.cmd = F_DUPFD; + return fcntl(p, &fcntl_args, retval); + + case LINUX_F_GETFD: + fcntl_args.cmd = F_GETFD; + return fcntl(p, &fcntl_args, retval); + + case LINUX_F_SETFD: + fcntl_args.cmd = F_SETFD; + return fcntl(p, &fcntl_args, retval); + + case LINUX_F_GETFL: + fcntl_args.cmd = F_GETFL; + error = fcntl(p, &fcntl_args, &result); + *retval = 0; + if (result & O_RDONLY) *retval |= LINUX_O_RDONLY; + if (result & O_WRONLY) *retval |= LINUX_O_WRONLY; + if (result & O_RDWR) *retval |= LINUX_O_RDWR; + if (result & O_NDELAY) *retval |= LINUX_O_NONBLOCK; + if (result & O_APPEND) *retval |= LINUX_O_APPEND; + if (result & O_FSYNC) *retval |= LINUX_O_SYNC; + return error; + + case LINUX_F_SETFL: + 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; + fcntl_args.cmd = F_SETFL; + return fcntl(p, &fcntl_args, retval); + + 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; + if (error = fcntl(p, &fcntl_args, retval)) + 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, retval); + + 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, retval); + + case LINUX_F_SETOWN: + fcntl_args.cmd = F_SETOWN; + return fcntl(p, &fcntl_args, retval); + + case LINUX_F_GETOWN: + fcntl_args.cmd = F_GETOWN; + return fcntl(p, &fcntl_args, retval); + } + return EINVAL; +} + +struct linux_lseek_args { + int fdes; + unsigned long off; + int whence; +}; + +int +linux_lseek(struct proc *p, struct linux_lseek_args *args, int *retval) +{ + + struct lseek_args { + int fdes; + int pad; + off_t off; + int whence; + } tmp_args; + off_t tmp_retval; + int error; + +#ifdef DEBUG + printf("Linux-emul(%d): lseek(%d, %d, %d)\n", + p->p_pid, args->fdes, args->off, args->whence); +#endif + tmp_args.fdes = args->fdes; + tmp_args.off = (off_t)args->off; + tmp_args.whence = args->whence; + error = lseek(p, &tmp_args, &tmp_retval); + *retval = (int)tmp_retval; + return error; +} + +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)) + +struct linux_readdir_args { + int fd; + struct linux_dirent *dent; + unsigned int count; +}; + +int +linux_readdir(struct proc *p, struct linux_readdir_args *args, int *retval) +{ + 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; + +#ifdef DEBUG + printf("Linux-emul(%d): readdir(%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; + + buflen = max(va.va_blocksize, nbytes); + buf = malloc(buflen, M_TEMP, M_WAITOK); + VOP_LOCK(vp); + off = fp->f_offset; +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; + + error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, (u_long *) 0, 0); + if (error) + goto out; + + inp = buf; + outp = (caddr_t) args->dent; + resid = nbytes; + if ((len = buflen - auio.uio_resid) == 0) + goto eof; + + while (len > 0) { + reclen = ((struct dirent *) inp)->d_reclen; + if (reclen & 3) + panic("linux_readdir"); + off += reclen; + bdp = (struct dirent *) inp; + if (bdp->d_fileno == 0) { + inp += reclen; + continue; + } + linuxreclen = LINUX_RECLEN(&linux_dirent, bdp->d_namlen); + if (reclen > len || resid < linuxreclen) { + outp++; + break; + } + linux_dirent.dino = (long) bdp->d_fileno; + linux_dirent.doff = (linux_off_t) linuxreclen; + linux_dirent.dreclen = (u_short) bdp->d_namlen; + strcpy(linux_dirent.dname, bdp->d_name); + if ((error = copyout((caddr_t)&linux_dirent, outp, linuxreclen))) + goto out; + inp += 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: + *retval = nbytes - resid; +out: + VOP_UNLOCK(vp); + free(buf, M_TEMP); + return error; +} diff --git a/sys/compat/linux/linux_ioctl.c b/sys/compat/linux/linux_ioctl.c new file mode 100644 index 0000000..12adff4 --- /dev/null +++ b/sys/compat/linux/linux_ioctl.c @@ -0,0 +1,495 @@ +/*- + * 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. + * + * $Id: linux_ioctl.c,v 1.2 1995/06/07 21:27:57 sos Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +struct linux_termios { + unsigned long c_iflag; + unsigned long c_oflag; + unsigned long c_cflag; + unsigned long c_lflag; + unsigned char c_line; + unsigned char c_cc[LINUX_NCCS]; +}; + +struct linux_winsize { + unsigned short ws_row, ws_col; + unsigned short ws_xpixel, ws_ypixel; +}; + +static struct speedtab sptab[] = { + { 0, 0 }, { 50, 1 }, { 75, 2 }, { 110, 3 }, + { 134, 4 }, { 135, 4 }, { 150, 5 }, { 200, 6 }, + { 300, 7 }, { 600, 8 }, { 1200, 9 }, { 1800, 10 }, + { 2400, 11 }, { 4800, 12 }, { 9600, 13 }, + { 19200, 14 }, { 38400, 15 }, + { 57600, 4097 }, { 115200, 4098 }, {-1, -1 } +}; + +static int +linux_to_bsd_speed(int code, struct speedtab *table) +{ + for ( ; table->sp_code != -1; table++) + if (table->sp_code == code) + return (table->sp_speed); + return -1; +} + +static int +bsd_to_linux_speed(int speed, struct speedtab *table) +{ + for ( ; table->sp_speed != -1; table++) + if (table->sp_speed == speed) + return (table->sp_code); + return -1; +} + +static void +bsd_to_linux_termios(struct termios *bsd_termios, + struct linux_termios *linux_termios) +{ + int i, speed; + +#ifdef DEBUG + printf("LINUX: BSD termios structure (input):\n"); + printf("i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d\n", + bsd_termios->c_iflag, bsd_termios->c_oflag, + bsd_termios->c_cflag, bsd_termios->c_lflag, + bsd_termios->c_ispeed, bsd_termios->c_ospeed); + printf("c_cc "); + for (i=0; ic_cc[i]); + printf("\n"); +#endif + linux_termios->c_iflag = 0; + if (bsd_termios->c_iflag & IGNBRK) + linux_termios->c_iflag |= LINUX_IGNBRK; + if (bsd_termios->c_iflag & BRKINT) + linux_termios->c_iflag |= LINUX_BRKINT; + if (bsd_termios->c_iflag & IGNPAR) + linux_termios->c_iflag |= LINUX_IGNPAR; + if (bsd_termios->c_iflag & PARMRK) + linux_termios->c_iflag |= LINUX_PARMRK; + if (bsd_termios->c_iflag & INPCK) + linux_termios->c_iflag |= LINUX_INPCK; + if (bsd_termios->c_iflag & ISTRIP) + linux_termios->c_iflag |= LINUX_ISTRIP; + if (bsd_termios->c_iflag & INLCR) + linux_termios->c_iflag |= LINUX_INLCR; + if (bsd_termios->c_iflag & IGNCR) + linux_termios->c_iflag |= LINUX_IGNCR; + if (bsd_termios->c_iflag & ICRNL) + linux_termios->c_iflag |= LINUX_ICRNL; + if (bsd_termios->c_iflag & IXON) + linux_termios->c_iflag |= LINUX_IXANY; + if (bsd_termios->c_iflag & IXON) + linux_termios->c_iflag |= LINUX_IXON; + if (bsd_termios->c_iflag & IXOFF) + linux_termios->c_iflag |= LINUX_IXOFF; + if (bsd_termios->c_iflag & IMAXBEL) + linux_termios->c_iflag |= LINUX_IMAXBEL; + + linux_termios->c_oflag = 0; + if (bsd_termios->c_oflag & OPOST) + linux_termios->c_oflag |= LINUX_OPOST; + if (bsd_termios->c_oflag & ONLCR) + linux_termios->c_oflag |= LINUX_ONLCR; + if (bsd_termios->c_oflag & OXTABS) + linux_termios->c_oflag |= LINUX_XTABS; + + linux_termios->c_cflag = + bsd_to_linux_speed(bsd_termios->c_ispeed, sptab); + linux_termios->c_cflag |= (bsd_termios->c_cflag & CSIZE) >> 4; + if (bsd_termios->c_cflag & CSTOPB) + linux_termios->c_cflag |= LINUX_CSTOPB; + if (bsd_termios->c_cflag & CREAD) + linux_termios->c_cflag |= LINUX_CREAD; + if (bsd_termios->c_cflag & PARENB) + linux_termios->c_cflag |= LINUX_PARENB; + if (bsd_termios->c_cflag & PARODD) + linux_termios->c_cflag |= LINUX_PARODD; + if (bsd_termios->c_cflag & HUPCL) + linux_termios->c_cflag |= LINUX_HUPCL; + if (bsd_termios->c_cflag & CLOCAL) + linux_termios->c_cflag |= LINUX_CLOCAL; + if (bsd_termios->c_cflag & CRTSCTS) + linux_termios->c_cflag |= LINUX_CRTSCTS; + + linux_termios->c_lflag = 0; + if (bsd_termios->c_lflag & ISIG) + linux_termios->c_lflag |= LINUX_ISIG; + if (bsd_termios->c_lflag & ICANON) + linux_termios->c_lflag |= LINUX_ICANON; + if (bsd_termios->c_lflag & ECHO) + linux_termios->c_lflag |= LINUX_ECHO; + if (bsd_termios->c_lflag & ECHOE) + linux_termios->c_lflag |= LINUX_ECHOE; + if (bsd_termios->c_lflag & ECHOK) + linux_termios->c_lflag |= LINUX_ECHOK; + if (bsd_termios->c_lflag & ECHONL) + linux_termios->c_lflag |= LINUX_ECHONL; + if (bsd_termios->c_lflag & NOFLSH) + linux_termios->c_lflag |= LINUX_NOFLSH; + if (bsd_termios->c_lflag & TOSTOP) + linux_termios->c_lflag |= LINUX_TOSTOP; + if (bsd_termios->c_lflag & ECHOCTL) + linux_termios->c_lflag |= LINUX_ECHOCTL; + if (bsd_termios->c_lflag & ECHOPRT) + linux_termios->c_lflag |= LINUX_ECHOPRT; + if (bsd_termios->c_lflag & ECHOKE) + linux_termios->c_lflag |= LINUX_ECHOKE; + if (bsd_termios->c_lflag & FLUSHO) + linux_termios->c_lflag |= LINUX_FLUSHO; + if (bsd_termios->c_lflag & PENDIN) + linux_termios->c_lflag |= LINUX_PENDIN; + if (bsd_termios->c_lflag & IEXTEN) + linux_termios->c_lflag |= LINUX_IEXTEN; + + for (i=0; ic_cc[i] = _POSIX_VDISABLE; + linux_termios->c_cc[LINUX_VINTR] = bsd_termios->c_cc[VINTR]; + linux_termios->c_cc[LINUX_VQUIT] = bsd_termios->c_cc[VQUIT]; + linux_termios->c_cc[LINUX_VERASE] = bsd_termios->c_cc[VERASE]; + linux_termios->c_cc[LINUX_VKILL] = bsd_termios->c_cc[VKILL]; + linux_termios->c_cc[LINUX_VEOF] = bsd_termios->c_cc[VEOF]; + linux_termios->c_cc[LINUX_VEOL] = bsd_termios->c_cc[VEOL]; + linux_termios->c_cc[LINUX_VMIN] = bsd_termios->c_cc[VMIN]; + linux_termios->c_cc[LINUX_VTIME] = bsd_termios->c_cc[VTIME]; + linux_termios->c_cc[LINUX_VEOL2] = bsd_termios->c_cc[VEOL2]; + linux_termios->c_cc[LINUX_VSWTC] = _POSIX_VDISABLE; + linux_termios->c_cc[LINUX_VSUSP] = bsd_termios->c_cc[VSUSP]; + linux_termios->c_cc[LINUX_VSTART] = bsd_termios->c_cc[VSTART]; + linux_termios->c_cc[LINUX_VSTOP] = bsd_termios->c_cc[VSTOP]; + linux_termios->c_cc[LINUX_VREPRINT] = bsd_termios->c_cc[VREPRINT]; + linux_termios->c_cc[LINUX_VDISCARD] = bsd_termios->c_cc[VDISCARD]; + linux_termios->c_cc[LINUX_VWERASE] = bsd_termios->c_cc[VWERASE]; + linux_termios->c_cc[LINUX_VLNEXT] = bsd_termios->c_cc[VLNEXT]; + + linux_termios->c_line = 0; +#ifdef DEBUG + printf("LINUX: LINUX termios structure (output):\n"); + printf("i=%08x o=%08x c=%08x l=%08x line=%d\n", + linux_termios->c_iflag, linux_termios->c_oflag, + linux_termios->c_cflag, linux_termios->c_lflag, + linux_termios->c_line); + printf("c_cc "); + for (i=0; ic_cc[i]); + printf("\n"); +#endif +} + +static void +linux_to_bsd_termios(struct linux_termios *linux_termios, + struct termios *bsd_termios) +{ + int i, speed; +#ifdef DEBUG + printf("LINUX: LINUX termios structure (input):\n"); + printf("i=%08x o=%08x c=%08x l=%08x line=%d\n", + linux_termios->c_iflag, linux_termios->c_oflag, + linux_termios->c_cflag, linux_termios->c_lflag, + linux_termios->c_line); + printf("c_cc "); + for (i=0; ic_cc[i]); + printf("\n"); +#endif + bsd_termios->c_iflag = 0; + if (linux_termios->c_iflag & LINUX_IGNBRK) + bsd_termios->c_iflag |= IGNBRK; + if (linux_termios->c_iflag & LINUX_BRKINT) + bsd_termios->c_iflag |= BRKINT; + if (linux_termios->c_iflag & LINUX_IGNPAR) + bsd_termios->c_iflag |= IGNPAR; + if (linux_termios->c_iflag & LINUX_PARMRK) + bsd_termios->c_iflag |= PARMRK; + if (linux_termios->c_iflag & LINUX_INPCK) + bsd_termios->c_iflag |= INPCK; + if (linux_termios->c_iflag & LINUX_ISTRIP) + bsd_termios->c_iflag |= ISTRIP; + if (linux_termios->c_iflag & LINUX_INLCR) + bsd_termios->c_iflag |= INLCR; + if (linux_termios->c_iflag & LINUX_IGNCR) + bsd_termios->c_iflag |= IGNCR; + if (linux_termios->c_iflag & LINUX_ICRNL) + bsd_termios->c_iflag |= ICRNL; + if (linux_termios->c_iflag & LINUX_IXON) + bsd_termios->c_iflag |= IXANY; + if (linux_termios->c_iflag & LINUX_IXON) + bsd_termios->c_iflag |= IXON; + if (linux_termios->c_iflag & LINUX_IXOFF) + bsd_termios->c_iflag |= IXOFF; + if (linux_termios->c_iflag & LINUX_IMAXBEL) + bsd_termios->c_iflag |= IMAXBEL; + + bsd_termios->c_oflag = 0; + if (linux_termios->c_oflag & LINUX_OPOST) + bsd_termios->c_oflag |= OPOST; + if (linux_termios->c_oflag & LINUX_ONLCR) + bsd_termios->c_oflag |= ONLCR; + if (linux_termios->c_oflag & LINUX_XTABS) + bsd_termios->c_oflag |= OXTABS; + + bsd_termios->c_cflag = (linux_termios->c_cflag & LINUX_CSIZE) << 4; + if (linux_termios->c_cflag & LINUX_CSTOPB) + bsd_termios->c_cflag |= CSTOPB; + if (linux_termios->c_cflag & LINUX_PARENB) + bsd_termios->c_cflag |= PARENB; + if (linux_termios->c_cflag & LINUX_PARODD) + bsd_termios->c_cflag |= PARODD; + if (linux_termios->c_cflag & LINUX_HUPCL) + bsd_termios->c_cflag |= HUPCL; + if (linux_termios->c_cflag & LINUX_CLOCAL) + bsd_termios->c_cflag |= CLOCAL; + if (linux_termios->c_cflag & LINUX_CRTSCTS) + bsd_termios->c_cflag |= CRTSCTS; + + bsd_termios->c_lflag = 0; + if (linux_termios->c_lflag & LINUX_ISIG) + bsd_termios->c_lflag |= ISIG; + if (linux_termios->c_lflag & LINUX_ICANON) + bsd_termios->c_lflag |= ICANON; + if (linux_termios->c_lflag & LINUX_ECHO) + bsd_termios->c_lflag |= ECHO; + if (linux_termios->c_lflag & LINUX_ECHOE) + bsd_termios->c_lflag |= ECHOE; + if (linux_termios->c_lflag & LINUX_ECHOK) + bsd_termios->c_lflag |= ECHOK; + if (linux_termios->c_lflag & LINUX_ECHONL) + bsd_termios->c_lflag |= ECHONL; + if (linux_termios->c_lflag & LINUX_NOFLSH) + bsd_termios->c_lflag |= NOFLSH; + if (linux_termios->c_lflag & LINUX_TOSTOP) + bsd_termios->c_lflag |= TOSTOP; + if (linux_termios->c_lflag & LINUX_ECHOCTL) + bsd_termios->c_lflag |= ECHOCTL; + if (linux_termios->c_lflag & LINUX_ECHOPRT) + bsd_termios->c_lflag |= ECHOPRT; + if (linux_termios->c_lflag & LINUX_ECHOKE) + bsd_termios->c_lflag |= ECHOKE; + if (linux_termios->c_lflag & LINUX_FLUSHO) + bsd_termios->c_lflag |= FLUSHO; + if (linux_termios->c_lflag & LINUX_PENDIN) + bsd_termios->c_lflag |= PENDIN; + if (linux_termios->c_lflag & IEXTEN) + bsd_termios->c_lflag |= IEXTEN; + + for (i=0; ic_cc[i] = _POSIX_VDISABLE; + bsd_termios->c_cc[VINTR] = linux_termios->c_cc[LINUX_VINTR]; + bsd_termios->c_cc[VQUIT] = linux_termios->c_cc[LINUX_VQUIT]; + bsd_termios->c_cc[VERASE] = linux_termios->c_cc[LINUX_VERASE]; + bsd_termios->c_cc[VKILL] = linux_termios->c_cc[LINUX_VKILL]; + bsd_termios->c_cc[VEOF] = linux_termios->c_cc[LINUX_VEOF]; + bsd_termios->c_cc[VEOL] = linux_termios->c_cc[LINUX_VEOL]; + bsd_termios->c_cc[VMIN] = linux_termios->c_cc[LINUX_VMIN]; + bsd_termios->c_cc[VTIME] = linux_termios->c_cc[LINUX_VTIME]; + bsd_termios->c_cc[VEOL2] = linux_termios->c_cc[LINUX_VEOL2]; + bsd_termios->c_cc[VSUSP] = linux_termios->c_cc[LINUX_VSUSP]; + bsd_termios->c_cc[VSTART] = linux_termios->c_cc[LINUX_VSTART]; + bsd_termios->c_cc[VSTOP] = linux_termios->c_cc[LINUX_VSTOP]; + bsd_termios->c_cc[VREPRINT] = linux_termios->c_cc[LINUX_VREPRINT]; + bsd_termios->c_cc[VDISCARD] = linux_termios->c_cc[LINUX_VDISCARD]; + bsd_termios->c_cc[VWERASE] = linux_termios->c_cc[LINUX_VWERASE]; + bsd_termios->c_cc[VLNEXT] = linux_termios->c_cc[LINUX_VLNEXT]; + + bsd_termios->c_ispeed = bsd_termios->c_ospeed = + linux_to_bsd_speed(linux_termios->c_cflag & LINUX_CBAUD, sptab); +#ifdef DEBUG + printf("LINUX: BSD termios structure (output):\n"); + printf("i=%08x o=%08x c=%08x l=%08x ispeed=%d ospeed=%d\n", + bsd_termios->c_iflag, bsd_termios->c_oflag, + bsd_termios->c_cflag, bsd_termios->c_lflag, + bsd_termios->c_ispeed, bsd_termios->c_ospeed); + printf("c_cc "); + for (i=0; ic_cc[i]); + printf("\n"); +#endif +} + + +struct linux_ioctl_args { + int fd; + int cmd; + int arg; +}; + +int +linux_ioctl(struct proc *p, struct linux_ioctl_args *args, int *retval) +{ + struct termios bsd_termios; + struct winsize bsd_winsize; + struct linux_termios linux_termios; + struct linux_winsize linux_winsize; + struct filedesc *fdp = p->p_fd; + struct file *fp; + int (*func)(); + int bsd_line, linux_line; + int error; + +#ifdef DEBUG + printf("Linux-emul(%d): ioctl(%d, %04x, *)\n", + p->p_pid, args->fd, args->cmd); +#endif + if ((unsigned)args->fd >= fdp->fd_nfiles + || (fp = fdp->fd_ofiles[args->fd]) == 0) + return EBADF; + + if (!fp || (fp->f_flag & (FREAD | FWRITE)) == 0) { + return EBADF; + } + + func = fp->f_ops->fo_ioctl; + switch (args->cmd) { + case LINUX_TCGETS: + if ((error = (*func)(fp, TIOCGETA, (caddr_t)&bsd_termios, p)) != 0) + return error; + bsd_to_linux_termios(&bsd_termios, &linux_termios); + return copyout((caddr_t)&linux_termios, (caddr_t)args->arg, + sizeof(linux_termios)); + + case LINUX_TCSETS: + linux_to_bsd_termios((struct linux_termios *)args->arg, &bsd_termios); + return (*func)(fp, TIOCSETA, (caddr_t)&bsd_termios, p); + + case LINUX_TCSETSW: + linux_to_bsd_termios((struct linux_termios *)args->arg, &bsd_termios); + return (*func)(fp, TIOCSETAW, (caddr_t)&bsd_termios, p); + + case LINUX_TCSETSF: + linux_to_bsd_termios((struct linux_termios *)args->arg, &bsd_termios); + return (*func)(fp, TIOCSETAF, (caddr_t)&bsd_termios, p); + + case LINUX_TIOCGPGRP: + args->cmd = TIOCGPGRP; + return ioctl(p, args, retval); + + case LINUX_TIOCSPGRP: + args->cmd = TIOCSPGRP; + return ioctl(p, args, retval); + + case LINUX_TIOCGWINSZ: + args->cmd = TIOCGWINSZ; + return ioctl(p, args, retval); + + case LINUX_TIOCSWINSZ: + args->cmd = TIOCSWINSZ; + return ioctl(p, args, retval); + + case LINUX_FIONREAD: + args->cmd = FIONREAD; + return ioctl(p, args, retval); + + case LINUX_FIONBIO: + args->cmd = FIONBIO; + return ioctl(p, args, retval); + + case LINUX_FIOASYNC: + args->cmd = FIOASYNC; + return ioctl(p, args, retval); + + case LINUX_FIONCLEX: + args->cmd = FIONCLEX; + return ioctl(p, args, retval); + + case LINUX_FIOCLEX: + args->cmd = FIOCLEX; + return ioctl(p, args, retval); + + case LINUX_TIOCEXCL: + args->cmd = TIOCEXCL; + return ioctl(p, args, retval); + + case LINUX_TIOCNXCL: + args->cmd = TIOCNXCL; + return ioctl(p, args, retval); + + case LINUX_TIOCCONS: + args->cmd = TIOCCONS; + return ioctl(p, args, retval); + + case LINUX_TIOCNOTTY: + args->cmd = TIOCNOTTY; + return ioctl(p, args, retval); + + case LINUX_TIOCSETD: + switch (args->arg) { + case LINUX_N_TTY: + bsd_line = TTYDISC; + return (*func)(fp, TIOCSETD, (caddr_t)&bsd_line, p); + case LINUX_N_SLIP: + bsd_line = SLIPDISC; + return (*func)(fp, TIOCSETD, (caddr_t)&bsd_line, p); + case LINUX_N_PPP: + bsd_line = PPPDISC; + return (*func)(fp, TIOCSETD, (caddr_t)&bsd_line, p); + default: + return EINVAL; + } + break; + + case LINUX_TIOCGETD: + bsd_line = TTYDISC; + if (error =(*func)(fp, TIOCSETD, (caddr_t)&bsd_line, p)) + return error; + switch (bsd_line) { + case TTYDISC: + linux_line = LINUX_N_TTY; + break; + case SLIPDISC: + linux_line = LINUX_N_SLIP; + break; + case PPPDISC: + linux_line = LINUX_N_PPP; + break; + default: + return EINVAL; + } + return copyout(&linux_line, (caddr_t)args->arg, + sizeof(int)); + } + uprintf("LINUX: 'ioctl' fd=%d, typ=0x%x(%c), num=0x%x not implemented\n", + args->fd, (args->cmd&0xffff00)>>8, + (args->cmd&0xffff00)>>8, args->cmd&0xff); + return EINVAL; +} diff --git a/sys/compat/linux/linux_ipc.c b/sys/compat/linux/linux_ipc.c new file mode 100644 index 0000000..b38b229 --- /dev/null +++ b/sys/compat/linux/linux_ipc.c @@ -0,0 +1,308 @@ +/*- + * 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. + * + * $Id: linux_ipc.c,v 1.2 1995/06/07 21:27:57 sos Exp $ + */ + +#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_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_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 */ +} + +struct linux_ipc_args { + int what; + int arg1; + int arg2; + int arg3; + caddr_t ptr; +}; + +int +linux_semop(struct proc *p, struct linux_ipc_args *args, int *retval) +{ + return ENOSYS; +} + +int +linux_semget(struct proc *p, struct linux_ipc_args *args, int *retval) +{ + return ENOSYS; +} + +int +linux_semctl(struct proc *p, struct linux_ipc_args *args, int *retval) +{ + return ENOSYS; +} + +int +linux_msgsnd(struct proc *p, struct linux_ipc_args *args, int *retval) +{ + return ENOSYS; +} + +int +linux_msgrcv(struct proc *p, struct linux_ipc_args *args, int *retval) +{ + return ENOSYS; +} + +int +linux_msgget(struct proc *p, struct linux_ipc_args *args, int *retval) +{ + return ENOSYS; +} + +int +linux_msgctl(struct proc *p, struct linux_ipc_args *args, int *retval) +{ + return ENOSYS; +} + +int +linux_shmat(struct proc *p, struct linux_ipc_args *args, int *retval) +{ + 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, retval))) + return error; + if ((error = copyout(retval, (caddr_t)args->arg3, sizeof(int)))) + return error; + retval[0] = 0; + return 0; +} + +int +linux_shmdt(struct proc *p, struct linux_ipc_args *args, int *retval) +{ + struct shmdt_args { + void *shmaddr; + } bsd_args; + + bsd_args.shmaddr = args->ptr; + return shmdt(p, &bsd_args, retval); +} + +int +linux_shmget(struct proc *p, struct linux_ipc_args *args, int *retval) +{ + 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, retval); +} + +int +linux_shmctl(struct proc *p, struct linux_ipc_args *args, int *retval) +{ + 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; + + switch (args->arg2) { + case LINUX_IPC_STAT: + bsd_args.shmid = args->arg1; + bsd_args.cmd = IPC_STAT; + bsd_args.buf = (struct shmid_ds*)ua_alloc_init(sizeof(struct shmid_ds)); + if ((error = shmctl(p, &bsd_args, retval))) + return error; + if ((error = copyin((caddr_t)&bsd_shmid, (caddr_t)bsd_args.buf, + 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*)ua_alloc_init(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, retval); + + case LINUX_IPC_RMID: + bsd_args.shmid = args->arg1; + bsd_args.cmd = IPC_RMID; + 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*)ua_alloc_init(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, retval); + + 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; + } +} + +int +linux_ipc(struct proc *p, struct linux_ipc_args *args, int *retval) +{ + switch (args->what) { + case LINUX_SEMOP: + return linux_semop(p, args, retval); + case LINUX_SEMGET: + return linux_semget(p, args, retval); + case LINUX_SEMCTL: + return linux_semctl(p, args, retval); + case LINUX_MSGSND: + return linux_msgsnd(p, args, retval); + case LINUX_MSGRCV: + return linux_msgrcv(p, args, retval); + case LINUX_MSGGET: + return linux_msgget(p, args, retval); + case LINUX_MSGCTL: + return linux_msgctl(p, args, retval); + case LINUX_SHMAT: + return linux_shmat(p, args, retval); + case LINUX_SHMDT: + return linux_shmdt(p, args, retval); + case LINUX_SHMGET: + return linux_shmget(p, args, retval); + case LINUX_SHMCTL: + return linux_shmctl(p, args, retval); + default: + uprintf("LINUX: 'ipc' typ=%d not implemented\n", args->what); + return ENOSYS; + } +} diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c new file mode 100644 index 0000000..bf40786 --- /dev/null +++ b/sys/compat/linux/linux_misc.c @@ -0,0 +1,660 @@ +/*- + * 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. + * + * $Id: linux_misc.c,v 1.4 1995/06/08 13:50:52 sos Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + + +struct linux_alarm_args { + unsigned int secs; +}; + +int +linux_alarm(struct proc *p, struct linux_alarm_args *args, int *retval) +{ + extern struct timeval time; + struct itimerval it, old_it; + int s; + +#ifdef DEBUG + printf("Linux-emul(%d): alarm(%d)\n", p->p_pid, args->secs); +#endif + it.it_value.tv_sec = (long)args->secs; + it.it_value.tv_usec = 0; + it.it_interval.tv_sec = 0; + it.it_interval.tv_usec = 0; + s = splclock(); + old_it = p->p_realtimer; + if (timerisset(&old_it.it_value)) + if (timercmp(&old_it.it_value, &time, <)) + timerclear(&old_it.it_value); + else + timevalsub(&old_it.it_value, &time); + splx(s); + if (itimerfix(&it.it_value) || itimerfix(&it.it_interval)) + return EINVAL; + s = splclock(); + untimeout(realitexpire, (caddr_t)p); + if (timerisset(&it.it_value)) { + timevaladd(&it.it_value, &time); + timeout(realitexpire, (caddr_t)p, hzto(&it.it_value)); + } + p->p_realtimer = it; + splx(s); + if (old_it.it_value.tv_usec) + old_it.it_value.tv_sec++; + *retval = old_it.it_value.tv_sec; + return 0; +} + +struct linux_brk_args { + linux_caddr_t dsend; +}; + +int +linux_brk(struct proc *p, struct linux_brk_args *args, int *retval) +{ +#if 0 + struct vmspace *vm = p->p_vmspace; + vm_offset_t new, old; + int error; + extern int swap_pager_full; + + if ((vm_offset_t)args->dsend < (vm_offset_t)vm->vm_daddr) + return EINVAL; + if (((caddr_t)args->dsend - (caddr_t)vm->vm_daddr) + > p->p_rlimit[RLIMIT_DATA].rlim_cur) + return ENOMEM; + + old = round_page((vm_offset_t)vm->vm_daddr) + ctob(vm->vm_dsize); + new = round_page((vm_offset_t)args->dsend); + *retval = old; + if ((new-old) > 0) { + if (swap_pager_full) + return ENOMEM; + error = vm_map_find(&vm->vm_map, NULL, 0, &old, (new-old), FALSE); + if (error) + return error; + vm->vm_dsize += btoc((new-old)); + *retval = (int)(vm->vm_daddr + ctob(vm->vm_dsize)); + } + return 0; +#else + struct vmspace *vm = p->p_vmspace; + vm_offset_t new, old; + struct obreak_args { + vm_offset_t newsize; + } tmp; + +#ifdef DEBUG + printf("Linux-emul(%d): brk(%08x)\n", p->p_pid, args->dsend); +#endif + old = (vm_offset_t)vm->vm_daddr + ctob(vm->vm_dsize); + new = (vm_offset_t)args->dsend; + tmp.newsize = new; + if (((caddr_t)new > vm->vm_daddr) && !obreak(p, &tmp, retval)) + retval[0] = (int)new; + else + retval[0] = (int)old; + + return 0; +#endif +} + +struct linux_uselib_args { + char *library; +}; + +int +linux_uselib(struct proc *p, struct linux_uselib_args *args, int *retval) +{ + struct nameidata ni; + struct vnode *vnodep; + struct exec *a_out = 0; + struct vattr attr; + unsigned long vmaddr, virtual_offset, file_offset; + unsigned long buffer, bss_size; + char *ptr; + char path[MAXPATHLEN]; + const char *prefix = "/compat/linux"; + size_t sz, len; + int error; + +#ifdef DEBUG + printf("Linux-emul(%d): uselib(%s)\n", p->p_pid, args->library); +#endif + + for (ptr = path; (*ptr = *prefix) != '\0'; ptr++, prefix++) ; + sz = MAXPATHLEN - (ptr - path); + if (error = copyinstr(args->library, ptr, sz, &len)) + return error; + if (*ptr != '/') + return EINVAL; + +#ifdef DEBUG + printf("Linux-emul(%d): uselib(%s)\n", p->p_pid, path); +#endif + + NDINIT(&ni, LOOKUP, FOLLOW, UIO_SYSSPACE, path, p); + if (error = namei(&ni)) + return error; + + vnodep = ni.ni_vp; + if (vnodep == NULL) + return ENOEXEC; + + if (vnodep->v_writecount) + return ETXTBSY; + + if (error = VOP_GETATTR(vnodep, &attr, p->p_ucred, p)) + return error; + + if ((vnodep->v_mount->mnt_flag & MNT_NOEXEC) + || ((attr.va_mode & 0111) == 0) + || (attr.va_type != VREG)) + return ENOEXEC; + + if (attr.va_size == 0) + return ENOEXEC; + + if (error = VOP_ACCESS(vnodep, VEXEC, p->p_ucred, p)) + return error; + + if (error = VOP_OPEN(vnodep, FREAD, p->p_ucred, p)) + return error; + + error = vm_mmap(kernel_map, (vm_offset_t *)&a_out, 1024, + VM_PROT_READ, VM_PROT_READ, 0, (caddr_t)vnodep, 0); + if (error) + return (error); + + /* + * Is it a Linux binary ? + */ + if (((a_out->a_magic >> 16) & 0xff) != 0x64) + return -1; + + /* + * Set file/virtual offset based on a.out variant. + */ + switch ((int)(a_out->a_magic & 0xffff)) { + case 0413: /* ZMAGIC */ + virtual_offset = 0; + file_offset = 1024; + break; + case 0314: /* QMAGIC */ + virtual_offset = 4096; + file_offset = 0; + break; + default: + return (-1); + } + + vnodep->v_flag |= VTEXT; + bss_size = round_page(a_out->a_bss); + /* + * Check if file_offset page aligned,. + * Currently we cannot handle misalinged file offsets, + * and so we read in the entire image (what a waste). + */ + if (file_offset & PGOFSET) { +#ifdef DEBUG +printf("uselib: Non page aligned binary %d\n", file_offset); +#endif + /* + * Map text+data read/write/execute + */ + vmaddr = virtual_offset + round_page(a_out->a_entry); + error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &vmaddr, + round_page(a_out->a_text + a_out->a_data), FALSE); + if (error) + return error; + + error = vm_mmap(kernel_map, &buffer, + round_page(a_out->a_text + a_out->a_data + file_offset), + VM_PROT_READ, VM_PROT_READ, MAP_FILE, + (caddr_t)vnodep, trunc_page(file_offset)); + if (error) + return error; + + error = copyout((caddr_t)(buffer + file_offset), (caddr_t)vmaddr, + a_out->a_text + a_out->a_data); + if (error) + return error; + + vm_map_remove(kernel_map, trunc_page(vmaddr), + round_page(a_out->a_text + a_out->a_data + file_offset)); + + error = vm_map_protect(&p->p_vmspace->vm_map, vmaddr, + round_page(a_out->a_text + a_out->a_data), + VM_PROT_ALL, TRUE); + if (error) + return error; + } + else { +#ifdef DEBUG +printf("uselib: Page aligned binary %d\n", file_offset); +#endif + vmaddr = virtual_offset + round_page(a_out->a_entry); + error = vm_mmap(&p->p_vmspace->vm_map, &vmaddr, + a_out->a_text + a_out->a_data, + VM_PROT_ALL, VM_PROT_ALL, MAP_PRIVATE | MAP_FIXED, + (caddr_t)vnodep, file_offset); + if (error) + return (error); + } +#ifdef DEBUG +printf("mem=%08x = %08x %08x\n", vmaddr, ((int*)vmaddr)[0], ((int*)vmaddr)[1]); +#endif + if (bss_size != 0) { + vmaddr = virtual_offset + round_page(a_out->a_entry) + + round_page(a_out->a_text + a_out->a_data); + error = vm_map_find(&p->p_vmspace->vm_map, NULL, 0, &vmaddr, + bss_size, FALSE); + if (error) + return error; + error = vm_map_protect(&p->p_vmspace->vm_map, vmaddr, bss_size, + VM_PROT_ALL, TRUE); + if (error) + return error; + } + return 0; +} + +struct linux_select_args { + void *ptr; +}; + +int +linux_select(struct proc *p, struct linux_select_args *args, int *retval) +{ + struct { + int nfds; + fd_set *readfds; + fd_set *writefds; + fd_set *exceptfds; + struct timeval *timeout; + } linux_args; + struct { + unsigned int nd; + fd_set *in; + fd_set *ou; + fd_set *ex; + struct timeval *tv; + } bsd_args; + int error; + + if ((error = copyin((caddr_t)args->ptr, (caddr_t)&linux_args, + sizeof(linux_args)))) + return error; +#ifdef DEBUG + printf("Linux-emul(%d): select(%d, %d, %d, %d, %d)\n", + p->p_pid, linux_args.nfds, linux_args.readfds, + linux_args.writefds, linux_args.exceptfds, + linux_args.timeout); +#endif + bsd_args.nd = linux_args.nfds; + bsd_args.in = linux_args.readfds; + bsd_args.ou = linux_args.writefds; + bsd_args.ex = linux_args.exceptfds; + bsd_args.tv = linux_args.timeout; + return select(p, &bsd_args, retval); +} + +struct linux_getpgid_args { + int pid; +}; + +int +linux_getpgid(struct proc *p, struct linux_getpgid_args *args, int *retval) +{ + struct proc *curproc; + +#ifdef DEBUG + printf("Linux-emul(%d): getpgid(%d)\n", p->p_pid, args->pid); +#endif + if (args->pid != p->p_pid) { + if (!(curproc = pfind(args->pid))) + return ESRCH; + } + else + curproc = p; + *retval = curproc->p_pgid; + return 0; +} + +int +linux_fork(struct proc *p, void *args, int *retval) +{ + int error; + +#ifdef DEBUG + printf("Linux-emul(%d): fork()\n", p->p_pid); +#endif + if (error = fork(p, args, retval)) + return error; + if (retval[1] == 1) + retval[0] = 0; + return 0; +} + +struct linux_mmap_args { + void *ptr; +}; + +int +linux_mmap(struct proc *p, struct linux_mmap_args *args, int *retval) +{ + struct { + linux_caddr_t addr; + int len; + int prot; + int flags; + int fd; + int pos; + } linux_args; + struct { + caddr_t addr; + size_t len; + int prot; + int flags; + int fd; + long pad; + off_t pos; + } bsd_args; + int error; + + if ((error = copyin((caddr_t)args->ptr, (caddr_t)&linux_args, + sizeof(linux_args)))) + return error; +#ifdef DEBUG + printf("Linux-emul(%d): mmap(%08x, %d, %d, %08x, %d, %d)\n", + p->p_pid, linux_args.addr, linux_args.len, linux_args.prot, + linux_args.flags, linux_args.fd, linux_args.pos); +#endif + bsd_args.flags = 0; + if (linux_args.flags & LINUX_MAP_SHARED) + bsd_args.flags |= MAP_SHARED; + if (linux_args.flags & LINUX_MAP_PRIVATE) + bsd_args.flags |= MAP_PRIVATE; + if (linux_args.flags & LINUX_MAP_FIXED) + bsd_args.flags |= MAP_FIXED; + if (linux_args.flags & LINUX_MAP_ANON) + bsd_args.flags |= MAP_ANON; + bsd_args.addr = linux_args.addr; + bsd_args.len = linux_args.len; + bsd_args.prot = linux_args.prot; + bsd_args.fd = linux_args.fd; + bsd_args.pos = linux_args.pos; + bsd_args.pad = 0; + return mmap(p, &bsd_args, retval); +} + +struct linux_pipe_args { + int *pipefds; +}; + +int +linux_pipe(struct proc *p, struct linux_pipe_args *args, int *retval) +{ + int error; + +#ifdef DEBUG + printf("Linux-emul(%d): pipe(*)\n", p->p_pid); +#endif + if (error = pipe(p, 0, retval)) + return error; + if (error = copyout(retval, args->pipefds, 2*sizeof(int))) + return error; + *retval = 0; + return 0; +} + +struct linux_time_args { + linux_time_t *tm; +}; + +int +linux_time(struct proc *p, struct linux_time_args *args, int *retval) +{ + struct timeval tv; + linux_time_t tm; + int error; + +#ifdef DEBUG + printf("Linux-emul(%d): time(*)\n", p->p_pid); +#endif + microtime(&tv); + tm = tv.tv_sec; + if (error = copyout(&tm, args->tm, sizeof(linux_time_t))) + return error; + *retval = tv.tv_sec; + return 0; +} + +struct linux_tms { + long tms_utime; + long tms_stime; + long tms_cutime; + long tms_cstime; +}; + +struct linux_tms_args { + char *buf; +}; + +int +linux_times(struct proc *p, struct linux_tms_args *args, int *retval) +{ + extern int hz; + struct timeval tv; + struct linux_tms tms; + +#ifdef DEBUG + printf("Linux-emul(%d): times(*)\n", p->p_pid); +#endif + tms.tms_utime = p->p_uticks; + tms.tms_stime = p->p_sticks; + tms.tms_cutime = p->p_stats->p_cru.ru_utime.tv_sec * hz + + ((p->p_stats->p_cru.ru_utime.tv_usec * hz)/1000000); + tms.tms_cstime = p->p_stats->p_cru.ru_stime.tv_sec * hz + + ((p->p_stats->p_cru.ru_stime.tv_usec * hz)/1000000); + microtime(&tv); + *retval = tv.tv_sec * hz + (tv.tv_usec * hz)/1000000; + return (copyout((caddr_t)&tms, (caddr_t)args->buf, + sizeof(struct linux_tms))); +} + +struct linux_newuname_t { + char sysname[65]; + char nodename[65]; + char release[65]; + char version[65]; + char machine[65]; + char domainname[65]; +}; + +struct linux_newuname_args { + char *buf; +}; + +int +linux_newuname(struct proc *p, struct linux_newuname_args *args, int *retval) +{ + struct linux_newuname_t linux_newuname; + extern char ostype[], osrelease[], machine[]; + extern char hostname[], domainname[]; + +#ifdef DEBUG + printf("Linux-emul(%d): newuname(*)\n", p->p_pid); +#endif + bzero(&linux_newuname, sizeof(struct linux_newuname_args)); + strncpy(linux_newuname.sysname, ostype, 64); + strncpy(linux_newuname.nodename, hostname, 64); + strncpy(linux_newuname.release, osrelease, 64); + strncpy(linux_newuname.version, version, 64); + strncpy(linux_newuname.machine, machine, 64); + strncpy(linux_newuname.domainname, domainname, 64); + return (copyout((caddr_t)&linux_newuname, (caddr_t)args->buf, + sizeof(struct linux_newuname_t))); +} + +struct linux_utime_args { + char *fname; + linux_time_t *timeptr; +}; + +int +linux_utime(struct proc *p, struct linux_utime_args *args, int *retval) +{ + struct bsd_utimes_args { + char *fname; + struct timeval *tptr; + } bsdutimes; + struct timeval tv; + +#ifdef DEBUG + printf("Linux-emul(%d): utime(%s, *)\n", p->p_pid, args->fname); +#endif + tv.tv_sec = (long)args->timeptr; + tv.tv_usec = 0; + bsdutimes.tptr = &tv; + bsdutimes.fname = args->fname; + return utimes(p, &bsdutimes, retval); +} + +struct linux_waitpid_args { + int pid; + int *status; + int options; +}; + +int +linux_waitpid(struct proc *p, struct linux_waitpid_args *args, int *retval) +{ + struct wait4_args { + int pid; + int *status; + int options; + struct rusage *rusage; + int compat; + } tmp; + int error, tmpstat; + +#ifdef DEBUG + printf("Linux-emul(%d): waitpid(%d, *, %d)\n", + p->p_pid, args->pid, args->options); +#endif + tmp.pid = args->pid; + tmp.status = args->status; + tmp.options = args->options; + tmp.rusage = NULL; + tmp.compat = 0; + + if (error = wait4(p, &tmp, retval)) + return error; + if (error = copyin(args->status, &tmpstat, sizeof(int))) + return error; + if (WIFSIGNALED(tmpstat)) + tmpstat = (tmpstat & 0xffffff80) | + bsd_to_linux_signal[WTERMSIG(tmpstat)]; + else if (WIFSTOPPED(tmpstat)) + tmpstat = (tmpstat & 0xffff00ff) | + (bsd_to_linux_signal[WSTOPSIG(tmpstat)]<<8); + return copyout(&tmpstat, args->status, sizeof(int)); +} + +struct linux_wait4_args { + int pid; + int *status; + int options; + struct rusage *rusage; +}; + +int +linux_wait4(struct proc *p, struct linux_wait4_args *args, int *retval) +{ + struct wait4_args { + int pid; + int *status; + int options; + struct rusage *rusage; + int compat; + } tmp; + int error, tmpstat; + +#ifdef DEBUG + printf("Linux-emul(%d): wait4(%d, *, %d, *)\n", + p->p_pid, args->pid, args->options); +#endif + tmp.pid = args->pid; + tmp.status = args->status; + tmp.options = args->options; + tmp.rusage = args->rusage; + tmp.compat = 0; + + if (error = wait4(p, &tmp, retval)) + return error; + if (error = copyin(args->status, &tmpstat, sizeof(int))) + return error; + if (WIFSIGNALED(tmpstat)) + tmpstat = (tmpstat & 0xffffff80) | + bsd_to_linux_signal[WTERMSIG(tmpstat)]; + else if (WIFSTOPPED(tmpstat)) + tmpstat = (tmpstat & 0xffff00ff) | + (bsd_to_linux_signal[WSTOPSIG(tmpstat)]<<8); + return copyout(&tmpstat, args->status, sizeof(int)); +} diff --git a/sys/compat/linux/linux_signal.c b/sys/compat/linux/linux_signal.c new file mode 100644 index 0000000..528bb62 --- /dev/null +++ b/sys/compat/linux/linux_signal.c @@ -0,0 +1,259 @@ +/*- + * 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. + * + * $Id: linux_signal.c,v 1.2 1995/06/07 21:27:57 sos Exp $ + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#define DONTMASK (sigmask(SIGKILL)|sigmask(SIGSTOP)|sigmask(SIGCHLD)) + +static sigset_t +linux_to_bsd_sigmask(linux_sigset_t mask) { + int i; + sigset_t new = 0; + + for (i = 1; i <= LINUX_NSIG; i++) + if (mask & (1 << i-1)) + new |= (1 << (linux_to_bsd_signal[i]-1)); + return new; +} + +static linux_sigset_t +bsd_to_linux_sigmask(sigset_t mask) { + int i; + sigset_t new = 0; + + for (i = 1; i <= NSIG; i++) + if (mask & (1 << i-1)) + new |= (1 << (bsd_to_linux_signal[i]-1)); + return new; +} + +struct linux_sigaction_args { + int sig; + linux_sigaction_t *nsa; + linux_sigaction_t *osa; +}; + +int +linux_sigaction(struct proc *p, struct linux_sigaction_args *args, int *retval) +{ + linux_sigaction_t linux_sa; + struct sigaction *nsa = NULL, *osa = NULL, bsd_sa; + struct sigaction_args { + int sig; + struct sigaction *nsa; + struct sigaction *osa; + } sa; + int error; + +#ifdef DEBUG + printf("Linux-emul(%d): sigaction(%d, *, *)\n", p->p_pid, args->sig); +#endif + if (args->osa) + osa = (struct sigaction *)ua_alloc_init(sizeof(struct sigaction)); + + if (args->nsa) { + nsa = (struct sigaction *)ua_alloc(sizeof(struct sigaction)); + if (error = copyin(args->nsa, &linux_sa, sizeof(linux_sigaction_t))) + return error; + bsd_sa.sa_mask = linux_to_bsd_sigmask(linux_sa.sa_mask); + bsd_sa.sa_handler = linux_sa.sa_handler; + bsd_sa.sa_flags = 0; + if (linux_sa.sa_flags & LINUX_SA_NOCLDSTOP) + bsd_sa.sa_flags |= SA_NOCLDSTOP; + if (linux_sa.sa_flags & LINUX_SA_ONSTACK) + bsd_sa.sa_flags |= SA_ONSTACK; + if (linux_sa.sa_flags & LINUX_SA_RESTART) + bsd_sa.sa_flags |= SA_RESTART; + if (error = copyout(&bsd_sa, nsa, sizeof(struct sigaction))) + return error; + } + sa.sig = linux_to_bsd_signal[args->sig]; + sa.nsa = nsa; + sa.osa = osa; + if ((error = sigaction(p, &sa, retval))) + return error; + + if (args->osa) { + if (error = copyin(osa, &bsd_sa, sizeof(struct sigaction))) + return error; + linux_sa.sa_handler = bsd_sa.sa_handler; + linux_sa.sa_restorer = NULL; + linux_sa.sa_mask = bsd_to_linux_sigmask(bsd_sa.sa_mask); + linux_sa.sa_flags = 0; + if (bsd_sa.sa_flags & SA_NOCLDSTOP) + linux_sa.sa_flags |= LINUX_SA_NOCLDSTOP; + if (bsd_sa.sa_flags & SA_ONSTACK) + linux_sa.sa_flags |= LINUX_SA_ONSTACK; + if (bsd_sa.sa_flags & SA_RESTART) + linux_sa.sa_flags |= LINUX_SA_RESTART; + if (error = copyout(&linux_sa, args->osa, sizeof(linux_sigaction_t))) + return error; + } + return 0; +} + +struct linux_sigprocmask_args { + int how; + linux_sigset_t *mask; + linux_sigset_t *omask; +}; + +int +linux_sigprocmask(struct proc *p, struct linux_sigprocmask_args *args, + int *retval) +{ + int error, s; + sigset_t mask; + sigset_t omask; + +#ifdef DEBUG + printf("Linux-emul(%d): sigprocmask(%d, *, *)\n", p->p_pid, args->how); +#endif + if (args->omask != NULL) { + omask = bsd_to_linux_sigmask(p->p_sigmask); + if (error = copyout(&omask, args->omask, sizeof(sigset_t))) + return error; + } + if (!(args->mask)) + return 0; + if (error = copyin(args->mask, &mask, sizeof(linux_sigset_t))) + return error; + + mask = linux_to_bsd_sigmask(mask); + s = splhigh(); + switch (args->how) { + case LINUX_SIG_BLOCK: + p->p_sigmask |= (mask & ~DONTMASK); + break; + case LINUX_SIG_UNBLOCK: + p->p_sigmask &= ~mask; + break; + case LINUX_SIG_SETMASK: + p->p_sigmask = (mask & ~DONTMASK); + break; + default: + error = EINVAL; + break; + } + splx(s); + return error; +} + +int +linux_siggetmask(struct proc *p, void *args, int *retval) +{ +#ifdef DEBUG + printf("Linux-emul(%d): siggetmask()\n", p->p_pid); +#endif + *retval = bsd_to_linux_sigmask(p->p_sigmask); + return 0; +} + +struct linux_sigsetmask_args { + linux_sigset_t mask; +}; + +int +linux_sigsetmask(struct proc *p, struct linux_sigsetmask_args *args,int *retval) +{ + int s; + +#ifdef DEBUG + printf("Linux-emul(%d): sigsetmask(%08x)\n", p->p_pid, args->mask); +#endif + s = splhigh(); + p->p_sigmask = (linux_to_bsd_sigmask(args->mask) & ~DONTMASK); + splx(s); + *retval = bsd_to_linux_sigmask(p->p_sigmask); + return 0; +} + +struct linux_sigpending_args { + linux_sigset_t *mask; +}; + +int +linux_sigpending(struct proc *p, struct linux_sigpending_args *args,int *retval) +{ + linux_sigset_t linux_sig; + +#ifdef DEBUG + printf("Linux-emul(%d): sigpending(*)\n", p->p_pid); +#endif + linux_sig = bsd_to_linux_sigmask(p->p_siglist & p->p_sigmask); + return copyout(&linux_sig, args->mask, sizeof(linux_sig)); +} + +struct linux_sigsuspend_args { + linux_sigset_t mask; +}; + +int +linux_sigsuspend(struct proc *p, struct linux_sigsuspend_args *args,int *retval) +{ + sigset_t tmp; + +#ifdef DEBUG + printf("Linux-emul(%d): sigsuspend(%08x)\n", p->p_pid, args->mask); +#endif + tmp = linux_to_bsd_sigmask(args->mask); + return sigsuspend(p, &tmp , retval); +} + +struct linux_kill_args { + int pid; + int signum; +}; + +int +linux_kill(struct proc *p, struct linux_kill_args *args, int *retval) +{ + struct { + int pid; + int signum; + } tmp; + +#ifdef DEBUG + printf("Linux-emul(%d): kill(%d, %d)\n", + p->p_pid, args->pid, args->signum); +#endif + tmp.pid = args->pid; + tmp.signum = linux_to_bsd_signal[args->signum]; + return kill(p, &tmp, retval); +} diff --git a/sys/compat/linux/linux_socket.c b/sys/compat/linux/linux_socket.c new file mode 100644 index 0000000..9267063 --- /dev/null +++ b/sys/compat/linux/linux_socket.c @@ -0,0 +1,595 @@ +/*- + * Copyright (c) 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. + * + * $Id: linux_socket.c,v 1.2 1995/06/07 21:27:57 sos Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include + + +static int +linux_to_bsd_domain(int domain) +{ + switch (domain) { + case LINUX_AF_UNSPEC: + return AF_UNSPEC; + case LINUX_AF_UNIX: + return AF_LOCAL; + case LINUX_AF_INET: + return AF_INET; + case LINUX_AF_AX25: + return AF_CCITT; + case LINUX_AF_IPX: + return AF_IPX; + case LINUX_AF_APPLETALK: + return AF_APPLETALK; + default: + return -1; + } +} + +static int +linux_to_bsd_sockopt_level(int level) +{ + switch (level) { + case LINUX_SOL_SOCKET: + return SOL_SOCKET; + default: + return level; + } +} + +static int linux_to_bsd_ip_sockopt(int opt) +{ + switch (opt) { + case LINUX_IP_TOS: + return IP_TOS; + case LINUX_IP_TTL: + return IP_TTL; + default: + return -1; + } +} + +static int +linux_to_bsd_so_sockopt(int opt) +{ + switch (opt) { + case LINUX_SO_DEBUG: + return SO_DEBUG; + case LINUX_SO_REUSEADDR: + return SO_REUSEADDR; + case LINUX_SO_TYPE: + return SO_TYPE; + case LINUX_SO_ERROR: + return SO_ERROR; + case LINUX_SO_DONTROUTE: + return SO_DONTROUTE; + case LINUX_SO_BROADCAST: + return SO_BROADCAST; + case LINUX_SO_SNDBUF: + return SO_SNDBUF; + case LINUX_SO_RCVBUF: + return SO_RCVBUF; + case LINUX_SO_KEEPALIVE: + return SO_KEEPALIVE; + case LINUX_SO_OOBINLINE: + return SO_OOBINLINE; + case LINUX_SO_LINGER: + return SO_LINGER; + case LINUX_SO_PRIORITY: + case LINUX_SO_NO_CHECK: + default: + return -1; + } +} + +struct linux_socket_args { + int domain; + int type; + int protocol; +}; + +static int +linux_socket(struct proc *p, struct linux_socket_args *args, int *retval) +{ + struct linux_socket_args linux_args; + struct { + int domain; + int type; + int protocol; + } bsd_args; + int error; + + if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) + return error; + bsd_args.protocol = linux_args.protocol; + bsd_args.type = linux_args.type; + bsd_args.domain = linux_to_bsd_domain(linux_args.domain); + if (bsd_args.domain == -1) + return EINVAL; + return socket(p, &bsd_args, retval); +} + +struct linux_bind_args { + int s; + struct sockaddr *name; + int namelen; +}; + +static int +linux_bind(struct proc *p, struct linux_bind_args *args, int *retval) +{ + struct linux_bind_args linux_args; + struct { + int s; + caddr_t name; + int namelen; + } bsd_args; + int error; + + if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) + return error; + bsd_args.s = linux_args.s; + bsd_args.name = (caddr_t)linux_args.name; + bsd_args.namelen = linux_args.namelen; + return bind(p, &bsd_args, retval); +} + +struct linux_connect_args { + int s; + struct sockaddr * name; + int namelen; +}; + +static int +linux_connect(struct proc *p, struct linux_connect_args *args, int *retval) +{ + struct linux_connect_args linux_args; + struct { + int s; + caddr_t name; + int namelen; + } bsd_args; + int error; + + if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) + return error; + bsd_args.s = linux_args.s; + bsd_args.name = (caddr_t)linux_args.name; + bsd_args.namelen = linux_args.namelen; + return connect(p, &bsd_args, retval); +} + +struct linux_listen_args { + int s; + int backlog; +}; + +static int +linux_listen(struct proc *p, struct linux_listen_args *args, int *retval) +{ + struct linux_listen_args linux_args; + struct { + int s; + int backlog; + } bsd_args; + int error; + + if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) + return error; + bsd_args.s = linux_args.s; + bsd_args.backlog = linux_args.backlog; + return listen(p, &bsd_args, retval); +} + +struct linux_accept_args { + int s; + struct sockaddr *addr; + int *namelen; +}; + +static int +linux_accept(struct proc *p, struct linux_accept_args *args, int *retval) +{ + struct linux_accept_args linux_args; + struct accept_args { + int s; + caddr_t name; + int *anamelen; + } bsd_args; + int error; + + if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) + return error; + bsd_args.s = linux_args.s; + bsd_args.name = (caddr_t)linux_args.addr; + bsd_args.anamelen = linux_args.namelen; + return oaccept(p, &bsd_args, retval); +} + +struct linux_getsockname_args { + int s; + struct sockaddr *addr; + int *namelen; +}; + +static int +linux_getsockname(struct proc *p, struct linux_getsockname_args *args, int *retval) +{ + struct linux_getsockname_args linux_args; + struct { + int fdes; + caddr_t asa; + int *alen; + } bsd_args; + int error; + + if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) + return error; + bsd_args.fdes = linux_args.s; + bsd_args.asa = (caddr_t) linux_args.addr; + bsd_args.alen = linux_args.namelen; + return ogetsockname(p, &bsd_args, retval); +} + +struct linux_getpeername_args { + int s; + struct sockaddr *addr; + int *namelen; +}; + +static int +linux_getpeername(struct proc *p, struct linux_getpeername_args *args, int *retval) +{ + struct linux_getpeername_args linux_args; + struct getpeername_args { + int fdes; + caddr_t asa; + int *alen; + } bsd_args; + int error; + + if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) + return error; + bsd_args.fdes = linux_args.s; + bsd_args.asa = (caddr_t) linux_args.addr; + bsd_args.alen = linux_args.namelen; + return ogetpeername(p, &bsd_args, retval); +} + +struct linux_socketpair_args { + int domain; + int type; + int protocol; + int *rsv; +}; + +static int +linux_socketpair(struct proc *p, struct linux_socketpair_args *args, int *retval) +{ + struct linux_socketpair_args linux_args; + struct { + int domain; + int type; + int protocol; + int *rsv; + } bsd_args; + int error; + + if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) + return error; + bsd_args.domain = linux_to_bsd_domain(linux_args.domain); + if (bsd_args.domain == -1) + return EINVAL; + bsd_args.type = linux_args.type; + bsd_args.protocol = linux_args.protocol; + bsd_args.rsv = linux_args.rsv; + return socketpair(p, &bsd_args, retval); +} + +struct linux_send_args { + int s; + void *msg; + int len; + int flags; +}; + +static int +linux_send(struct proc *p, struct linux_send_args *args, int *retval) +{ + struct linux_send_args linux_args; + struct { + int s; + caddr_t buf; + int len; + int flags; + } bsd_args; + int error; + + if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) + return error; + bsd_args.s = linux_args.s; + bsd_args.buf = linux_args.msg; + bsd_args.len = linux_args.len; + bsd_args.flags = linux_args.flags; + return osend(p, &bsd_args, retval); +} + +struct linux_recv_args { + int s; + void *msg; + int len; + int flags; +}; + +static int +linux_recv(struct proc *p, struct linux_recv_args *args, int *retval) +{ + struct linux_recv_args linux_args; + struct { + int s; + caddr_t buf; + int len; + int flags; + } bsd_args; + int error; + + if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) + return error; + bsd_args.s = linux_args.s; + bsd_args.buf = linux_args.msg; + bsd_args.len = linux_args.len; + bsd_args.flags = linux_args.flags; + return orecv(p, &bsd_args, retval); +} + +struct linux_sendto_args { + int s; + void *msg; + int len; + int flags; + caddr_t to; + int tolen; +}; + +static int +linux_sendto(struct proc *p, struct linux_sendto_args *args, int *retval) +{ + struct linux_sendto_args linux_args; + struct { + int s; + caddr_t buf; + size_t len; + int flags; + caddr_t to; + int tolen; + } bsd_args; + int error; + + if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) + return error; + bsd_args.s = linux_args.s; + bsd_args.buf = linux_args.msg; + bsd_args.len = linux_args.len; + bsd_args.flags = linux_args.flags; + bsd_args.to = linux_args.to; + bsd_args.tolen = linux_args.tolen; + return sendto(p, &bsd_args, retval); +} + +struct linux_recvfrom_args { + int s; + void *buf; + int len; + int flags; + caddr_t from; + int *fromlen; +}; + +static int +linux_recvfrom(struct proc *p, struct linux_recvfrom_args *args, int *retval) +{ + struct linux_recvfrom_args linux_args; + struct { + int s; + caddr_t buf; + size_t len; + int flags; + caddr_t from; + int *fromlenaddr; + } bsd_args; + int error; + + if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) + return error; + bsd_args.s = linux_args.s; + bsd_args.buf = linux_args.buf; + bsd_args.len = linux_args.len; + bsd_args.flags = linux_args.flags; + bsd_args.from = linux_args.from; + bsd_args.fromlenaddr = linux_args.fromlen; + return orecvfrom(p, &bsd_args, retval); +} + +struct linux_shutdown_args { + int s; + int how; +}; + +static int +linux_shutdown(struct proc *p, struct linux_shutdown_args *args, int *retval) +{ + struct linux_shutdown_args linux_args; + struct { + int s; + int how; + } bsd_args; + int error; + + if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) + return error; + bsd_args.s = linux_args.s; + bsd_args.how = linux_args.how; + return shutdown(p, &bsd_args, retval); +} + +struct linux_setsockopt_args { + int s; + int level; + int optname; + void *optval; + int optlen; +}; + +static int +linux_setsockopt(struct proc *p, struct linux_setsockopt_args *args, int *retval) +{ + struct linux_setsockopt_args linux_args; + struct { + int s; + int level; + int name; + caddr_t val; + int valsize; + } bsd_args; + int error, name; + + if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) + return error; + bsd_args.s = linux_args.s; + bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level); + switch (bsd_args.level) { + case SOL_SOCKET: + name = linux_to_bsd_so_sockopt(linux_args.optname); + break; + case IPPROTO_IP: + name = linux_to_bsd_ip_sockopt(linux_args.optname); + break; + default: + return EINVAL; + } + if (name == -1) + return EINVAL; + bsd_args.name = name; + bsd_args.val = linux_args.optval; + bsd_args.valsize = linux_args.optlen; + return setsockopt(p, &bsd_args, retval); +} + +struct linux_getsockopt_args { + int s; + int level; + int optname; + void *optval; + int *optlen; +}; + +static int +linux_getsockopt(struct proc *p, struct linux_getsockopt_args *args, int *retval) +{ + struct linux_getsockopt_args linux_args; + struct { + int s; + int level; + int name; + caddr_t val; + int *avalsize; + } bsd_args; + int error, name; + + if ((error=copyin((caddr_t)args, (caddr_t)&linux_args, sizeof(linux_args)))) + return error; + bsd_args.s = linux_args.s; + bsd_args.level = linux_to_bsd_sockopt_level(linux_args.level); + switch (bsd_args.level) { + case SOL_SOCKET: + name = linux_to_bsd_so_sockopt(linux_args.optname); + break; + case IPPROTO_IP: + name = linux_to_bsd_ip_sockopt(linux_args.optname); + break; + default: + return EINVAL; + } + if (name == -1) + return EINVAL; + bsd_args.val = linux_args.optval; + bsd_args.avalsize = linux_args.optlen; + return getsockopt(p, &bsd_args, retval); +} + +struct linux_socketcall_args { + int what; + void *args; +}; + +int +linux_socketcall(struct proc *p, struct linux_socketcall_args *args,int *retval) +{ + switch (args->what) { + case LINUX_SOCKET: + return linux_socket(p, args->args, retval); + case LINUX_BIND: + return linux_bind(p, args->args, retval); + case LINUX_CONNECT: + return linux_connect(p, args->args, retval); + case LINUX_LISTEN: + return linux_listen(p, args->args, retval); + case LINUX_ACCEPT: + return linux_accept(p, args->args, retval); + case LINUX_GETSOCKNAME: + return linux_getsockname(p, args->args, retval); + case LINUX_GETPEERNAME: + return linux_getpeername(p, args->args, retval); + case LINUX_SOCKETPAIR: + return linux_socketpair(p, args->args, retval); + case LINUX_SEND: + return linux_send(p, args->args, retval); + case LINUX_RECV: + return linux_recv(p, args->args, retval); + case LINUX_SENDTO: + return linux_sendto(p, args->args, retval); + case LINUX_RECVFROM: + return linux_recvfrom(p, args->args, retval); + case LINUX_SHUTDOWN: + return linux_shutdown(p, args->args, retval); + case LINUX_SETSOCKOPT: + return linux_setsockopt(p, args->args, retval); + case LINUX_GETSOCKOPT: + return linux_getsockopt(p, args->args, retval); + default: + uprintf("LINUX: 'socket' typ=%d not implemented\n", args->what); + return ENOSYS; + } +} diff --git a/sys/compat/linux/linux_stats.c b/sys/compat/linux/linux_stats.c new file mode 100644 index 0000000..1dbfcf1 --- /dev/null +++ b/sys/compat/linux/linux_stats.c @@ -0,0 +1,273 @@ +/*- + * 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. + * + * $Id: linux_stats.c,v 1.3 1995/06/08 13:50:52 sos Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +struct linux_newstat { + unsigned short stat_dev; + unsigned short __pad1; + unsigned long stat_ino; + unsigned short stat_mode; + unsigned short stat_nlink; + unsigned short stat_uid; + unsigned short stat_gid; + unsigned short stat_rdev; + unsigned short __pad2; + unsigned long stat_size; + unsigned long stat_blksize; + unsigned long stat_blocks; + unsigned long stat_atime; + unsigned long __unused1; + unsigned long stat_mtime; + unsigned long __unused2; + unsigned long stat_ctime; + unsigned long __unused3; + unsigned long __unused4; + unsigned long __unused5; +}; + +struct linux_newstat_args { + char *path; + struct linux_newstat *buf; +}; + +static int +newstat_copyout(struct stat *buf, void *ubuf) +{ + struct linux_newstat tbuf; + + tbuf.stat_dev = (buf->st_dev & 0xff) | ((buf->st_dev & 0xff00)<<10); + 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, int *retval) +{ + struct stat buf; + struct linux_newstat tbuf; + struct nameidata nd; + int error; + +#ifdef DEBUG + printf("Linux-emul(%d): newstat(%s, *)\n", p->p_pid, args->path); +#endif + NDINIT(&nd, LOOKUP, LOCKLEAF|FOLLOW, UIO_USERSPACE, args->path, p); + error = namei(&nd); + if (!error) { + error = vn_stat(nd.ni_vp, &buf, p); + vput(nd.ni_vp); + } + if (!error) + error = newstat_copyout(&buf, args->buf); + return error; +} + +int +linux_newlstat(struct proc *p, struct linux_newstat_args *args, int *retval) +{ + struct stat buf; + struct linux_newstat tbuf; + struct nameidata nd; + int error; + +#ifdef DEBUG + printf("Linux-emul(%d): newlstat(%s, *)\n", p->p_pid, args->path); +#endif + NDINIT(&nd, LOOKUP, LOCKLEAF|FOLLOW, UIO_USERSPACE, args->path, p); + error = namei(&nd); + if (!error) { + error = vn_stat(nd.ni_vp, &buf, p); + vput(nd.ni_vp); + } + if (!error) + error = newstat_copyout(&buf, args->buf); + return error; +} + +struct linux_newfstat_args { + int fd; + struct linux_newstat *buf; +}; + +int +linux_newfstat(struct proc *p, struct linux_newfstat_args *args, int *retval) +{ + struct linux_newstat tbuf; + struct filedesc *fdp = p->p_fd; + struct file *fp; + struct stat buf; + int error; + +#ifdef DEBUG + printf("Linux-emul(%d): newlstat(%d, *)\n", p->p_pid, args->fd); +#endif + if ((unsigned)args->fd >= fdp->fd_nfiles + || (fp = fdp->fd_ofiles[args->fd]) == NULL) + return EBADF; + switch (fp->f_type) { + case DTYPE_VNODE: + error = vn_stat((struct vnode *)fp->f_data, &buf, p); + break; + case DTYPE_SOCKET: + error = soo_stat((struct socket *)fp->f_data, &buf); + break; + default: + panic("LINUX newfstat"); + } + if (!error) + error = newstat_copyout(&buf, args->buf); + return error; +} + +struct linux_statfs { + long ftype; + long fbsize; + long fblocks; + long fbfree; + long fbavail; + long ffiles; + long fffree; + linux_fsid_t ffsid; + long fnamelen; + long fspare[6]; +}; + + +struct linux_statfs_args { + char *path; + struct statfs *buf; +}; + +int +linux_statfs(struct proc *p, struct linux_statfs_args *args, int *retval) +{ + struct mount *mp; + struct nameidata *ndp; + struct statfs *bsd_statfs; + struct nameidata nd; + struct linux_statfs linux_statfs; + int error; + +#ifdef DEBUG + printf("Linux-emul(%d): statfs(%s, *)\n", p->p_pid, args->path); +#endif + ndp = &nd; + ndp->ni_cnd.cn_nameiop = LOOKUP; + ndp->ni_cnd.cn_flags = FOLLOW; + ndp->ni_cnd.cn_proc = curproc; + ndp->ni_cnd.cn_cred = curproc->p_cred->pc_ucred; + ndp->ni_segflg = UIO_USERSPACE; + ndp->ni_dirp = args->path; + if (error = namei(ndp)) + return error; + mp = ndp->ni_vp->v_mount; + bsd_statfs = &mp->mnt_stat; + vrele(ndp->ni_vp); + if (error = VFS_STATFS(mp, bsd_statfs, p)) + return error; + bsd_statfs->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; + linux_statfs.ftype = bsd_statfs->f_type; + linux_statfs.fbsize = bsd_statfs->f_bsize; + linux_statfs.fblocks = bsd_statfs->f_blocks; + linux_statfs.fbfree = bsd_statfs->f_bfree; + linux_statfs.fbavail = bsd_statfs->f_bavail; + linux_statfs.fffree = bsd_statfs->f_ffree; + linux_statfs.ffiles = bsd_statfs->f_files; + linux_statfs.ffsid.val[0] = bsd_statfs->f_fsid.val[0]; + linux_statfs.ffsid.val[1] = bsd_statfs->f_fsid.val[1]; + linux_statfs.fnamelen = MAXNAMLEN; + return copyout((caddr_t)&linux_statfs, (caddr_t)args->buf, + sizeof(struct linux_statfs)); +} + +struct linux_fstatfs_args { + int fd; + struct statfs *buf; +}; + +int +linux_fstatfs(struct proc *p, struct linux_fstatfs_args *args, int *retval) +{ + struct file *fp; + struct mount *mp; + struct statfs *bsd_statfs; + struct linux_statfs linux_statfs; + int error; + +#ifdef DEBUG + printf("Linux-emul(%d): fstatfs(%d, *)\n", p->p_pid, args->fd); +#endif + if (error = getvnode(p->p_fd, args->fd, &fp)) + return error; + mp = ((struct vnode *)fp->f_data)->v_mount; + bsd_statfs = &mp->mnt_stat; + if (error = VFS_STATFS(mp, bsd_statfs, p)) + return error; + bsd_statfs->f_flags = mp->mnt_flag & MNT_VISFLAGMASK; + linux_statfs.ftype = bsd_statfs->f_type; + linux_statfs.fbsize = bsd_statfs->f_bsize; + linux_statfs.fblocks = bsd_statfs->f_blocks; + linux_statfs.fbfree = bsd_statfs->f_bfree; + linux_statfs.fbavail = bsd_statfs->f_bavail; + linux_statfs.fffree = bsd_statfs->f_ffree; + linux_statfs.ffiles = bsd_statfs->f_files; + linux_statfs.ffsid.val[0] = bsd_statfs->f_fsid.val[0]; + linux_statfs.ffsid.val[1] = bsd_statfs->f_fsid.val[1]; + linux_statfs.fnamelen = MAXNAMLEN; + return copyout((caddr_t)&linux_statfs, (caddr_t)args->buf, + sizeof(struct linux_statfs)); +} -- cgit v1.1