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