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