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