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