/*
* Copyright (c) 2001 Matthew R. Green
* 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.
*
* 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.
*/
/*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Lawrence Berkeley Laboratory.
*
* 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. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*
* @(#)sunos_misc.c 8.1 (Berkeley) 6/18/93
*
* Header: sunos_misc.c,v 1.16 93/04/07 02:46:27 torek Exp
*/
/*
* SunOS compatibility module, 64-bit kernel version
*
* SunOS system calls that are implemented differently in BSD are
* handled here.
*/
int
sunos32_sys_lstat(struct lwp *l, const struct sunos32_sys_lstat_args *uap, register_t *retval)
{
/* {
syscallarg(const netbsd32_charp) path;
syscallarg(netbsd32_stat43p_t) ub;
} */
struct stat sb;
struct netbsd32_stat43 sb32;
int error;
error = do_sys_stat(SCARG_P32(uap, path), NOFOLLOW, &sb);
if (error)
return error;
/*
* For symbolic links, SunOS returned the attributes of its
* containing directory, except for mode, size, and links.
* This is no longer emulated, the parent directory is not consulted.
*/
sunos32_from___stat13(&sb, &sb32);
error = copyout((void *)&sb32, SCARG_P32(uap, ub), sizeof (sb32));
return (error);
}
/*
* Read Sun-style directory entries. We suck them into kernel space so
* that they can be massaged before being copied out to user code. Like
* SunOS, we squish out `empty' entries.
*
* This is quite ugly, but what do you expect from compatibility code?
*/
int
sunos32_sys_getdents(struct lwp *l, const struct sunos32_sys_getdents_args *uap, register_t *retval)
{
/* {
syscallarg(int) fd;
syscallarg(netbsd32_charp) buf;
syscallarg(int) nbytes;
} */
struct dirent *bdp;
struct vnode *vp;
char *inp, *sbuf; /* BSD-format */
int len, reclen; /* BSD-format */
char *outp; /* Sun-format */
int resid, sunos_reclen;/* Sun-format */
struct file *fp;
struct uio auio;
struct iovec aiov;
struct sunos32_dirent idb;
off_t off; /* true file offset */
int buflen, error, eofflag;
off_t *cookiebuf, *cookie;
int ncookies;
/* fd_getvnode() will use the descriptor for us */
if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
return (error);
buflen = uimin(MAXBSIZE, SCARG(uap, nbytes));
sbuf = malloc(buflen, M_TEMP, M_WAITOK);
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
off = fp->f_offset;
again:
aiov.iov_base = sbuf;
aiov.iov_len = buflen;
auio.uio_iov = &aiov;
auio.uio_iovcnt = 1;
auio.uio_rw = UIO_READ;
auio.uio_resid = buflen;
auio.uio_offset = off;
UIO_SETUP_SYSSPACE(&auio);
/*
* First we read into the malloc'ed buffer, then
* we massage it into user space, one record at a time.
*/
error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &cookiebuf,
&ncookies);
if (error)
goto out;
for (cookie = cookiebuf; len > 0; len -= reclen) {
bdp = (struct dirent *)inp;
reclen = bdp->d_reclen;
if (reclen & 3) {
error = EIO;
goto out;
}
if (cookie && (*cookie >> 32) != 0) {
compat_offseterr(vp, "sunos_getdents");
error = EINVAL;
goto out;
}
if (bdp->d_fileno == 0) {
inp += reclen; /* it is a hole; squish it out */
if (cookie)
off = *cookie++;
else
off += reclen;
continue;
}
memset(&idb, 0, sizeof(idb));
sunos_reclen = SUNOS32_RECLEN(&idb, bdp->d_namlen);
if (reclen > len || resid < sunos_reclen) {
/* entry too big for buffer, so just stop */
outp++;
break;
}
if (cookie)
off = *cookie++; /* each entry points to next */
else
off += reclen;
/*
* Massage in place to make a Sun-shaped dirent (otherwise
* we have to worry about touching user memory outside of
* the copyout() call).
*/
idb.d_fileno = bdp->d_fileno;
idb.d_off = off;
idb.d_reclen = sunos_reclen;
idb.d_namlen = bdp->d_namlen;
strlcpy(idb.d_name, bdp->d_name, sizeof(idb.d_name));
if ((error = copyout((void *)&idb, outp, sunos_reclen)) != 0)
goto out;
/* advance past this real entry */
inp += reclen;
/* advance output past Sun-shaped entry */
outp += sunos_reclen;
resid -= sunos_reclen;
}
/* if we squished out the whole block, try again */
if (outp == SCARG_P32(uap, buf)) {
if (cookiebuf)
free(cookiebuf, M_TEMP);
cookiebuf = NULL;
goto again;
}
fp->f_offset = off; /* update the vnode offset */
error = sys_mmap(l, &ua, retval);
if ((u_long)*retval > (u_long)UINT_MAX) {
printf("sunos32_mmap: retval out of range: 0x%lx\n",
(u_long)*retval);
/* Should try to recover and return an error here. */
}
return (error);
}
switch (SCARG(uap, func)) {
case MC_ADVISE: /* ignore for now */
return (0);
case MC_SYNC: /* translate to msync */
return (netbsd32___msync13(l, (const void *)uap, retval));
default:
return (EINVAL);
}
}
int
sunos32_sys_setsockopt(struct lwp *l, const struct sunos32_sys_setsockopt_args *uap, register_t *retval)
{
/* {
syscallarg(int) s;
syscallarg(int) level;
syscallarg(int) name;
syscallarg(netbsd32_caddr_t) val;
syscallarg(int) valsize;
} */
struct sockopt sopt;
struct socket *so;
int name = SCARG(uap, name);
int error;
/* fd_getsock() will use the descriptor for us */
if ((error = fd_getsock(SCARG(uap, s), &so)) != 0)
return (error);
#define SO_DONTLINGER (~SO_LINGER)
if (name == SO_DONTLINGER) {
struct linger lg;
static inline int sunos32_sys_socket_common(struct lwp *, register_t *,
int type);
static inline int
sunos32_sys_socket_common(struct lwp *l, register_t *retval, int type)
{
struct socket *so;
int error, fd;
/* fd_getsock() will use the descriptor for us */
fd = (int)*retval;
if ((error = fd_getsock(fd, &so)) == 0) {
if (type == SOCK_DGRAM)
so->so_options |= SO_BROADCAST;
fd_putfile(fd);
}
return (error);
}
/*
* difference to our setpgid call is to include backwards
* compatibility to pre-setsid() binaries. Do setsid()
* instead of setpgid() in those cases where the process
* tries to create a new session the old way.
*/
if (!SCARG(uap, pgid) &&
(!SCARG(uap, pid) || SCARG(uap, pid) == p->p_pid))
return sys_setsid(l, NULL, retval);
else
return netbsd32_setpgid(l, (const void *)uap, retval);
}
int
sunos32_sys_open(struct lwp *l, const struct sunos32_sys_open_args *uap, register_t *retval)
{
/* {
syscallarg(const netbsd32_charp) path;
syscallarg(int) flags;
syscallarg(int) mode;
} */
struct proc *p = l->l_proc;
struct sys_open_args ua;
int lf, r;
int noctty;
int ret;
/* XXXSMP unlocked */
if (!ret && !noctty && SESS_LEADER(p) && !(p->p_lflag & PL_CONTROLT)) {
file_t *fp;
int fd;
fd = (int)*retval;
fp = fd_getfile(fd);
/* ignore any error, just give it a try */
if (fp != NULL) {
if (fp->f_type == DTYPE_VNODE)
(fp->f_ops->fo_ioctl)(fp, TIOCSCTTY, NULL);
fd_putfile(fd);
}
}
return ret;
}
/*
* SunOS reboot system call (for compatibility).
* Sun lets you pass in a boot string which the PROM
* saves and provides to the next boot program.
*/
/*
* Sun RB_STRING (Get user supplied bootstring.)
* If the machine supports passing a string to the
* next booted kernel.
*/
if (sun_howto & SUNOS_RB_STRING)
bootstr = SCARG_P32(uap, bootstr);
else
bootstr = NULL;
if (SCARG_P32(uap, nsv)) {
error = copyin(SCARG_P32(uap, nsv), &sv, sizeof(sv));
if (error != 0)
return (error);
/*
* SunOS uses the mask 0x0004 as SV_RESETHAND
* meaning: `reset to SIG_DFL on delivery'.
* We support only the bits in: 0xF
* (those bits are the same as ours)
*/
if (sv.sv_flags & ~0xF)
return (EINVAL);