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