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