ibcs2_misc.c revision 141488
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 141488 2005-02-07 22:02:18Z 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/imgact.h> 66#include <sys/kernel.h> 67#include <sys/lock.h> 68#include <sys/mac.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/reboot.h> 73#include <sys/resourcevar.h> 74#include <sys/stat.h> 75#include <sys/sysctl.h> 76#include <sys/syscallsubr.h> 77#include <sys/sysproto.h> 78#include <sys/time.h> 79#include <sys/times.h> 80#include <sys/vnode.h> 81#include <sys/wait.h> 82 83#include <machine/cpu.h> 84 85#include <i386/ibcs2/ibcs2_dirent.h> 86#include <i386/ibcs2/ibcs2_signal.h> 87#include <i386/ibcs2/ibcs2_proto.h> 88#include <i386/ibcs2/ibcs2_unistd.h> 89#include <i386/ibcs2/ibcs2_util.h> 90#include <i386/ibcs2/ibcs2_utime.h> 91#include <i386/ibcs2/ibcs2_xenix.h> 92 93int 94ibcs2_ulimit(td, uap) 95 struct thread *td; 96 struct ibcs2_ulimit_args *uap; 97{ 98 struct rlimit rl; 99 struct proc *p; 100 int error; 101#define IBCS2_GETFSIZE 1 102#define IBCS2_SETFSIZE 2 103#define IBCS2_GETPSIZE 3 104#define IBCS2_GETDTABLESIZE 4 105 106 p = td->td_proc; 107 switch (uap->cmd) { 108 case IBCS2_GETFSIZE: 109 PROC_LOCK(p); 110 td->td_retval[0] = lim_cur(p, RLIMIT_FSIZE); 111 PROC_UNLOCK(p); 112 if (td->td_retval[0] == -1) 113 td->td_retval[0] = 0x7fffffff; 114 return 0; 115 case IBCS2_SETFSIZE: 116 PROC_LOCK(p); 117 rl.rlim_max = lim_max(p, RLIMIT_FSIZE); 118 PROC_UNLOCK(p); 119 rl.rlim_cur = uap->newlimit; 120 error = kern_setrlimit(td, RLIMIT_FSIZE, &rl); 121 if (!error) { 122 PROC_LOCK(p); 123 td->td_retval[0] = lim_cur(p, RLIMIT_FSIZE); 124 PROC_UNLOCK(p); 125 } else { 126 DPRINTF(("failed ")); 127 } 128 return error; 129 case IBCS2_GETPSIZE: 130 PROC_LOCK(p); 131 td->td_retval[0] = lim_cur(p, RLIMIT_RSS); /* XXX */ 132 PROC_UNLOCK(p); 133 return 0; 134 case IBCS2_GETDTABLESIZE: 135 uap->cmd = IBCS2_SC_OPEN_MAX; 136 return ibcs2_sysconf(td, (struct ibcs2_sysconf_args *)uap); 137 default: 138 return ENOSYS; 139 } 140} 141 142#define IBCS2_WSTOPPED 0177 143#define IBCS2_STOPCODE(sig) ((sig) << 8 | IBCS2_WSTOPPED) 144int 145ibcs2_wait(td, uap) 146 struct thread *td; 147 struct ibcs2_wait_args *uap; 148{ 149 int error, options, status; 150 int *statusp; 151 pid_t pid; 152 struct trapframe *tf = td->td_frame; 153 154 if ((tf->tf_eflags & (PSL_Z|PSL_PF|PSL_N|PSL_V)) 155 == (PSL_Z|PSL_PF|PSL_N|PSL_V)) { 156 /* waitpid */ 157 pid = uap->a1; 158 statusp = (int *)uap->a2; 159 options = uap->a3; 160 } else { 161 /* wait */ 162 pid = WAIT_ANY; 163 statusp = (int *)uap->a1; 164 options = 0; 165 } 166 error = kern_wait(td, pid, &status, options, NULL); 167 if (error) 168 return error; 169 if (statusp) { 170 /* 171 * Convert status/signal result. 172 */ 173 if (WIFSTOPPED(status)) { 174 if (WSTOPSIG(status) <= 0 || 175 WSTOPSIG(status) > IBCS2_SIGTBLSZ) 176 return (EINVAL); 177 status = 178 IBCS2_STOPCODE(bsd_to_ibcs2_sig[_SIG_IDX(WSTOPSIG(status))]); 179 } else if (WIFSIGNALED(status)) { 180 if (WTERMSIG(status) <= 0 || 181 WTERMSIG(status) > IBCS2_SIGTBLSZ) 182 return (EINVAL); 183 status = bsd_to_ibcs2_sig[_SIG_IDX(WTERMSIG(status))]; 184 } 185 /* else exit status -- identical */ 186 187 /* record result/status */ 188 td->td_retval[1] = status; 189 return copyout(&status, statusp, sizeof(status)); 190 } 191 192 return 0; 193} 194 195int 196ibcs2_execv(td, uap) 197 struct thread *td; 198 struct ibcs2_execv_args *uap; 199{ 200 struct image_args eargs; 201 char *path; 202 int error; 203 204 CHECKALTEXIST(td, uap->path, &path); 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 exec_free_args(&eargs); 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 char *path; 221 int error; 222 223 CHECKALTEXIST(td, uap->path, &path); 224 225 error = exec_copyin_args(&eargs, path, UIO_SYSSPACE, uap->argp, 226 uap->envp); 227 free(path, M_TEMP); 228 if (error == 0) 229 error = kern_execve(td, &eargs, NULL); 230 exec_free_args(&eargs); 231 return (error); 232} 233 234int 235ibcs2_umount(td, uap) 236 struct thread *td; 237 struct ibcs2_umount_args *uap; 238{ 239 struct unmount_args um; 240 241 um.path = uap->name; 242 um.flags = 0; 243 return unmount(td, &um); 244} 245 246int 247ibcs2_mount(td, uap) 248 struct thread *td; 249 struct ibcs2_mount_args *uap; 250{ 251#ifdef notyet 252 int oflags = uap->flags, nflags, error; 253 char fsname[MFSNAMELEN]; 254 255 if (oflags & (IBCS2_MS_NOSUB | IBCS2_MS_SYS5)) 256 return (EINVAL); 257 if ((oflags & IBCS2_MS_NEWTYPE) == 0) 258 return (EINVAL); 259 nflags = 0; 260 if (oflags & IBCS2_MS_RDONLY) 261 nflags |= MNT_RDONLY; 262 if (oflags & IBCS2_MS_NOSUID) 263 nflags |= MNT_NOSUID; 264 if (oflags & IBCS2_MS_REMOUNT) 265 nflags |= MNT_UPDATE; 266 uap->flags = nflags; 267 268 if (error = copyinstr((caddr_t)uap->type, fsname, sizeof fsname, 269 (u_int *)0)) 270 return (error); 271 272 if (strcmp(fsname, "4.2") == 0) { 273 uap->type = (caddr_t)STACK_ALLOC(); 274 if (error = copyout("ufs", uap->type, sizeof("ufs"))) 275 return (error); 276 } else if (strcmp(fsname, "nfs") == 0) { 277 struct ibcs2_nfs_args sna; 278 struct sockaddr_in sain; 279 struct nfs_args na; 280 struct sockaddr sa; 281 282 if (error = copyin(uap->data, &sna, sizeof sna)) 283 return (error); 284 if (error = copyin(sna.addr, &sain, sizeof sain)) 285 return (error); 286 bcopy(&sain, &sa, sizeof sa); 287 sa.sa_len = sizeof(sain); 288 uap->data = (caddr_t)STACK_ALLOC(); 289 na.addr = (struct sockaddr *)((int)uap->data + sizeof na); 290 na.sotype = SOCK_DGRAM; 291 na.proto = IPPROTO_UDP; 292 na.fh = (nfsv2fh_t *)sna.fh; 293 na.flags = sna.flags; 294 na.wsize = sna.wsize; 295 na.rsize = sna.rsize; 296 na.timeo = sna.timeo; 297 na.retrans = sna.retrans; 298 na.hostname = sna.hostname; 299 300 if (error = copyout(&sa, na.addr, sizeof sa)) 301 return (error); 302 if (error = copyout(&na, uap->data, sizeof na)) 303 return (error); 304 } 305 return (mount(td, uap)); 306#else 307 return EINVAL; 308#endif 309} 310 311/* 312 * Read iBCS2-style directory entries. We suck them into kernel space so 313 * that they can be massaged before being copied out to user code. Like 314 * SunOS, we squish out `empty' entries. 315 * 316 * This is quite ugly, but what do you expect from compatibility code? 317 */ 318 319int 320ibcs2_getdents(td, uap) 321 struct thread *td; 322 register struct ibcs2_getdents_args *uap; 323{ 324 register struct vnode *vp; 325 register caddr_t inp, buf; /* BSD-format */ 326 register int len, reclen; /* BSD-format */ 327 register caddr_t outp; /* iBCS2-format */ 328 register int resid; /* iBCS2-format */ 329 struct file *fp; 330 struct uio auio; 331 struct iovec aiov; 332 struct ibcs2_dirent idb; 333 off_t off; /* true file offset */ 334 int buflen, error, eofflag; 335 u_long *cookies = NULL, *cookiep; 336 int ncookies; 337#define BSD_DIRENT(cp) ((struct dirent *)(cp)) 338#define IBCS2_RECLEN(reclen) (reclen + sizeof(u_short)) 339 340 if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0) 341 return (error); 342 if ((fp->f_flag & FREAD) == 0) { 343 fdrop(fp, td); 344 return (EBADF); 345 } 346 vp = fp->f_vnode; 347 if (vp->v_type != VDIR) { /* XXX vnode readdir op should do this */ 348 fdrop(fp, td); 349 return (EINVAL); 350 } 351 352 off = fp->f_offset; 353#define DIRBLKSIZ 512 /* XXX we used to use ufs's DIRBLKSIZ */ 354 buflen = max(DIRBLKSIZ, uap->nbytes); 355 buflen = min(buflen, MAXBSIZE); 356 buf = malloc(buflen, M_TEMP, M_WAITOK); 357 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 358again: 359 aiov.iov_base = buf; 360 aiov.iov_len = buflen; 361 auio.uio_iov = &aiov; 362 auio.uio_iovcnt = 1; 363 auio.uio_rw = UIO_READ; 364 auio.uio_segflg = UIO_SYSSPACE; 365 auio.uio_td = td; 366 auio.uio_resid = buflen; 367 auio.uio_offset = off; 368 369 if (cookies) { 370 free(cookies, M_TEMP); 371 cookies = NULL; 372 } 373 374#ifdef MAC 375 error = mac_check_vnode_readdir(td->td_ucred, vp); 376 if (error) 377 goto out; 378#endif 379 380 /* 381 * First we read into the malloc'ed buffer, then 382 * we massage it into user space, one record at a time. 383 */ 384 if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, &cookies)) != 0) 385 goto out; 386 inp = buf; 387 outp = uap->buf; 388 resid = uap->nbytes; 389 if ((len = buflen - auio.uio_resid) <= 0) 390 goto eof; 391 392 cookiep = cookies; 393 394 if (cookies) { 395 /* 396 * When using cookies, the vfs has the option of reading from 397 * a different offset than that supplied (UFS truncates the 398 * offset to a block boundary to make sure that it never reads 399 * partway through a directory entry, even if the directory 400 * has been compacted). 401 */ 402 while (len > 0 && ncookies > 0 && *cookiep <= off) { 403 len -= BSD_DIRENT(inp)->d_reclen; 404 inp += BSD_DIRENT(inp)->d_reclen; 405 cookiep++; 406 ncookies--; 407 } 408 } 409 410 for (; len > 0; len -= reclen) { 411 if (cookiep && ncookies == 0) 412 break; 413 reclen = BSD_DIRENT(inp)->d_reclen; 414 if (reclen & 3) { 415 printf("ibcs2_getdents: reclen=%d\n", reclen); 416 error = EFAULT; 417 goto out; 418 } 419 if (BSD_DIRENT(inp)->d_fileno == 0) { 420 inp += reclen; /* it is a hole; squish it out */ 421 if (cookiep) { 422 off = *cookiep++; 423 ncookies--; 424 } else 425 off += reclen; 426 continue; 427 } 428 if (reclen > len || resid < IBCS2_RECLEN(reclen)) { 429 /* entry too big for buffer, so just stop */ 430 outp++; 431 break; 432 } 433 /* 434 * Massage in place to make an iBCS2-shaped dirent (otherwise 435 * we have to worry about touching user memory outside of 436 * the copyout() call). 437 */ 438 idb.d_ino = (ibcs2_ino_t)BSD_DIRENT(inp)->d_fileno; 439 idb.d_off = (ibcs2_off_t)off; 440 idb.d_reclen = (u_short)IBCS2_RECLEN(reclen); 441 if ((error = copyout((caddr_t)&idb, outp, 10)) != 0 || 442 (error = copyout(BSD_DIRENT(inp)->d_name, outp + 10, 443 BSD_DIRENT(inp)->d_namlen + 1)) != 0) 444 goto out; 445 /* advance past this real entry */ 446 if (cookiep) { 447 off = *cookiep++; 448 ncookies--; 449 } else 450 off += reclen; 451 inp += reclen; 452 /* advance output past iBCS2-shaped entry */ 453 outp += IBCS2_RECLEN(reclen); 454 resid -= IBCS2_RECLEN(reclen); 455 } 456 /* if we squished out the whole block, try again */ 457 if (outp == uap->buf) 458 goto again; 459 fp->f_offset = off; /* update the vnode offset */ 460eof: 461 td->td_retval[0] = uap->nbytes - resid; 462out: 463 VOP_UNLOCK(vp, 0, td); 464 fdrop(fp, td); 465 if (cookies) 466 free(cookies, M_TEMP); 467 free(buf, M_TEMP); 468 return (error); 469} 470 471int 472ibcs2_read(td, uap) 473 struct thread *td; 474 struct ibcs2_read_args *uap; 475{ 476 register struct vnode *vp; 477 register caddr_t inp, buf; /* BSD-format */ 478 register int len, reclen; /* BSD-format */ 479 register caddr_t outp; /* iBCS2-format */ 480 register int resid; /* iBCS2-format */ 481 struct file *fp; 482 struct uio auio; 483 struct iovec aiov; 484 struct ibcs2_direct { 485 ibcs2_ino_t ino; 486 char name[14]; 487 } idb; 488 off_t off; /* true file offset */ 489 int buflen, error, eofflag, size; 490 u_long *cookies = NULL, *cookiep; 491 int ncookies; 492 493 if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0) { 494 if (error == EINVAL) 495 return read(td, (struct read_args *)uap); 496 else 497 return error; 498 } 499 if ((fp->f_flag & FREAD) == 0) { 500 fdrop(fp, td); 501 return (EBADF); 502 } 503 vp = fp->f_vnode; 504 if (vp->v_type != VDIR) { 505 fdrop(fp, td); 506 return read(td, (struct read_args *)uap); 507 } 508 509 off = fp->f_offset; 510 if (vp->v_type != VDIR) 511 return read(td, (struct read_args *)uap); 512 513 DPRINTF(("ibcs2_read: read directory\n")); 514 515 buflen = max(DIRBLKSIZ, uap->nbytes); 516 buflen = min(buflen, MAXBSIZE); 517 buf = malloc(buflen, M_TEMP, M_WAITOK); 518 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 519again: 520 aiov.iov_base = buf; 521 aiov.iov_len = buflen; 522 auio.uio_iov = &aiov; 523 auio.uio_iovcnt = 1; 524 auio.uio_rw = UIO_READ; 525 auio.uio_segflg = UIO_SYSSPACE; 526 auio.uio_td = td; 527 auio.uio_resid = buflen; 528 auio.uio_offset = off; 529 530 if (cookies) { 531 free(cookies, M_TEMP); 532 cookies = NULL; 533 } 534 535#ifdef MAC 536 error = mac_check_vnode_readdir(td->td_ucred, vp); 537 if (error) 538 goto out; 539#endif 540 541 /* 542 * First we read into the malloc'ed buffer, then 543 * we massage it into user space, one record at a time. 544 */ 545 if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, &cookies)) != 0) { 546 DPRINTF(("VOP_READDIR failed: %d\n", error)); 547 goto out; 548 } 549 inp = buf; 550 outp = uap->buf; 551 resid = uap->nbytes; 552 if ((len = buflen - auio.uio_resid) <= 0) 553 goto eof; 554 555 cookiep = cookies; 556 557 if (cookies) { 558 /* 559 * When using cookies, the vfs has the option of reading from 560 * a different offset than that supplied (UFS truncates the 561 * offset to a block boundary to make sure that it never reads 562 * partway through a directory entry, even if the directory 563 * has been compacted). 564 */ 565 while (len > 0 && ncookies > 0 && *cookiep <= off) { 566 len -= BSD_DIRENT(inp)->d_reclen; 567 inp += BSD_DIRENT(inp)->d_reclen; 568 cookiep++; 569 ncookies--; 570 } 571 } 572 573 for (; len > 0 && resid > 0; len -= reclen) { 574 if (cookiep && ncookies == 0) 575 break; 576 reclen = BSD_DIRENT(inp)->d_reclen; 577 if (reclen & 3) { 578 printf("ibcs2_read: reclen=%d\n", reclen); 579 error = EFAULT; 580 goto out; 581 } 582 if (BSD_DIRENT(inp)->d_fileno == 0) { 583 inp += reclen; /* it is a hole; squish it out */ 584 if (cookiep) { 585 off = *cookiep++; 586 ncookies--; 587 } else 588 off += reclen; 589 continue; 590 } 591 if (reclen > len || resid < sizeof(struct ibcs2_direct)) { 592 /* entry too big for buffer, so just stop */ 593 outp++; 594 break; 595 } 596 /* 597 * Massage in place to make an iBCS2-shaped dirent (otherwise 598 * we have to worry about touching user memory outside of 599 * the copyout() call). 600 * 601 * TODO: if length(filename) > 14, then break filename into 602 * multiple entries and set inode = 0xffff except last 603 */ 604 idb.ino = (BSD_DIRENT(inp)->d_fileno > 0xfffe) ? 0xfffe : 605 BSD_DIRENT(inp)->d_fileno; 606 (void)copystr(BSD_DIRENT(inp)->d_name, idb.name, 14, &size); 607 bzero(idb.name + size, 14 - size); 608 if ((error = copyout(&idb, outp, sizeof(struct ibcs2_direct))) != 0) 609 goto out; 610 /* advance past this real entry */ 611 if (cookiep) { 612 off = *cookiep++; 613 ncookies--; 614 } else 615 off += reclen; 616 inp += reclen; 617 /* advance output past iBCS2-shaped entry */ 618 outp += sizeof(struct ibcs2_direct); 619 resid -= sizeof(struct ibcs2_direct); 620 } 621 /* if we squished out the whole block, try again */ 622 if (outp == uap->buf) 623 goto again; 624 fp->f_offset = off; /* update the vnode offset */ 625eof: 626 td->td_retval[0] = uap->nbytes - resid; 627out: 628 VOP_UNLOCK(vp, 0, td); 629 fdrop(fp, td); 630 if (cookies) 631 free(cookies, M_TEMP); 632 free(buf, M_TEMP); 633 return (error); 634} 635 636int 637ibcs2_mknod(td, uap) 638 struct thread *td; 639 struct ibcs2_mknod_args *uap; 640{ 641 char *path; 642 int error; 643 644 CHECKALTCREAT(td, uap->path, &path); 645 if (S_ISFIFO(uap->mode)) 646 error = kern_mkfifo(td, path, UIO_SYSSPACE, uap->mode); 647 else 648 error = kern_mknod(td, path, UIO_SYSSPACE, uap->mode, uap->dev); 649 free(path, M_TEMP); 650 return (error); 651} 652 653int 654ibcs2_getgroups(td, uap) 655 struct thread *td; 656 struct ibcs2_getgroups_args *uap; 657{ 658 int error, i; 659 ibcs2_gid_t *iset = NULL; 660 struct getgroups_args sa; 661 gid_t *gp; 662 caddr_t sg = stackgap_init(); 663 664 if (uap->gidsetsize < 0) 665 return (EINVAL); 666 if (uap->gidsetsize > NGROUPS_MAX) 667 uap->gidsetsize = NGROUPS_MAX; 668 sa.gidsetsize = uap->gidsetsize; 669 if (uap->gidsetsize) { 670 sa.gidset = stackgap_alloc(&sg, NGROUPS_MAX * 671 sizeof(gid_t *)); 672 iset = stackgap_alloc(&sg, uap->gidsetsize * 673 sizeof(ibcs2_gid_t)); 674 } 675 if ((error = getgroups(td, &sa)) != 0) 676 return error; 677 if (uap->gidsetsize == 0) 678 return 0; 679 680 for (i = 0, gp = sa.gidset; i < td->td_retval[0]; i++) 681 iset[i] = (ibcs2_gid_t)*gp++; 682 if (td->td_retval[0] && (error = copyout((caddr_t)iset, 683 (caddr_t)uap->gidset, 684 sizeof(ibcs2_gid_t) * td->td_retval[0]))) 685 return error; 686 return 0; 687} 688 689int 690ibcs2_setgroups(td, uap) 691 struct thread *td; 692 struct ibcs2_setgroups_args *uap; 693{ 694 int error, i; 695 ibcs2_gid_t *iset; 696 struct setgroups_args sa; 697 gid_t *gp; 698 caddr_t sg = stackgap_init(); 699 700 if (uap->gidsetsize < 0 || uap->gidsetsize > NGROUPS_MAX) 701 return (EINVAL); 702 sa.gidsetsize = uap->gidsetsize; 703 sa.gidset = stackgap_alloc(&sg, sa.gidsetsize * 704 sizeof(gid_t *)); 705 iset = stackgap_alloc(&sg, sa.gidsetsize * 706 sizeof(ibcs2_gid_t *)); 707 if (sa.gidsetsize) { 708 if ((error = copyin((caddr_t)uap->gidset, (caddr_t)iset, 709 sizeof(ibcs2_gid_t *) * 710 uap->gidsetsize)) != 0) 711 return error; 712 } 713 for (i = 0, gp = sa.gidset; i < sa.gidsetsize; i++) 714 *gp++ = (gid_t)iset[i]; 715 return setgroups(td, &sa); 716} 717 718int 719ibcs2_setuid(td, uap) 720 struct thread *td; 721 struct ibcs2_setuid_args *uap; 722{ 723 struct setuid_args sa; 724 725 sa.uid = (uid_t)uap->uid; 726 return setuid(td, &sa); 727} 728 729int 730ibcs2_setgid(td, uap) 731 struct thread *td; 732 struct ibcs2_setgid_args *uap; 733{ 734 struct setgid_args sa; 735 736 sa.gid = (gid_t)uap->gid; 737 return setgid(td, &sa); 738} 739 740int 741ibcs2_time(td, uap) 742 struct thread *td; 743 struct ibcs2_time_args *uap; 744{ 745 struct timeval tv; 746 747 microtime(&tv); 748 td->td_retval[0] = tv.tv_sec; 749 if (uap->tp) 750 return copyout((caddr_t)&tv.tv_sec, (caddr_t)uap->tp, 751 sizeof(ibcs2_time_t)); 752 else 753 return 0; 754} 755 756int 757ibcs2_pathconf(td, uap) 758 struct thread *td; 759 struct ibcs2_pathconf_args *uap; 760{ 761 char *path; 762 int error; 763 764 CHECKALTEXIST(td, uap->path, &path); 765 uap->name++; /* iBCS2 _PC_* defines are offset by one */ 766 error = kern_pathconf(td, path, UIO_SYSSPACE, uap->name); 767 free(path, M_TEMP); 768 return (error); 769} 770 771int 772ibcs2_fpathconf(td, uap) 773 struct thread *td; 774 struct ibcs2_fpathconf_args *uap; 775{ 776 uap->name++; /* iBCS2 _PC_* defines are offset by one */ 777 return fpathconf(td, (struct fpathconf_args *)uap); 778} 779 780int 781ibcs2_sysconf(td, uap) 782 struct thread *td; 783 struct ibcs2_sysconf_args *uap; 784{ 785 int mib[2], value, len, error; 786 struct proc *p; 787 788 p = td->td_proc; 789 switch(uap->name) { 790 case IBCS2_SC_ARG_MAX: 791 mib[1] = KERN_ARGMAX; 792 break; 793 794 case IBCS2_SC_CHILD_MAX: 795 PROC_LOCK(p); 796 td->td_retval[0] = lim_cur(td->td_proc, RLIMIT_NPROC); 797 PROC_UNLOCK(p); 798 return 0; 799 800 case IBCS2_SC_CLK_TCK: 801 td->td_retval[0] = hz; 802 return 0; 803 804 case IBCS2_SC_NGROUPS_MAX: 805 mib[1] = KERN_NGROUPS; 806 break; 807 808 case IBCS2_SC_OPEN_MAX: 809 PROC_LOCK(p); 810 td->td_retval[0] = lim_cur(td->td_proc, RLIMIT_NOFILE); 811 PROC_UNLOCK(p); 812 return 0; 813 814 case IBCS2_SC_JOB_CONTROL: 815 mib[1] = KERN_JOB_CONTROL; 816 break; 817 818 case IBCS2_SC_SAVED_IDS: 819 mib[1] = KERN_SAVED_IDS; 820 break; 821 822 case IBCS2_SC_VERSION: 823 mib[1] = KERN_POSIX1; 824 break; 825 826 case IBCS2_SC_PASS_MAX: 827 td->td_retval[0] = 128; /* XXX - should we create PASS_MAX ? */ 828 return 0; 829 830 case IBCS2_SC_XOPEN_VERSION: 831 td->td_retval[0] = 2; /* XXX: What should that be? */ 832 return 0; 833 834 default: 835 return EINVAL; 836 } 837 838 mib[0] = CTL_KERN; 839 len = sizeof(value); 840 error = kernel_sysctl(td, mib, 2, &value, &len, NULL, 0, NULL, 0); 841 if (error) 842 return error; 843 td->td_retval[0] = value; 844 return 0; 845} 846 847int 848ibcs2_alarm(td, uap) 849 struct thread *td; 850 struct ibcs2_alarm_args *uap; 851{ 852 struct itimerval itv, oitv; 853 int error; 854 855 timevalclear(&itv.it_interval); 856 itv.it_value.tv_sec = uap->sec; 857 itv.it_value.tv_usec = 0; 858 error = kern_setitimer(td, ITIMER_REAL, &itv, &oitv); 859 if (error) 860 return (error); 861 if (oitv.it_value.tv_usec != 0) 862 oitv.it_value.tv_sec++; 863 td->td_retval[0] = oitv.it_value.tv_sec; 864 return (0); 865} 866 867int 868ibcs2_times(td, uap) 869 struct thread *td; 870 struct ibcs2_times_args *uap; 871{ 872 struct rusage ru; 873 struct timeval t; 874 struct tms tms; 875 int error; 876 877#define CONVTCK(r) (r.tv_sec * hz + r.tv_usec / (1000000 / hz)) 878 879 error = kern_getrusage(td, RUSAGE_SELF, &ru); 880 if (error) 881 return (error); 882 tms.tms_utime = CONVTCK(ru.ru_utime); 883 tms.tms_stime = CONVTCK(ru.ru_stime); 884 885 error = kern_getrusage(td, RUSAGE_CHILDREN, &ru); 886 if (error) 887 return (error); 888 tms.tms_cutime = CONVTCK(ru.ru_utime); 889 tms.tms_cstime = CONVTCK(ru.ru_stime); 890 891 microtime(&t); 892 td->td_retval[0] = CONVTCK(t); 893 894 return (copyout(&tms, uap->tp, sizeof(struct tms))); 895} 896 897int 898ibcs2_stime(td, uap) 899 struct thread *td; 900 struct ibcs2_stime_args *uap; 901{ 902 int error; 903 struct settimeofday_args sa; 904 caddr_t sg = stackgap_init(); 905 906 sa.tv = stackgap_alloc(&sg, sizeof(*sa.tv)); 907 sa.tzp = NULL; 908 if ((error = copyin((caddr_t)uap->timep, 909 &(sa.tv->tv_sec), sizeof(long))) != 0) 910 return error; 911 sa.tv->tv_usec = 0; 912 if ((error = settimeofday(td, &sa)) != 0) 913 return EPERM; 914 return 0; 915} 916 917int 918ibcs2_utime(td, uap) 919 struct thread *td; 920 struct ibcs2_utime_args *uap; 921{ 922 struct ibcs2_utimbuf ubuf; 923 struct timeval tbuf[2], *tp; 924 char *path; 925 int error; 926 927 if (uap->buf) { 928 error = copyin(uap->buf, &ubuf, sizeof(ubuf)); 929 if (error) 930 return (error); 931 tbuf[0].tv_sec = ubuf.actime; 932 tbuf[0].tv_usec = 0; 933 tbuf[1].tv_sec = ubuf.modtime; 934 tbuf[1].tv_usec = 0; 935 tp = tbuf; 936 } else 937 tp = NULL; 938 939 CHECKALTEXIST(td, uap->path, &path); 940 error = kern_utimes(td, path, UIO_SYSSPACE, tp, UIO_SYSSPACE); 941 free(path, M_TEMP); 942 return (error); 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 char *path; 1113 int error; 1114 1115 CHECKALTEXIST(td, uap->path, &path); 1116 error = kern_unlink(td, path, UIO_SYSSPACE); 1117 free(path, M_TEMP); 1118 return (error); 1119} 1120 1121int 1122ibcs2_chdir(td, uap) 1123 struct thread *td; 1124 struct ibcs2_chdir_args *uap; 1125{ 1126 char *path; 1127 int error; 1128 1129 CHECKALTEXIST(td, uap->path, &path); 1130 error = kern_chdir(td, path, UIO_SYSSPACE); 1131 free(path, M_TEMP); 1132 return (error); 1133} 1134 1135int 1136ibcs2_chmod(td, uap) 1137 struct thread *td; 1138 struct ibcs2_chmod_args *uap; 1139{ 1140 char *path; 1141 int error; 1142 1143 CHECKALTEXIST(td, uap->path, &path); 1144 error = kern_chmod(td, path, UIO_SYSSPACE, uap->mode); 1145 free(path, M_TEMP); 1146 return (error); 1147} 1148 1149int 1150ibcs2_chown(td, uap) 1151 struct thread *td; 1152 struct ibcs2_chown_args *uap; 1153{ 1154 char *path; 1155 int error; 1156 1157 CHECKALTEXIST(td, uap->path, &path); 1158 error = kern_chown(td, path, UIO_SYSSPACE, uap->uid, uap->gid); 1159 free(path, M_TEMP); 1160 return (error); 1161} 1162 1163int 1164ibcs2_rmdir(td, uap) 1165 struct thread *td; 1166 struct ibcs2_rmdir_args *uap; 1167{ 1168 char *path; 1169 int error; 1170 1171 CHECKALTEXIST(td, uap->path, &path); 1172 error = kern_rmdir(td, path, UIO_SYSSPACE); 1173 free(path, M_TEMP); 1174 return (error); 1175} 1176 1177int 1178ibcs2_mkdir(td, uap) 1179 struct thread *td; 1180 struct ibcs2_mkdir_args *uap; 1181{ 1182 char *path; 1183 int error; 1184 1185 CHECKALTEXIST(td, uap->path, &path); 1186 error = kern_mkdir(td, path, UIO_SYSSPACE, uap->mode); 1187 free(path, M_TEMP); 1188 return (error); 1189} 1190 1191int 1192ibcs2_symlink(td, uap) 1193 struct thread *td; 1194 struct ibcs2_symlink_args *uap; 1195{ 1196 char *path, *link; 1197 int error; 1198 1199 CHECKALTEXIST(td, uap->path, &path); 1200 1201 /* 1202 * Have to expand CHECKALTCREAT() so that 'path' can be freed on 1203 * errors. 1204 */ 1205 error = ibcs2_emul_find(td, uap->link, UIO_USERSPACE, &link, 1); 1206 if (link == NULL) { 1207 free(path, M_TEMP); 1208 return (error); 1209 } 1210 error = kern_symlink(td, path, link, UIO_SYSSPACE); 1211 free(path, M_TEMP); 1212 free(link, M_TEMP); 1213 return (error); 1214} 1215 1216int 1217ibcs2_rename(td, uap) 1218 struct thread *td; 1219 struct ibcs2_rename_args *uap; 1220{ 1221 char *from, *to; 1222 int error; 1223 1224 CHECKALTEXIST(td, uap->from, &from); 1225 1226 /* 1227 * Have to expand CHECKALTCREAT() so that 'from' can be freed on 1228 * errors. 1229 */ 1230 error = ibcs2_emul_find(td, uap->to, UIO_USERSPACE, &to, 1); 1231 if (link == NULL) { 1232 free(from, M_TEMP); 1233 return (error); 1234 } 1235 error = kern_rename(td, from, to, UIO_SYSSPACE); 1236 free(from, M_TEMP); 1237 free(to, M_TEMP); 1238 return (error); 1239} 1240 1241int 1242ibcs2_readlink(td, uap) 1243 struct thread *td; 1244 struct ibcs2_readlink_args *uap; 1245{ 1246 char *path; 1247 int error; 1248 1249 CHECKALTEXIST(td, uap->path, &path); 1250 error = kern_readlink(td, path, UIO_SYSSPACE, uap->buf, UIO_USERSPACE, 1251 uap->count); 1252 free(path, M_TEMP); 1253 return (error); 1254} 1255