ibcs2_misc.c revision 39659
1/*
2 * Copyright (c) 1995 Steven Wallace
3 * Copyright (c) 1994, 1995 Scott Bartram
4 * Copyright (c) 1992, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * This software was developed by the Computer Systems Engineering group
8 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
9 * contributed to Berkeley.
10 *
11 * All advertising materials mentioning features or use of this software
12 * must display the following acknowledgement:
13 *	This product includes software developed by the University of
14 *	California, Lawrence Berkeley Laboratory.
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 * 1. Redistributions of source code must retain the above copyright
20 *    notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 *    notice, this list of conditions and the following disclaimer in the
23 *    documentation and/or other materials provided with the distribution.
24 * 3. All advertising materials mentioning features or use of this software
25 *    must display the following acknowledgement:
26 *	This product includes software developed by the University of
27 *	California, Berkeley and its contributors.
28 * 4. Neither the name of the University nor the names of its contributors
29 *    may be used to endorse or promote products derived from this software
30 *    without specific prior written permission.
31 *
32 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
36 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 * SUCH DAMAGE.
43 *
44 * from: Header: sun_misc.c,v 1.16 93/04/07 02:46:27 torek Exp
45 *
46 *	@(#)sun_misc.c	8.1 (Berkeley) 6/18/93
47 *
48 * $Id: ibcs2_misc.c,v 1.29 1998/08/17 18:12:52 bde Exp $
49 */
50
51/*
52 * IBCS2 compatibility module.
53 *
54 * IBCS2 system calls that are implemented differently in BSD are
55 * handled here.
56 */
57#include <sys/param.h>
58#include <sys/dirent.h>
59#include <sys/fcntl.h>
60#include <sys/file.h>
61#include <sys/filedesc.h>
62#include <sys/kernel.h>
63#include <sys/lock.h>
64#include <sys/malloc.h>
65#include <sys/reboot.h>
66#include <sys/resourcevar.h>
67#include <sys/stat.h>
68#include <sys/sysctl.h>
69#include <sys/sysproto.h>
70#include <sys/systm.h>
71#include <sys/time.h>
72#include <sys/times.h>
73#include <sys/vnode.h>
74#include <sys/wait.h>
75
76#include <machine/cpu.h>
77
78#include <i386/ibcs2/ibcs2_dirent.h>
79#include <i386/ibcs2/ibcs2_signal.h>
80#include <i386/ibcs2/ibcs2_proto.h>
81#include <i386/ibcs2/ibcs2_unistd.h>
82#include <i386/ibcs2/ibcs2_util.h>
83#include <i386/ibcs2/ibcs2_utime.h>
84#include <i386/ibcs2/ibcs2_xenix.h>
85
86int
87ibcs2_ulimit(p, uap)
88	struct proc *p;
89	struct ibcs2_ulimit_args *uap;
90{
91#ifdef notyet
92	int error;
93	struct rlimit rl;
94	struct setrlimit_args {
95		int resource;
96		struct rlimit *rlp;
97	} sra;
98#endif
99#define IBCS2_GETFSIZE		1
100#define IBCS2_SETFSIZE		2
101#define IBCS2_GETPSIZE		3
102#define IBCS2_GETDTABLESIZE	4
103
104	switch (SCARG(uap, cmd)) {
105	case IBCS2_GETFSIZE:
106		p->p_retval[0] = p->p_rlimit[RLIMIT_FSIZE].rlim_cur;
107		if (p->p_retval[0] == -1) p->p_retval[0] = 0x7fffffff;
108		return 0;
109	case IBCS2_SETFSIZE:	/* XXX - fix this */
110#ifdef notyet
111		rl.rlim_cur = SCARG(uap, newlimit);
112		sra.resource = RLIMIT_FSIZE;
113		sra.rlp = &rl;
114		error = setrlimit(p, &sra);
115		if (!error)
116			p->p_retval[0] = p->p_rlimit[RLIMIT_FSIZE].rlim_cur;
117		else
118			DPRINTF(("failed "));
119		return error;
120#else
121		p->p_retval[0] = SCARG(uap, newlimit);
122		return 0;
123#endif
124	case IBCS2_GETPSIZE:
125		p->p_retval[0] = p->p_rlimit[RLIMIT_RSS].rlim_cur; /* XXX */
126		return 0;
127	case IBCS2_GETDTABLESIZE:
128		uap->cmd = IBCS2_SC_OPEN_MAX;
129		return ibcs2_sysconf(p, (struct ibcs2_sysconf_args *)uap);
130	default:
131		return ENOSYS;
132	}
133}
134
135#define IBCS2_WSTOPPED       0177
136#define IBCS2_STOPCODE(sig)  ((sig) << 8 | IBCS2_WSTOPPED)
137int
138ibcs2_wait(p, uap)
139	struct proc *p;
140	struct ibcs2_wait_args *uap;
141{
142	int error, status;
143	struct wait_args w4;
144        struct trapframe *tf = p->p_md.md_regs;
145
146	SCARG(&w4, rusage) = NULL;
147        if ((tf->tf_eflags & (PSL_Z|PSL_PF|PSL_N|PSL_V))
148            == (PSL_Z|PSL_PF|PSL_N|PSL_V)) {
149		/* waitpid */
150		SCARG(&w4, pid) = SCARG(uap, a1);
151		SCARG(&w4, status) = (int *)SCARG(uap, a2);
152		SCARG(&w4, options) = SCARG(uap, a3);
153	} else {
154		/* wait */
155		SCARG(&w4, pid) = WAIT_ANY;
156		SCARG(&w4, status) = (int *)SCARG(uap, a1);
157		SCARG(&w4, options) = 0;
158	}
159	if ((error = wait4(p, &w4)) != 0)
160		return error;
161	if (SCARG(&w4, status))	{	/* this is real iBCS brain-damage */
162		error = copyin((caddr_t)SCARG(&w4, status), (caddr_t)&status,
163			       sizeof(SCARG(&w4, status)));
164		if(error)
165		  return error;
166
167		/* convert status/signal result */
168		if(WIFSTOPPED(status))
169			status =
170			  IBCS2_STOPCODE(bsd_to_ibcs2_sig[WSTOPSIG(status)]);
171		else if(WIFSIGNALED(status))
172			status = bsd_to_ibcs2_sig[WTERMSIG(status)];
173		/* else exit status -- identical */
174
175		/* record result/status */
176		p->p_retval[1] = status;
177		return copyout((caddr_t)&status, (caddr_t)SCARG(&w4, status),
178			       sizeof(SCARG(&w4, status)));
179	}
180
181	return 0;
182}
183
184int
185ibcs2_execv(p, uap)
186	struct proc *p;
187	struct ibcs2_execv_args *uap;
188{
189	struct execve_args ea;
190	caddr_t sg = stackgap_init();
191
192        CHECKALTEXIST(p, &sg, SCARG(uap, path));
193	SCARG(&ea, fname) = SCARG(uap, path);
194	SCARG(&ea, argv) = SCARG(uap, argp);
195	SCARG(&ea, envv) = NULL;
196	return execve(p, &ea);
197}
198
199int
200ibcs2_execve(p, uap)
201        struct proc *p;
202        struct ibcs2_execve_args *uap;
203{
204        caddr_t sg = stackgap_init();
205        CHECKALTEXIST(p, &sg, SCARG(uap, path));
206        return execve(p, (struct execve_args *)uap);
207}
208
209int
210ibcs2_umount(p, uap)
211	struct proc *p;
212	struct ibcs2_umount_args *uap;
213{
214	struct unmount_args um;
215
216	SCARG(&um, path) = SCARG(uap, name);
217	SCARG(&um, flags) = 0;
218	return unmount(p, &um);
219}
220
221int
222ibcs2_mount(p, uap)
223	struct proc *p;
224	struct ibcs2_mount_args *uap;
225{
226#ifdef notyet
227	int oflags = SCARG(uap, flags), nflags, error;
228	char fsname[MFSNAMELEN];
229
230	if (oflags & (IBCS2_MS_NOSUB | IBCS2_MS_SYS5))
231		return (EINVAL);
232	if ((oflags & IBCS2_MS_NEWTYPE) == 0)
233		return (EINVAL);
234	nflags = 0;
235	if (oflags & IBCS2_MS_RDONLY)
236		nflags |= MNT_RDONLY;
237	if (oflags & IBCS2_MS_NOSUID)
238		nflags |= MNT_NOSUID;
239	if (oflags & IBCS2_MS_REMOUNT)
240		nflags |= MNT_UPDATE;
241	SCARG(uap, flags) = nflags;
242
243	if (error = copyinstr((caddr_t)SCARG(uap, type), fsname, sizeof fsname,
244			      (u_int *)0))
245		return (error);
246
247	if (strcmp(fsname, "4.2") == 0) {
248		SCARG(uap, type) = (caddr_t)STACK_ALLOC();
249		if (error = copyout("ufs", SCARG(uap, type), sizeof("ufs")))
250			return (error);
251	} else if (strcmp(fsname, "nfs") == 0) {
252		struct ibcs2_nfs_args sna;
253		struct sockaddr_in sain;
254		struct nfs_args na;
255		struct sockaddr sa;
256
257		if (error = copyin(SCARG(uap, data), &sna, sizeof sna))
258			return (error);
259		if (error = copyin(sna.addr, &sain, sizeof sain))
260			return (error);
261		bcopy(&sain, &sa, sizeof sa);
262		sa.sa_len = sizeof(sain);
263		SCARG(uap, data) = (caddr_t)STACK_ALLOC();
264		na.addr = (struct sockaddr *)((int)SCARG(uap, data) + sizeof na);
265		na.sotype = SOCK_DGRAM;
266		na.proto = IPPROTO_UDP;
267		na.fh = (nfsv2fh_t *)sna.fh;
268		na.flags = sna.flags;
269		na.wsize = sna.wsize;
270		na.rsize = sna.rsize;
271		na.timeo = sna.timeo;
272		na.retrans = sna.retrans;
273		na.hostname = sna.hostname;
274
275		if (error = copyout(&sa, na.addr, sizeof sa))
276			return (error);
277		if (error = copyout(&na, SCARG(uap, data), sizeof na))
278			return (error);
279	}
280	return (mount(p, uap));
281#else
282	return EINVAL;
283#endif
284}
285
286/*
287 * Read iBCS2-style directory entries.  We suck them into kernel space so
288 * that they can be massaged before being copied out to user code.  Like
289 * SunOS, we squish out `empty' entries.
290 *
291 * This is quite ugly, but what do you expect from compatibility code?
292 */
293
294int
295ibcs2_getdents(p, uap)
296	struct proc *p;
297	register struct ibcs2_getdents_args *uap;
298{
299	register struct vnode *vp;
300	register caddr_t inp, buf;	/* BSD-format */
301	register int len, reclen;	/* BSD-format */
302	register caddr_t outp;		/* iBCS2-format */
303	register int resid;		/* iBCS2-format */
304	struct file *fp;
305	struct uio auio;
306	struct iovec aiov;
307	struct ibcs2_dirent idb;
308	off_t off;			/* true file offset */
309	int buflen, error, eofflag;
310	u_long *cookies = NULL, *cookiep;
311	int ncookies;
312#define	BSD_DIRENT(cp)		((struct dirent *)(cp))
313#define	IBCS2_RECLEN(reclen)	(reclen + sizeof(u_short))
314
315	if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
316		return (error);
317	if ((fp->f_flag & FREAD) == 0)
318		return (EBADF);
319	vp = (struct vnode *)fp->f_data;
320	if (vp->v_type != VDIR)	/* XXX  vnode readdir op should do this */
321		return (EINVAL);
322
323	off = fp->f_offset;
324#define	DIRBLKSIZ	512		/* XXX we used to use ufs's DIRBLKSIZ */
325	buflen = max(DIRBLKSIZ, SCARG(uap, nbytes));
326	buflen = min(buflen, MAXBSIZE);
327	buf = malloc(buflen, M_TEMP, M_WAITOK);
328	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
329again:
330	aiov.iov_base = buf;
331	aiov.iov_len = buflen;
332	auio.uio_iov = &aiov;
333	auio.uio_iovcnt = 1;
334	auio.uio_rw = UIO_READ;
335	auio.uio_segflg = UIO_SYSSPACE;
336	auio.uio_procp = p;
337	auio.uio_resid = buflen;
338	auio.uio_offset = off;
339
340	if (cookies) {
341		free(cookies, M_TEMP);
342		cookies = NULL;
343	}
344
345	/*
346	 * First we read into the malloc'ed buffer, then
347	 * we massage it into user space, one record at a time.
348	 */
349	if (error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, &cookies))
350		goto out;
351	inp = buf;
352	outp = SCARG(uap, buf);
353	resid = SCARG(uap, nbytes);
354	if ((len = buflen - auio.uio_resid) <= 0)
355		goto eof;
356
357	cookiep = cookies;
358
359	if (cookies) {
360		/*
361		 * When using cookies, the vfs has the option of reading from
362		 * a different offset than that supplied (UFS truncates the
363		 * offset to a block boundary to make sure that it never reads
364		 * partway through a directory entry, even if the directory
365		 * has been compacted).
366		 */
367		while (len > 0 && ncookies > 0 && *cookiep <= off) {
368			len -= BSD_DIRENT(inp)->d_reclen;
369			inp += BSD_DIRENT(inp)->d_reclen;
370			cookiep++;
371			ncookies--;
372		}
373	}
374
375	for (; len > 0; len -= reclen) {
376		if (cookiep && ncookies == 0)
377			break;
378		reclen = BSD_DIRENT(inp)->d_reclen;
379		if (reclen & 3) {
380		        printf("ibcs2_getdents: reclen=%d\n", reclen);
381		        error = EFAULT;
382			goto out;
383		}
384		if (BSD_DIRENT(inp)->d_fileno == 0) {
385			inp += reclen;	/* it is a hole; squish it out */
386			if (cookiep) {
387				off = *cookiep++;
388				ncookies--;
389			} else
390				off += reclen;
391			continue;
392		}
393		if (reclen > len || resid < IBCS2_RECLEN(reclen)) {
394			/* entry too big for buffer, so just stop */
395			outp++;
396			break;
397		}
398		/*
399		 * Massage in place to make a iBCS2-shaped dirent (otherwise
400		 * we have to worry about touching user memory outside of
401		 * the copyout() call).
402		 */
403		idb.d_ino = (ibcs2_ino_t)BSD_DIRENT(inp)->d_fileno;
404		idb.d_off = (ibcs2_off_t)off;
405		idb.d_reclen = (u_short)IBCS2_RECLEN(reclen);
406		if ((error = copyout((caddr_t)&idb, outp, 10)) != 0 ||
407		    (error = copyout(BSD_DIRENT(inp)->d_name, outp + 10,
408				     BSD_DIRENT(inp)->d_namlen + 1)) != 0)
409			goto out;
410		/* advance past this real entry */
411		if (cookiep) {
412			off = *cookiep++;
413			ncookies--;
414		} else
415			off += reclen;
416		inp += reclen;
417		/* advance output past iBCS2-shaped entry */
418		outp += IBCS2_RECLEN(reclen);
419		resid -= IBCS2_RECLEN(reclen);
420	}
421	/* if we squished out the whole block, try again */
422	if (outp == SCARG(uap, buf))
423		goto again;
424	fp->f_offset = off;		/* update the vnode offset */
425eof:
426	p->p_retval[0] = SCARG(uap, nbytes) - resid;
427out:
428	if (cookies)
429		free(cookies, M_TEMP);
430	VOP_UNLOCK(vp, 0, p);
431	free(buf, M_TEMP);
432	return (error);
433}
434
435int
436ibcs2_read(p, uap)
437	struct proc *p;
438	struct ibcs2_read_args *uap;
439{
440	register struct vnode *vp;
441	register caddr_t inp, buf;	/* BSD-format */
442	register int len, reclen;	/* BSD-format */
443	register caddr_t outp;		/* iBCS2-format */
444	register int resid;		/* iBCS2-format */
445	struct file *fp;
446	struct uio auio;
447	struct iovec aiov;
448	struct ibcs2_direct {
449		ibcs2_ino_t ino;
450		char name[14];
451	} idb;
452	off_t off;			/* true file offset */
453	int buflen, error, eofflag, size;
454	u_long *cookies = NULL, *cookiep;
455	int ncookies;
456
457	if (error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) {
458		if (error == EINVAL)
459			return read(p, (struct read_args *)uap);
460		else
461			return error;
462	}
463	if ((fp->f_flag & FREAD) == 0)
464		return (EBADF);
465	vp = (struct vnode *)fp->f_data;
466	if (vp->v_type != VDIR)
467		return read(p, (struct read_args *)uap);
468
469	DPRINTF(("ibcs2_read: read directory\n"));
470
471	off = fp->f_offset;
472	buflen = max(DIRBLKSIZ, SCARG(uap, nbytes));
473	buflen = min(buflen, MAXBSIZE);
474	buf = malloc(buflen, M_TEMP, M_WAITOK);
475	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
476again:
477	aiov.iov_base = buf;
478	aiov.iov_len = buflen;
479	auio.uio_iov = &aiov;
480	auio.uio_iovcnt = 1;
481	auio.uio_rw = UIO_READ;
482	auio.uio_segflg = UIO_SYSSPACE;
483	auio.uio_procp = p;
484	auio.uio_resid = buflen;
485	auio.uio_offset = off;
486
487	if (cookies) {
488		free(cookies, M_TEMP);
489		cookies = NULL;
490	}
491
492	/*
493	 * First we read into the malloc'ed buffer, then
494	 * we massage it into user space, one record at a time.
495	 */
496	if (error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, &cookies)) {
497		DPRINTF(("VOP_READDIR failed: %d\n", error));
498		goto out;
499	}
500	inp = buf;
501	outp = SCARG(uap, buf);
502	resid = SCARG(uap, nbytes);
503	if ((len = buflen - auio.uio_resid) <= 0)
504		goto eof;
505
506	cookiep = cookies;
507
508	if (cookies) {
509		/*
510		 * When using cookies, the vfs has the option of reading from
511		 * a different offset than that supplied (UFS truncates the
512		 * offset to a block boundary to make sure that it never reads
513		 * partway through a directory entry, even if the directory
514		 * has been compacted).
515		 */
516		while (len > 0 && ncookies > 0 && *cookiep <= off) {
517			len -= BSD_DIRENT(inp)->d_reclen;
518			inp += BSD_DIRENT(inp)->d_reclen;
519			cookiep++;
520			ncookies--;
521		}
522	}
523
524	for (; len > 0 && resid > 0; len -= reclen) {
525		if (cookiep && ncookies == 0)
526			break;
527		reclen = BSD_DIRENT(inp)->d_reclen;
528		if (reclen & 3) {
529		        printf("ibcs2_read: reclen=%d\n", reclen);
530		        error = EFAULT;
531			goto out;
532		}
533		if (BSD_DIRENT(inp)->d_fileno == 0) {
534			inp += reclen;	/* it is a hole; squish it out */
535			if (cookiep) {
536				off = *cookiep++;
537				ncookies--;
538			} else
539				off += reclen;
540			continue;
541		}
542		if (reclen > len || resid < sizeof(struct ibcs2_direct)) {
543			/* entry too big for buffer, so just stop */
544			outp++;
545			break;
546		}
547		/*
548		 * Massage in place to make a iBCS2-shaped dirent (otherwise
549		 * we have to worry about touching user memory outside of
550		 * the copyout() call).
551		 *
552		 * TODO: if length(filename) > 14, then break filename into
553		 * multiple entries and set inode = 0xffff except last
554		 */
555		idb.ino = (BSD_DIRENT(inp)->d_fileno > 0xfffe) ? 0xfffe :
556			BSD_DIRENT(inp)->d_fileno;
557		(void)copystr(BSD_DIRENT(inp)->d_name, idb.name, 14, &size);
558		bzero(idb.name + size, 14 - size);
559		if (error = copyout(&idb, outp, sizeof(struct ibcs2_direct)))
560			goto out;
561		/* advance past this real entry */
562		if (cookiep) {
563			off = *cookiep++;
564			ncookies--;
565		} else
566			off += reclen;
567		inp += reclen;
568		/* advance output past iBCS2-shaped entry */
569		outp += sizeof(struct ibcs2_direct);
570		resid -= sizeof(struct ibcs2_direct);
571	}
572	/* if we squished out the whole block, try again */
573	if (outp == SCARG(uap, buf))
574		goto again;
575	fp->f_offset = off;		/* update the vnode offset */
576eof:
577	p->p_retval[0] = SCARG(uap, nbytes) - resid;
578out:
579	if (cookies)
580		free(cookies, M_TEMP);
581	VOP_UNLOCK(vp, 0, p);
582	free(buf, M_TEMP);
583	return (error);
584}
585
586int
587ibcs2_mknod(p, uap)
588	struct proc *p;
589	struct ibcs2_mknod_args *uap;
590{
591        caddr_t sg = stackgap_init();
592
593        CHECKALTCREAT(p, &sg, SCARG(uap, path));
594	if (S_ISFIFO(SCARG(uap, mode))) {
595                struct mkfifo_args ap;
596                SCARG(&ap, path) = SCARG(uap, path);
597                SCARG(&ap, mode) = SCARG(uap, mode);
598		return mkfifo(p, &ap);
599	} else {
600                struct mknod_args ap;
601                SCARG(&ap, path) = SCARG(uap, path);
602                SCARG(&ap, mode) = SCARG(uap, mode);
603                SCARG(&ap, dev) = SCARG(uap, dev);
604                return mknod(p, &ap);
605	}
606}
607
608int
609ibcs2_getgroups(p, uap)
610	struct proc *p;
611	struct ibcs2_getgroups_args *uap;
612{
613	int error, i;
614	ibcs2_gid_t *iset = NULL;
615	struct getgroups_args sa;
616	gid_t *gp;
617	caddr_t sg = stackgap_init();
618
619	SCARG(&sa, gidsetsize) = SCARG(uap, gidsetsize);
620	if (SCARG(uap, gidsetsize)) {
621		SCARG(&sa, gidset) = stackgap_alloc(&sg, NGROUPS_MAX *
622						    sizeof(gid_t *));
623		iset = stackgap_alloc(&sg, SCARG(uap, gidsetsize) *
624				      sizeof(ibcs2_gid_t));
625	}
626	if (error = getgroups(p, &sa))
627		return error;
628	if (SCARG(uap, gidsetsize) == 0)
629		return 0;
630
631	for (i = 0, gp = SCARG(&sa, gidset); i < p->p_retval[0]; i++)
632		iset[i] = (ibcs2_gid_t)*gp++;
633	if (p->p_retval[0] && (error = copyout((caddr_t)iset,
634					  (caddr_t)SCARG(uap, gidset),
635					  sizeof(ibcs2_gid_t) * p->p_retval[0])))
636		return error;
637        return 0;
638}
639
640int
641ibcs2_setgroups(p, uap)
642	struct proc *p;
643	struct ibcs2_setgroups_args *uap;
644{
645	int error, i;
646	ibcs2_gid_t *iset;
647	struct setgroups_args sa;
648	gid_t *gp;
649	caddr_t sg = stackgap_init();
650
651	SCARG(&sa, gidsetsize) = SCARG(uap, gidsetsize);
652	SCARG(&sa, gidset) = stackgap_alloc(&sg, SCARG(&sa, gidsetsize) *
653					    sizeof(gid_t *));
654	iset = stackgap_alloc(&sg, SCARG(&sa, gidsetsize) *
655			      sizeof(ibcs2_gid_t *));
656	if (SCARG(&sa, gidsetsize)) {
657		if (error = copyin((caddr_t)SCARG(uap, gidset), (caddr_t)iset,
658				   sizeof(ibcs2_gid_t *) *
659				   SCARG(uap, gidsetsize)))
660			return error;
661	}
662	for (i = 0, gp = SCARG(&sa, gidset); i < SCARG(&sa, gidsetsize); i++)
663		*gp++ = (gid_t)iset[i];
664	return setgroups(p, &sa);
665}
666
667int
668ibcs2_setuid(p, uap)
669	struct proc *p;
670	struct ibcs2_setuid_args *uap;
671{
672	struct setuid_args sa;
673
674	SCARG(&sa, uid) = (uid_t)SCARG(uap, uid);
675	return setuid(p, &sa);
676}
677
678int
679ibcs2_setgid(p, uap)
680	struct proc *p;
681	struct ibcs2_setgid_args *uap;
682{
683	struct setgid_args sa;
684
685	SCARG(&sa, gid) = (gid_t)SCARG(uap, gid);
686	return setgid(p, &sa);
687}
688
689int
690ibcs2_time(p, uap)
691	struct proc *p;
692	struct ibcs2_time_args *uap;
693{
694	struct timeval tv;
695
696	microtime(&tv);
697	p->p_retval[0] = tv.tv_sec;
698	if (SCARG(uap, tp))
699		return copyout((caddr_t)&tv.tv_sec, (caddr_t)SCARG(uap, tp),
700			       sizeof(ibcs2_time_t));
701	else
702		return 0;
703}
704
705int
706ibcs2_pathconf(p, uap)
707	struct proc *p;
708	struct ibcs2_pathconf_args *uap;
709{
710	SCARG(uap, name)++;	/* iBCS2 _PC_* defines are offset by one */
711        return pathconf(p, (struct pathconf_args *)uap);
712}
713
714int
715ibcs2_fpathconf(p, uap)
716	struct proc *p;
717	struct ibcs2_fpathconf_args *uap;
718{
719	SCARG(uap, name)++;	/* iBCS2 _PC_* defines are offset by one */
720        return fpathconf(p, (struct fpathconf_args *)uap);
721}
722
723int
724ibcs2_sysconf(p, uap)
725	struct proc *p;
726	struct ibcs2_sysconf_args *uap;
727{
728	int mib[2], value, len, error;
729	struct sysctl_args sa;
730	struct __getrlimit_args ga;
731
732	switch(SCARG(uap, name)) {
733	case IBCS2_SC_ARG_MAX:
734		mib[1] = KERN_ARGMAX;
735		break;
736
737	case IBCS2_SC_CHILD_MAX:
738	    {
739		caddr_t sg = stackgap_init();
740
741		SCARG(&ga, which) = RLIMIT_NPROC;
742		SCARG(&ga, rlp) = stackgap_alloc(&sg, sizeof(struct rlimit *));
743		if (error = getrlimit(p, &ga))
744			return error;
745		p->p_retval[0] = SCARG(&ga, rlp)->rlim_cur;
746		return 0;
747	    }
748
749	case IBCS2_SC_CLK_TCK:
750		p->p_retval[0] = hz;
751		return 0;
752
753	case IBCS2_SC_NGROUPS_MAX:
754		mib[1] = KERN_NGROUPS;
755		break;
756
757	case IBCS2_SC_OPEN_MAX:
758	    {
759		caddr_t sg = stackgap_init();
760
761		SCARG(&ga, which) = RLIMIT_NOFILE;
762		SCARG(&ga, rlp) = stackgap_alloc(&sg, sizeof(struct rlimit *));
763		if (error = getrlimit(p, &ga))
764			return error;
765		p->p_retval[0] = SCARG(&ga, rlp)->rlim_cur;
766		return 0;
767	    }
768
769	case IBCS2_SC_JOB_CONTROL:
770		mib[1] = KERN_JOB_CONTROL;
771		break;
772
773	case IBCS2_SC_SAVED_IDS:
774		mib[1] = KERN_SAVED_IDS;
775		break;
776
777	case IBCS2_SC_VERSION:
778		mib[1] = KERN_POSIX1;
779		break;
780
781	case IBCS2_SC_PASS_MAX:
782		p->p_retval[0] = 128;		/* XXX - should we create PASS_MAX ? */
783		return 0;
784
785	case IBCS2_SC_XOPEN_VERSION:
786		p->p_retval[0] = 2;		/* XXX: What should that be? */
787		return 0;
788
789	default:
790		return EINVAL;
791	}
792
793	mib[0] = CTL_KERN;
794	len = sizeof(value);
795	SCARG(&sa, name) = mib;
796	SCARG(&sa, namelen) = 2;
797	SCARG(&sa, old) = &value;
798	SCARG(&sa, oldlenp) = &len;
799	SCARG(&sa, new) = NULL;
800	SCARG(&sa, newlen) = 0;
801	if (error = __sysctl(p, &sa))
802		return error;
803	p->p_retval[0] = value;
804	return 0;
805}
806
807int
808ibcs2_alarm(p, uap)
809	struct proc *p;
810	struct ibcs2_alarm_args *uap;
811{
812	int error;
813        struct itimerval *itp, *oitp;
814	struct setitimer_args sa;
815	caddr_t sg = stackgap_init();
816
817        itp = stackgap_alloc(&sg, sizeof(*itp));
818	oitp = stackgap_alloc(&sg, sizeof(*oitp));
819        timevalclear(&itp->it_interval);
820        itp->it_value.tv_sec = SCARG(uap, sec);
821        itp->it_value.tv_usec = 0;
822
823	SCARG(&sa, which) = ITIMER_REAL;
824	SCARG(&sa, itv) = itp;
825	SCARG(&sa, oitv) = oitp;
826        error = setitimer(p, &sa);
827	if (error)
828		return error;
829        if (oitp->it_value.tv_usec)
830                oitp->it_value.tv_sec++;
831        p->p_retval[0] = oitp->it_value.tv_sec;
832        return 0;
833}
834
835int
836ibcs2_times(p, uap)
837	struct proc *p;
838	struct ibcs2_times_args *uap;
839{
840	int error;
841	struct getrusage_args ga;
842	struct tms tms;
843        struct timeval t;
844	caddr_t sg = stackgap_init();
845        struct rusage *ru = stackgap_alloc(&sg, sizeof(*ru));
846#define CONVTCK(r)      (r.tv_sec * hz + r.tv_usec / (1000000 / hz))
847
848	SCARG(&ga, who) = RUSAGE_SELF;
849	SCARG(&ga, rusage) = ru;
850	error = getrusage(p, &ga);
851	if (error)
852                return error;
853        tms.tms_utime = CONVTCK(ru->ru_utime);
854        tms.tms_stime = CONVTCK(ru->ru_stime);
855
856	SCARG(&ga, who) = RUSAGE_CHILDREN;
857        error = getrusage(p, &ga);
858	if (error)
859		return error;
860        tms.tms_cutime = CONVTCK(ru->ru_utime);
861        tms.tms_cstime = CONVTCK(ru->ru_stime);
862
863	microtime(&t);
864        p->p_retval[0] = CONVTCK(t);
865
866	return copyout((caddr_t)&tms, (caddr_t)SCARG(uap, tp),
867		       sizeof(struct tms));
868}
869
870int
871ibcs2_stime(p, uap)
872	struct proc *p;
873	struct ibcs2_stime_args *uap;
874{
875	int error;
876	struct settimeofday_args sa;
877	caddr_t sg = stackgap_init();
878
879	SCARG(&sa, tv) = stackgap_alloc(&sg, sizeof(*SCARG(&sa, tv)));
880	SCARG(&sa, tzp) = NULL;
881	if (error = copyin((caddr_t)SCARG(uap, timep),
882			   &(SCARG(&sa, tv)->tv_sec), sizeof(long)))
883		return error;
884	SCARG(&sa, tv)->tv_usec = 0;
885	if (error = settimeofday(p, &sa))
886		return EPERM;
887	return 0;
888}
889
890int
891ibcs2_utime(p, uap)
892	struct proc *p;
893	struct ibcs2_utime_args *uap;
894{
895	int error;
896	struct utimes_args sa;
897	struct timeval *tp;
898	caddr_t sg = stackgap_init();
899
900        CHECKALTEXIST(p, &sg, SCARG(uap, path));
901	SCARG(&sa, path) = SCARG(uap, path);
902	if (SCARG(uap, buf)) {
903		struct ibcs2_utimbuf ubuf;
904
905		if (error = copyin((caddr_t)SCARG(uap, buf), (caddr_t)&ubuf,
906				   sizeof(ubuf)))
907			return error;
908		SCARG(&sa, tptr) = stackgap_alloc(&sg,
909						  2 * sizeof(struct timeval *));
910		tp = (struct timeval *)SCARG(&sa, tptr);
911		tp->tv_sec = ubuf.actime;
912		tp->tv_usec = 0;
913		tp++;
914		tp->tv_sec = ubuf.modtime;
915		tp->tv_usec = 0;
916	} else
917		SCARG(&sa, tptr) = NULL;
918	return utimes(p, &sa);
919}
920
921int
922ibcs2_nice(p, uap)
923	struct proc *p;
924	struct ibcs2_nice_args *uap;
925{
926	int error;
927	struct setpriority_args sa;
928
929	SCARG(&sa, which) = PRIO_PROCESS;
930	SCARG(&sa, who) = 0;
931	SCARG(&sa, prio) = p->p_nice + SCARG(uap, incr);
932	if (error = setpriority(p, &sa))
933		return EPERM;
934	p->p_retval[0] = p->p_nice;
935	return 0;
936}
937
938/*
939 * iBCS2 getpgrp, setpgrp, setsid, and setpgid
940 */
941
942int
943ibcs2_pgrpsys(p, uap)
944	struct proc *p;
945	struct ibcs2_pgrpsys_args *uap;
946{
947	switch (SCARG(uap, type)) {
948	case 0:			/* getpgrp */
949		p->p_retval[0] = p->p_pgrp->pg_id;
950		return 0;
951
952	case 1:			/* setpgrp */
953	    {
954		struct setpgid_args sa;
955
956		SCARG(&sa, pid) = 0;
957		SCARG(&sa, pgid) = 0;
958		setpgid(p, &sa);
959		p->p_retval[0] = p->p_pgrp->pg_id;
960		return 0;
961	    }
962
963	case 2:			/* setpgid */
964	    {
965		struct setpgid_args sa;
966
967		SCARG(&sa, pid) = SCARG(uap, pid);
968		SCARG(&sa, pgid) = SCARG(uap, pgid);
969		return setpgid(p, &sa);
970	    }
971
972	case 3:			/* setsid */
973		return setsid(p, NULL);
974
975	default:
976		return EINVAL;
977	}
978}
979
980/*
981 * XXX - need to check for nested calls
982 */
983
984int
985ibcs2_plock(p, uap)
986	struct proc *p;
987	struct ibcs2_plock_args *uap;
988{
989	int error;
990#define IBCS2_UNLOCK	0
991#define IBCS2_PROCLOCK	1
992#define IBCS2_TEXTLOCK	2
993#define IBCS2_DATALOCK	4
994
995
996        if (error = suser(p->p_ucred, &p->p_acflag))
997                return EPERM;
998	switch(SCARG(uap, cmd)) {
999	case IBCS2_UNLOCK:
1000	case IBCS2_PROCLOCK:
1001	case IBCS2_TEXTLOCK:
1002	case IBCS2_DATALOCK:
1003		return 0;	/* XXX - TODO */
1004	}
1005	return EINVAL;
1006}
1007
1008int
1009ibcs2_uadmin(p, uap)
1010	struct proc *p;
1011	struct ibcs2_uadmin_args *uap;
1012{
1013#define SCO_A_REBOOT        1
1014#define SCO_A_SHUTDOWN      2
1015#define SCO_A_REMOUNT       4
1016#define SCO_A_CLOCK         8
1017#define SCO_A_SETCONFIG     128
1018#define SCO_A_GETDEV        130
1019
1020#define SCO_AD_HALT         0
1021#define SCO_AD_BOOT         1
1022#define SCO_AD_IBOOT        2
1023#define SCO_AD_PWRDOWN      3
1024#define SCO_AD_PWRNAP       4
1025
1026#define SCO_AD_PANICBOOT    1
1027
1028#define SCO_AD_GETBMAJ      0
1029#define SCO_AD_GETCMAJ      1
1030
1031        if (suser(p->p_ucred, &p->p_acflag))
1032                return EPERM;
1033
1034	switch(SCARG(uap, cmd)) {
1035	case SCO_A_REBOOT:
1036	case SCO_A_SHUTDOWN:
1037		switch(SCARG(uap, func)) {
1038			struct reboot_args r;
1039		case SCO_AD_HALT:
1040		case SCO_AD_PWRDOWN:
1041		case SCO_AD_PWRNAP:
1042			r.opt = RB_HALT;
1043			reboot(p, &r);
1044		case SCO_AD_BOOT:
1045		case SCO_AD_IBOOT:
1046			r.opt = RB_AUTOBOOT;
1047			reboot(p, &r);
1048		}
1049		return EINVAL;
1050	case SCO_A_REMOUNT:
1051	case SCO_A_CLOCK:
1052	case SCO_A_SETCONFIG:
1053		return 0;
1054	case SCO_A_GETDEV:
1055		return EINVAL;	/* XXX - TODO */
1056	}
1057	return EINVAL;
1058}
1059
1060int
1061ibcs2_sysfs(p, uap)
1062	struct proc *p;
1063	struct ibcs2_sysfs_args *uap;
1064{
1065#define IBCS2_GETFSIND        1
1066#define IBCS2_GETFSTYP        2
1067#define IBCS2_GETNFSTYP       3
1068
1069	switch(SCARG(uap, cmd)) {
1070	case IBCS2_GETFSIND:
1071	case IBCS2_GETFSTYP:
1072	case IBCS2_GETNFSTYP:
1073		break;
1074	}
1075	return EINVAL;		/* XXX - TODO */
1076}
1077
1078int
1079ibcs2_unlink(p, uap)
1080	struct proc *p;
1081	struct ibcs2_unlink_args *uap;
1082{
1083        caddr_t sg = stackgap_init();
1084
1085	CHECKALTEXIST(p, &sg, SCARG(uap, path));
1086	return unlink(p, (struct unlink_args *)uap);
1087}
1088
1089int
1090ibcs2_chdir(p, uap)
1091	struct proc *p;
1092	struct ibcs2_chdir_args *uap;
1093{
1094        caddr_t sg = stackgap_init();
1095
1096	CHECKALTEXIST(p, &sg, SCARG(uap, path));
1097	return chdir(p, (struct chdir_args *)uap);
1098}
1099
1100int
1101ibcs2_chmod(p, uap)
1102	struct proc *p;
1103	struct ibcs2_chmod_args *uap;
1104{
1105        caddr_t sg = stackgap_init();
1106
1107	CHECKALTEXIST(p, &sg, SCARG(uap, path));
1108	return chmod(p, (struct chmod_args *)uap);
1109}
1110
1111int
1112ibcs2_chown(p, uap)
1113	struct proc *p;
1114	struct ibcs2_chown_args *uap;
1115{
1116        caddr_t sg = stackgap_init();
1117
1118	CHECKALTEXIST(p, &sg, SCARG(uap, path));
1119	return chown(p, (struct chown_args *)uap);
1120}
1121
1122int
1123ibcs2_rmdir(p, uap)
1124	struct proc *p;
1125	struct ibcs2_rmdir_args *uap;
1126{
1127        caddr_t sg = stackgap_init();
1128
1129	CHECKALTEXIST(p, &sg, SCARG(uap, path));
1130	return rmdir(p, (struct rmdir_args *)uap);
1131}
1132
1133int
1134ibcs2_mkdir(p, uap)
1135	struct proc *p;
1136	struct ibcs2_mkdir_args *uap;
1137{
1138        caddr_t sg = stackgap_init();
1139
1140	CHECKALTCREAT(p, &sg, SCARG(uap, path));
1141	return mkdir(p, (struct mkdir_args *)uap);
1142}
1143
1144int
1145ibcs2_symlink(p, uap)
1146	struct proc *p;
1147	struct ibcs2_symlink_args *uap;
1148{
1149        caddr_t sg = stackgap_init();
1150
1151	CHECKALTEXIST(p, &sg, SCARG(uap, path));
1152	CHECKALTCREAT(p, &sg, SCARG(uap, link));
1153	return symlink(p, (struct symlink_args *)uap);
1154}
1155
1156int
1157ibcs2_rename(p, uap)
1158	struct proc *p;
1159	struct ibcs2_rename_args *uap;
1160{
1161        caddr_t sg = stackgap_init();
1162
1163	CHECKALTEXIST(p, &sg, SCARG(uap, from));
1164	CHECKALTCREAT(p, &sg, SCARG(uap, to));
1165	return rename(p, (struct rename_args *)uap);
1166}
1167
1168int
1169ibcs2_readlink(p, uap)
1170	struct proc *p;
1171	struct ibcs2_readlink_args *uap;
1172{
1173        caddr_t sg = stackgap_init();
1174
1175	CHECKALTEXIST(p, &sg, SCARG(uap, path));
1176	return readlink(p, (struct readlink_args *) uap);
1177}
1178