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