/*	$NetBSD: osf1_misc.c,v 1.2 1995/03/21 13:34:26 mycroft Exp $	*/

/*
 * Copyright (c) 1994, 1995 Carnegie-Mellon University.
 * All rights reserved.
 *
 * Author: Chris G. Demetriou
 * 
 * Permission to use, copy, modify and distribute this software and
 * its documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 * 
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 
 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 * 
 * Carnegie Mellon requests users of this software to return to
 *
 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 *
 * any improvements or extensions that they make and grant Carnegie the
 * rights to redistribute these changes.
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/exec.h>
#include <sys/file.h>
#include <sys/filedesc.h>
#include <sys/proc.h>
#include <sys/malloc.h>
#include <sys/mman.h>
#include <sys/namei.h>
#include <sys/reboot.h>
#include <sys/signal.h>
#include <sys/stat.h>
#include <vm/vm.h>

#include <sys/mount.h>
#include <sys/syscallargs.h>
#include <compat/osf1/osf1_syscallargs.h>

#ifdef SYSCALL_DEBUG
extern int scdebug;
#endif

int
osf1_open(p, uap, retval)
	struct proc *p;
	struct osf1_open_args /* {
		syscallarg(char *) path;
		syscallarg(int) flags;
		syscallarg(int) mode;
	} */ *uap;
	register_t *retval;
{
	struct open_args /* {
		syscallarg(char *) path;
		syscallarg(int) flags;
		syscallarg(int) mode;
	} */ a;
#ifdef SYSCALL_DEBUG
	char pnbuf[1024];

	if (scdebug &&
	    copyinstr(SCARG(uap, path), pnbuf, sizeof pnbuf, NULL) == 0)
		printf("osf1_open: open: %s\n", pnbuf);
#endif

	SCARG(&a, path) = SCARG(uap, path);
	SCARG(&a, flags) = SCARG(uap, flags);		/* XXX translate */
	SCARG(&a, mode) = SCARG(uap, mode);

	return open(p, &a, retval);
}

int
osf1_setsysinfo(p, uap, retval)
	struct proc *p;
	struct osf1_setsysinfo_args /* {
		syscallarg(u_long) op;
		syscallarg(caddr_t) buffer;
		syscallarg(u_long) nbytes;
		syscallarg(caddr_t) arg;
		syscallarg(u_long) flag;
	} */ *uap;
	register_t *retval;
{

	return (0);
}

#define OSF1_RLIMIT_LASTCOMMON	5		/* last one that's common */
#define OSF1_RLIMIT_NOFILE	6		/* OSF1's RLIMIT_NOFILE */
#define OSF1_RLIMIT_NLIMITS	8		/* Number of OSF1 rlimits */

osf1_getrlimit(p, uap, retval)
	struct proc *p;
	struct osf1_getrlimit_args /* {
		syscallarg(u_int) which;
		syscallarg(struct rlimit *) rlp;
	} */ *uap;
	register_t *retval;
{
	struct getrlimit_args /* {
		syscallarg(u_int) which;
		syscallarg(struct rlimit *) rlp;
	} */ a;

	if (SCARG(uap, which) >= OSF1_RLIMIT_NLIMITS)
		return (EINVAL);

	if (SCARG(uap, which) <= OSF1_RLIMIT_LASTCOMMON)
		SCARG(&a, which) = SCARG(uap, which);
	else if (SCARG(uap, which) == OSF1_RLIMIT_NOFILE)
		SCARG(&a, which) = RLIMIT_NOFILE;
	else
		return (0);
	SCARG(&a, rlp) = SCARG(uap, rlp);

	return getrlimit(p, &a, retval);
}

osf1_setrlimit(p, uap, retval)
	struct proc *p;
	struct osf1_setrlimit_args /* {
		syscallarg(u_int) which;
		syscallarg(struct rlimit *) rlp;
	} */ *uap;
	register_t *retval;
{
	struct setrlimit_args /* {
		syscallarg(u_int) which;
		syscallarg(struct rlimit *) rlp;
	} */ a;

	if (SCARG(uap, which) >= OSF1_RLIMIT_NLIMITS)
		return (EINVAL);

	if (SCARG(uap, which) <= OSF1_RLIMIT_LASTCOMMON)
		SCARG(&a, which) = SCARG(uap, which);
	else if (SCARG(uap, which) == OSF1_RLIMIT_NOFILE)
		SCARG(&a, which) = RLIMIT_NOFILE;
	else
		return (0);
	SCARG(&a, rlp) = SCARG(uap, rlp);

	return setrlimit(p, &a, retval);
}

#define	OSF1_MAP_SHARED		0x001
#define OSF1_MAP_PRIVATE	0x002
#define	OSF1_MAP_ANONYMOUS	0x010
#define	OSF1_MAP_FILE		0x000
#define OSF1_MAP_TYPE		0x0f0
#define	OSF1_MAP_FIXED		0x100
#define	OSF1_MAP_HASSEMAPHORE	0x200
#define	OSF1_MAP_INHERIT	0x400
#define	OSF1_MAP_UNALIGNED	0x800

int
osf1_mmap(p, uap, retval)
	struct proc *p;
	struct osf1_mmap_args /* {
		syscallarg(caddr_t) addr;
		syscallarg(size_t) len;
		syscallarg(int) prot;
		syscallarg(int) flags;
		syscallarg(int) fd;
		syscallarg(off_t) pos;
	} */ *uap;
	register_t *retval;
{
	struct mmap_args /* {
		syscallarg(caddr_t) addr;
		syscallarg(size_t) len;
		syscallarg(int) prot;
		syscallarg(int) flags;
		syscallarg(int) fd;
		syscallarg(long) pad;
		syscallarg(off_t) pos;
	} */ a;

	SCARG(&a, addr) = SCARG(uap, addr);
	SCARG(&a, len) = SCARG(uap, len);
	SCARG(&a, prot) = SCARG(uap, prot);
	SCARG(&a, fd) = SCARG(uap, fd);
	SCARG(&a, pad) = 0;
	SCARG(&a, pos) = SCARG(uap, pos);

	SCARG(&a, flags) = 0;
	if (SCARG(uap, flags) & OSF1_MAP_SHARED)
		SCARG(&a, flags) |= MAP_SHARED;
	if (SCARG(uap, flags) & OSF1_MAP_PRIVATE)
		SCARG(&a, flags) |= MAP_PRIVATE;
	switch (SCARG(uap, flags) & OSF1_MAP_TYPE) {
	case OSF1_MAP_ANONYMOUS:
		SCARG(&a, flags) |= MAP_ANON;
		break;
	case OSF1_MAP_FILE:
		SCARG(&a, flags) |= MAP_FILE;
		break;
	default:
		return (EINVAL);
	}
	if (SCARG(uap, flags) & OSF1_MAP_FIXED)
		SCARG(&a, flags) |= MAP_FIXED;
	if (SCARG(uap, flags) & OSF1_MAP_HASSEMAPHORE)
		SCARG(&a, flags) |= MAP_HASSEMAPHORE;
	if (SCARG(uap, flags) & OSF1_MAP_INHERIT)
		SCARG(&a, flags) |= MAP_INHERIT;
	if (SCARG(uap, flags) & OSF1_MAP_UNALIGNED)
		return (EINVAL);

	return mmap(p, &a, retval);
}

int
osf1_usleep_thread(p, uap, retval)
	struct proc *p;
	struct osf1_usleep_thread_args /* {
		syscallarg(struct timeval *) sleep;
		syscallarg(struct timeval *) slept;
	} */ *uap;
	register_t *retval;
{
	struct timeval tv, endtv;
	u_long ticks;
	int error, s;

	if (error = copyin(SCARG(uap, sleep), &tv, sizeof tv))
		return (error);

	ticks = ((u_long)tv.tv_sec * 1000000 + tv.tv_usec) / tick;
	s = splclock();
	tv = time;
	splx(s);

	tsleep(p, PUSER|PCATCH, "OSF/1", ticks);	/* XXX */

	if (SCARG(uap, slept) != NULL) {
		s = splclock();
		timersub(&time, &tv, &endtv);
		splx(s);
		if (tv.tv_sec < 0 || tv.tv_usec < 0)
			tv.tv_sec = tv.tv_usec = 0;

		error = copyout(&endtv, SCARG(uap, slept), sizeof endtv);
	}
	return (error);
}

#define	OSF1_SA_ONSTACK		0x00000001
#define	OSF1_SA_RESTART		0x00000002
#define	OSF1_SA_NOCLDSTOP	0x00000004
#define	OSF1_SA_NODEFER		0x00000008
#define	OSF1_SA_RESETHAND	0x00000010
#define	OSF1_SA_NOCLDWAIT	0x00000020
#define	OSF1_SA_SIGINFO		0x00000040

static int
copysigaction(osf, bsd)
	struct sigaction *osf;
	struct sigaction *bsd;
{

	bsd->sa_handler = osf->sa_handler;
	bsd->sa_mask = osf->sa_mask;
	bsd->sa_flags = 0;
	if (osf->sa_flags & (OSF1_SA_NODEFER|OSF1_SA_RESETHAND|
	    OSF1_SA_NOCLDWAIT|OSF1_SA_SIGINFO))
		return (EINVAL);
	if (osf->sa_flags & OSF1_SA_ONSTACK)
		bsd->sa_flags |= SA_ONSTACK;
	if (osf->sa_flags & OSF1_SA_RESTART)
		bsd->sa_flags |= SA_RESTART;
	if (osf->sa_flags & OSF1_SA_NOCLDSTOP)
		bsd->sa_flags |= SA_NOCLDSTOP;
}

int
osf1_sigaction(p, uap, retval)
	struct proc *p;
	struct osf1_sigaction_args /* {
		syscallarg(int) signum;
		syscallarg(struct sigaction *) nsa;
		syscallarg(struct sigaction *) osa;
	} */ *uap;
	register_t *retval;
{
	struct sigaction_args /* {
		syscallarg(int) signum;
		syscallarg(struct sigaction *) nsa;
		syscallarg(struct sigaction *) osa;
	} */ a;
	struct sigaction osf1_nsa, osf1_osa;
	struct sigaction bsd_nsa, bsd_osa;
	int error;
	extern char sigcode[], esigcode[];
#define	szsigcode	(esigcode - sigcode)

	SCARG(&a, signum) = SCARG(uap, signum);
	if (SCARG(uap, nsa) == NULL)
		SCARG(&a, nsa) = NULL;
	else {
		if (error = copyin(SCARG(uap, nsa), &osf1_nsa, sizeof osf1_nsa))
			return (error);
		if (error = copysigaction(&osf1_nsa, &bsd_nsa))
			return (error);
		SCARG(&a, nsa) = (struct sigaction *)
		    ALIGN(PS_STRINGS - szsigcode - STACKGAPLEN);
		if (error = copyout(&bsd_nsa, SCARG(&a, nsa), sizeof bsd_nsa))
			return (error);
	}
	if (SCARG(uap, osa) == NULL)
		SCARG(&a, osa) = NULL;
	else {
		if (error = copyin(SCARG(uap, osa), &osf1_osa, sizeof osf1_osa))
			return (error);
		if (error = copysigaction(&osf1_osa, &bsd_osa))
			return (error);
		SCARG(&a, osa) = (struct sigaction *)
		    ALIGN(PS_STRINGS - szsigcode - STACKGAPLEN +
		    sizeof(struct sigaction));
		if (error = copyout(&bsd_osa, SCARG(&a, osa), sizeof bsd_osa))
			return (error);
	}

	/* XXX should return old sigaction, if requested. */
	return sigaction(p, &a, retval);
}

struct osf1_stat {
	int32_t		st_dev;
	u_int32_t	st_ino;
	u_int32_t	st_mode;
	u_int16_t	st_nlink;
	u_int32_t	st_uid;
	u_int32_t	st_gid;
	int32_t		st_rdev;
	u_int64_t	st_size;
	int32_t		st_atime_sec;
	int32_t		st_spare1;
	int32_t		st_mtime_sec;
	int32_t		st_spare2;
	int32_t		st_ctime_sec;
	int32_t		st_spare3;
	u_int32_t	st_blksize;
	int32_t		st_blocks;
	u_int32_t	st_flags;
	u_int32_t	st_gen;
};

/*
 * Get file status; this version follows links.
 */
/* ARGSUSED */
osf1_stat(p, uap, retval)
	struct proc *p;
	register struct osf1_stat_args /* {
		syscallarg(char *) path;
		syscallarg(struct osf1_stat *) ub;
	} */ *uap;
	register_t *retval;
{
	struct stat sb;
	struct osf1_stat osb;
	int error;
	struct nameidata nd;

	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
	    SCARG(uap, path), p);
	if (error = namei(&nd))
		return (error);
	error = vn_stat(nd.ni_vp, &sb, p);
	vput(nd.ni_vp);
	if (error)
		return (error);
	cvtstat2osf1(&sb, &osb);
	error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb));
	return (error);
}

/*
 * Get file status; this version does not follow links.
 */
/* ARGSUSED */
osf1_lstat(p, uap, retval)
	struct proc *p;
	register struct osf1_lstat_args /* {
		syscallarg(char *) path;
		syscallarg(struct osf1_stat *) ub;
	} */ *uap;
	register_t *retval;
{
	struct stat sb;
	struct osf1_stat osb;
	int error;
	struct nameidata nd;

	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF, UIO_USERSPACE,
	    SCARG(uap, path), p);
	if (error = namei(&nd))
		return (error);
	error = vn_stat(nd.ni_vp, &sb, p);
	vput(nd.ni_vp);
	if (error)
		return (error);
	cvtstat2osf1(&sb, &osb);
	error = copyout((caddr_t)&osb, (caddr_t)SCARG(uap, ub), sizeof (osb));
	return (error);
}

/*
 * Return status information about a file descriptor.
 */
osf1_fstat(p, uap, retval)
	struct proc *p;
	register struct osf1_fstat_args /* {
		syscallarg(int) fd;
		syscallarg(struct osf1_stat *) sb;
	} */ *uap;
	register_t *retval;
{
	register struct filedesc *fdp = p->p_fd;
	register struct file *fp;
	struct stat ub;
	struct osf1_stat oub;
	int error;

	if ((unsigned)SCARG(uap, fd) >= fdp->fd_nfiles ||
	    (fp = fdp->fd_ofiles[SCARG(uap, fd)]) == NULL)
		return (EBADF);
	switch (fp->f_type) {

	case DTYPE_VNODE:
		error = vn_stat((struct vnode *)fp->f_data, &ub, p);
		break;

	case DTYPE_SOCKET:
		error = soo_stat((struct socket *)fp->f_data, &ub);
		break;

	default:
		panic("ofstat");
		/*NOTREACHED*/
	}
	cvtstat2osf1(&ub, &oub);
	if (error == 0)
		error = copyout((caddr_t)&oub, (caddr_t)SCARG(uap, sb),
		    sizeof (oub));
	return (error);
}

#define	bsd2osf_dev(dev)	(major(dev) << 20 | minor(dev))
#define	osf2bsd_dev(dev)	makedev((dev >> 20) & 0xfff, dev & 0xfffff)

/*
 * Convert from a stat structure to an osf1 stat structure.
 */
cvtstat2osf1(st, ost)
	struct stat *st;
	struct osf1_stat *ost;
{

	ost->st_dev = bsd2osf_dev(st->st_dev);
	ost->st_ino = st->st_ino;
	ost->st_mode = st->st_mode;
	ost->st_nlink = st->st_nlink;
	ost->st_uid = st->st_uid == -2 ? (u_int16_t) -2 : st->st_uid;
	ost->st_gid = st->st_gid == -2 ? (u_int16_t) -2 : st->st_gid;
	ost->st_rdev = bsd2osf_dev(st->st_rdev);
	ost->st_size = st->st_size;
	ost->st_atime_sec = st->st_atime;
	ost->st_spare1 = 0;
	ost->st_mtime_sec = st->st_mtime;
	ost->st_spare2 = 0;
	ost->st_ctime_sec = st->st_ctime;
	ost->st_spare3 = 0;
	ost->st_blksize = st->st_blksize;
	ost->st_blocks = st->st_blocks;
	ost->st_flags = st->st_flags;
	ost->st_gen = st->st_gen;
}

int
osf1_mknod(p, uap, retval)
	struct proc *p;
	struct osf1_mknod_args /* {
		syscallarg(char *) path;
		syscallarg(int) mode;
		syscallarg(int) dev;
	} */ *uap;
	register_t *retval;
{
	struct mknod_args a;

	SCARG(&a, path) = SCARG(uap, path);
	SCARG(&a, mode) = SCARG(uap, mode);
	SCARG(&a, dev) = osf2bsd_dev(SCARG(uap, dev));

	return mknod(p, &a, retval);
}

#define OSF1_F_DUPFD	0
#define	OSF1_F_GETFD	1
#define	OSF1_F_SETFD	2
#define	OSF1_F_GETFL	3
#define	OSF1_F_SETFL	4

#define	OSF1_FAPPEND	0x00008		/* XXX OSF1_O_APPEND */
#define	OSF1_FNONBLOCK	0x00004		/* XXX OSF1_O_NONBLOCK */
#define	OSF1_FASYNC	0x00040
#define	OSF1_FSYNC	0x04000		/* XXX OSF1_O_SYNC */

int
osf1_fcntl(p, uap, retval)
	struct proc *p;
	struct osf1_fcntl_args /* {
		syscallarg(int) fd;
		syscallarg(int) cmd;
		syscallarg(void *) arg;
	} */ *uap;
	register_t *retval;
{
	struct fcntl_args a;
	long tmp;
	int error;

	SCARG(&a, fd) = SCARG(uap, fd);

	switch (SCARG(uap, cmd)) {
	case OSF1_F_DUPFD:
		SCARG(&a, cmd) = F_DUPFD;
		SCARG(&a, arg) = SCARG(uap, arg);
		break;

	case OSF1_F_GETFD:
		SCARG(&a, cmd) = F_GETFD;
		SCARG(&a, arg) = SCARG(uap, arg);
		break;

	case OSF1_F_SETFD:
		SCARG(&a, cmd) = F_SETFD;
		SCARG(&a, arg) = SCARG(uap, arg);
		break;

	case OSF1_F_GETFL:
		SCARG(&a, cmd) = F_GETFL;
		SCARG(&a, arg) = SCARG(uap, arg);		/* ignored */
		break;

	case OSF1_F_SETFL:
		SCARG(&a, cmd) = F_SETFL;
		tmp = 0;
		if ((long)SCARG(uap, arg) & OSF1_FAPPEND)
			tmp |= FAPPEND;
		if ((long)SCARG(uap, arg) & OSF1_FNONBLOCK)
			tmp |= FNONBLOCK;
		if ((long)SCARG(uap, arg) & OSF1_FASYNC)
			tmp |= FASYNC;
		if ((long)SCARG(uap, arg) & OSF1_FSYNC)
			tmp |= FFSYNC;
		SCARG(&a, arg) = (void *)tmp;
		break;

	default:					/* XXX other cases */
		return (EINVAL);
	}

	error = fcntl(p, &a, retval);

	if (error)
		return error;

	switch (SCARG(uap, cmd)) {
	case OSF1_F_GETFL:
		/* XXX */
		break;
	}

	return error;
}

int
osf1_socket(p, uap, retval)
	struct proc *p;
	register struct osf1_socket_args /* {
		syscallarg(int) domain;
		syscallarg(int) type;
		syscallarg(int) protocol;
	} */ *uap;
	register_t *retval;
{
	struct socket_args a;

	if (SCARG(uap, type) > AF_LINK)
		return (EINVAL);	/* XXX After AF_LINK, divergence. */

	SCARG(&a, domain) = SCARG(uap, domain);
	SCARG(&a, type) = SCARG(uap, type);
	SCARG(&a, protocol) = SCARG(uap, protocol);

	return socket(p, &a, retval);
}

int
osf1_sendto(p, uap, retval)
	struct proc *p;
	register struct sendto_args /* {
		syscallarg(int) s;
		syscallarg(caddr_t) buf;
		syscallarg(size_t) len;
		syscallarg(int) flags;
		syscallarg(caddr_t) to;
		syscallarg(int) tolen;
	} */ *uap;
	register_t *retval;
{
	struct sendto_args a;

	if (SCARG(uap, flags) & ~0x7f)		/* unsupported flags */
		return (EINVAL);

	SCARG(&a, s) = SCARG(uap, s);
	SCARG(&a, buf) = SCARG(uap, buf);
	SCARG(&a, len) = SCARG(uap, len);
	SCARG(&a, flags) = SCARG(uap, flags);
	SCARG(&a, to) = SCARG(uap, to);
	SCARG(&a, tolen) = SCARG(uap, tolen);

	return sendto(p, &a, retval);
}

#define	OSF1_RB_ASKNAME		0x001
#define	OSF1_RB_SINGLE		0x002
#define	OSF1_RB_NOSYNC		0x004
#define	OSF1_RB_HALT		0x008
#define	OSF1_RB_INITNAME	0x010
#define	OSF1_RB_DFLTROOT	0x020
#define	OSF1_RB_ALTBOOT		0x040
#define	OSF1_RB_UNIPROC		0x080
#define	OSF1_RB_ALLFLAGS	0x0ff		/* all of the above */

int
osf1_reboot(p, uap, retval)
	struct proc *p;
	struct osf1_reboot_args /* {
		syscallarg(int) opt;
	} */ *uap;
	register_t *retval;
{
	struct reboot_args a;

	if (SCARG(uap, opt) & ~OSF1_RB_ALLFLAGS &&
	    SCARG(uap, opt) & (OSF1_RB_ALTBOOT|OSF1_RB_UNIPROC))
		return (EINVAL);

	SCARG(&a, opt) = 0;
	if (SCARG(uap, opt) & OSF1_RB_ASKNAME)
		SCARG(&a, opt) |= RB_ASKNAME;
	if (SCARG(uap, opt) & OSF1_RB_SINGLE)
		SCARG(&a, opt) |= RB_SINGLE;
	if (SCARG(uap, opt) & OSF1_RB_NOSYNC)
		SCARG(&a, opt) |= RB_NOSYNC;
	if (SCARG(uap, opt) & OSF1_RB_HALT)
		SCARG(&a, opt) |= RB_HALT;
	if (SCARG(uap, opt) & OSF1_RB_INITNAME)
		SCARG(&a, opt) |= RB_INITNAME;
	if (SCARG(uap, opt) & OSF1_RB_DFLTROOT)
		SCARG(&a, opt) |= RB_DFLTROOT;

	return reboot(p, &a, retval);
}

int
osf1_lseek(p, uap, retval)
	struct proc *p;
	struct osf1_lseek_args /* {
		syscallarg(int) fd;
		syscallarg(off_t) offset;
		syscallarg(int) whence;
	} */ *uap;
	register_t *retval;
{
	struct lseek_args a;

	SCARG(&a, fd) = SCARG(uap, fd);
	SCARG(&a, pad) = 0;
	SCARG(&a, offset) = SCARG(uap, offset);
	SCARG(&a, whence) = SCARG(uap, whence);

	return lseek(p, &a, retval);
}

/*
 * OSF/1 defines _POSIX_SAVED_IDS, which means that our normal
 * setuid() won't work.
 *
 * Instead, by P1003.1b-1993, setuid() is supposed to work like:
 *	If the process has appropriate [super-user] priviledges, the
 *	    setuid() function sets the real user ID, effective user
 *	    ID, and the saved set-user-ID to uid.
 *	If the process does not have appropriate priviledges, but uid
 *	    is equal to the real user ID or the saved set-user-ID, the
 *	    setuid() function sets the effective user ID to uid; the
 *	    real user ID and saved set-user-ID remain unchanged by
 *	    this function call.
 */
int
osf1_setuid(p, uap, retval)
	struct proc *p;
	struct osf1_setuid_args /* {
		syscallargs(uid_t) uid;
	} */ *uap;
	register_t *retval;
{
	register struct pcred *pc = p->p_cred;
	uid_t uid = SCARG(uap, uid);
	int error;

	if ((error = suser(pc->pc_ucred, &p->p_acflag)) != 0 &&
	    uid != pc->p_ruid && uid != pc->p_svuid)
		return (error);

	pc->pc_ucred = crcopy(pc->pc_ucred);
	pc->pc_ucred->cr_uid = uid;
	if (error == 0) {
	        (void)chgproccnt(pc->p_ruid, -1);
	        (void)chgproccnt(uid, 1);
		pc->p_ruid = uid;
		pc->p_svuid = uid;
	}
	p->p_flag |= P_SUGID;
	return (0);
}

/*
 * OSF/1 defines _POSIX_SAVED_IDS, which means that our normal
 * setgid() won't work.
 *
 * If you change "uid" to "gid" in the discussion, above, about
 * setuid(), you'll get a correct description of setgid().
 */
int
osf1_setgid(p, uap, retval)
	struct proc *p;
	struct osf1_setgid_args /* {
		syscallargs(gid_t) gid;
	} */ *uap;
	register_t *retval;
{
	register struct pcred *pc = p->p_cred;
	gid_t gid = SCARG(uap, gid);
	int error;

	if ((error = suser(pc->pc_ucred, &p->p_acflag)) != 0 &&
	    gid != pc->p_rgid && gid != pc->p_svgid)
		return (error);

	pc->pc_ucred = crcopy(pc->pc_ucred);
	pc->pc_ucred->cr_gid = gid;
	if (error == 0) {
		pc->p_rgid = gid;
		pc->p_svgid = gid;
	}
	p->p_flag |= P_SUGID;
	return (0);
}

/*
 * The structures end up being the same... but we can't be sure that
 * the other word of our iov_len is zero!
 */
struct osf1_iovec {
	char	*iov_base;
	int	iov_len;
};

int
osf1_readv(p, uap, retval)
	struct proc *p;
	struct osf1_readv_args /* {
		syscallarg(int) fd;
		syscallarg(struct osf1_iovec *) iovp;
		syscallarg(u_int) iovcnt;
	} */ *uap;
	register_t *retval;
{
	struct readv_args /* {
		syscallarg(int) fd;
		syscallarg(struct iovec *) iovp;
		syscallarg(u_int) iovcnt;
	} */ a;
	struct osf1_iovec *oio;
	struct iovec *nio;
	int error, i;
	extern char sigcode[], esigcode[];

	if (SCARG(uap, iovcnt) > (STACKGAPLEN / sizeof (struct iovec)))
		return (EINVAL);

	oio = (struct osf1_iovec *)
	    malloc(SCARG(uap, iovcnt)*sizeof (struct osf1_iovec),
	    M_TEMP, M_WAITOK);
	nio = (struct iovec *) malloc(SCARG(uap, iovcnt)*sizeof (struct iovec),
	    M_TEMP, M_WAITOK);

	error = 0;
	if (error = copyin(SCARG(uap, iovp), oio,
	    SCARG(uap, iovcnt)*sizeof (struct osf1_iovec)))
		goto punt;
	for (i = 0; i < SCARG(uap, iovcnt); i++) {
		nio[i].iov_base = oio[i].iov_base;
		nio[i].iov_len = oio[i].iov_len;
	}
	if (error = copyout(nio,
	    (caddr_t)ALIGN(PS_STRINGS - szsigcode - STACKGAPLEN),
	    SCARG(uap, iovcnt)*sizeof (struct iovec)))
		goto punt;

	SCARG(&a, fd) = SCARG(uap, fd);
	SCARG(&a, iovp) =
	    (struct iovec *)ALIGN(PS_STRINGS - szsigcode - STACKGAPLEN);
	SCARG(&a, iovcnt) = SCARG(uap, iovcnt);

	error = readv(p, &a, retval);

punt:
	free(oio, M_TEMP);
	free(nio, M_TEMP);
	return (error);
}

int
osf1_writev(p, uap, retval)
	struct proc *p;
	struct osf1_writev_args /* {
		syscallarg(int) fd;
		syscallarg(struct osf1_iovec *) iovp;
		syscallarg(u_int) iovcnt;
	} */ *uap;
	register_t *retval;
{
	struct writev_args /* {
		syscallarg(int) fd;
		syscallarg(struct iovec *) iovp;
		syscallarg(u_int) iovcnt;
	} */ a;
	struct osf1_iovec *oio;
	struct iovec *nio;
	int error, i;
	extern char sigcode[], esigcode[];

	if (SCARG(uap, iovcnt) > (STACKGAPLEN / sizeof (struct iovec)))
		return (EINVAL);

	oio = (struct osf1_iovec *)
	    malloc(SCARG(uap, iovcnt)*sizeof (struct osf1_iovec),
	    M_TEMP, M_WAITOK);
	nio = (struct iovec *)malloc(SCARG(uap, iovcnt)*sizeof (struct iovec),
	    M_TEMP, M_WAITOK);

	error = 0;
	if (error = copyin(SCARG(uap, iovp), oio,
	    SCARG(uap, iovcnt)*sizeof (struct osf1_iovec)))
		goto punt;
	for (i = 0; i < SCARG(uap, iovcnt); i++) {
		nio[i].iov_base = oio[i].iov_base;
		nio[i].iov_len = oio[i].iov_len;
	}
	if (error = copyout(nio,
	    (caddr_t)ALIGN(PS_STRINGS - szsigcode - STACKGAPLEN),
	    SCARG(uap, iovcnt)*sizeof (struct iovec)))
		goto punt;

	SCARG(&a, fd) = SCARG(uap, fd);
	SCARG(&a, iovp) =
	    (struct iovec *)ALIGN(PS_STRINGS - szsigcode - STACKGAPLEN);
	SCARG(&a, iovcnt) = SCARG(uap, iovcnt);

	error = writev(p, &a, retval);

punt:
	free(oio, M_TEMP);
	free(nio, M_TEMP);
	return (error);
}

/* More of the stupid off_t padding! */
int
osf1_truncate(p, uap, retval)
	struct proc *p;
	struct osf1_truncate_args /* {
		syscallarg(char *) path;
		syscallarg(off_t) length;
	} */ *uap;
	register_t retval;
{
	struct truncate_args a;

	SCARG(&a, path) = SCARG(uap, path);
	SCARG(&a, pad) = 0;
	SCARG(&a, length) = SCARG(uap, length);

	return truncate(p, &a, retval);
}

int
osf1_ftruncate(p, uap, retval)
	struct proc *p;
	struct osf1_ftruncate_args /* {
		syscallarg(int) fd;
		syscallarg(off_t) length;
	} */ *uap;
	register_t retval;
{
	struct ftruncate_args a;

	SCARG(&a, fd) = SCARG(uap, fd);
	SCARG(&a, pad) = 0;
	SCARG(&a, length) = SCARG(uap, length);

	return ftruncate(p, &a, retval);
}

int
osf1_getsid(p, uap, retval)
	struct proc *p;
	struct osf1_getsid_args /* {
		syscallarg(pid_t) pid;
	} */ *uap;
	register_t *retval;
{
	struct proc *t;

	if (SCARG(uap, pid) == 0)
		t = p;
	else if ((t = pfind(SCARG(uap, pid))) == NULL)
		return (ESRCH);

	*retval = t->p_session->s_leader->p_pid;
	return (0);
}

int
osf1_getrusage(p, uap, retval)	/* XXX */
	struct proc *p;
	void *uap;
	register_t *retval;
{

	return EINVAL;
}

int
osf1_madvise(p, uap, retval)	/* XXX */
	struct proc *p;
	void *uap;
	register_t *retval;
{

	return EINVAL;
}
