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