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