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