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