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