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