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: releng/12.0/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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }
Cache object: 3123c67deb83d3edb21175f74fd9eceb
|