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