1 /* 2 * Copyright (c) 1992, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This software was developed by the Computer Systems Engineering group 6 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 7 * contributed to Berkeley. 8 * 9 * All advertising materials mentioning features or use of this software 10 * must display the following acknowledgement: 11 * This product includes software developed by the University of 12 * California, Lawrence Berkeley Laboratory. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 3. All advertising materials mentioning features or use of this software 23 * must display the following acknowledgement: 24 * This product includes software developed by the University of 25 * California, Berkeley and its contributors. 26 * 4. Neither the name of the University nor the names of its contributors 27 * may be used to endorse or promote products derived from this software 28 * without specific prior written permission. 29 * 30 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 31 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 33 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 34 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 36 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 38 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 39 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 40 * SUCH DAMAGE. 41 * 42 * @(#)sun_misc.c 8.1 (Berkeley) 6/18/93 43 * 44 * from: Header: sun_misc.c,v 1.16 93/04/07 02:46:27 torek Exp 45 * $Id: sunos_misc.c,v 1.9 1993/11/22 22:54:48 deraadt Exp $ 46 */ 47 48 /* 49 * SunOS compatibility module. 50 * 51 * SunOS system calls that are implemented differently in BSD are 52 * handled here. 53 */ 54 55 #include <sys/param.h> 56 #include <sys/systm.h> 57 #include <ufs/dir.h> 58 #include <sys/proc.h> 59 #include <sys/file.h> 60 #include <sys/filedesc.h> 61 #include <sys/ioctl.h> 62 #include <sys/kernel.h> 63 #include <sys/malloc.h> 64 #include <sys/mbuf.h> 65 #include <sys/mman.h> 66 #include <sys/mount.h> 67 #include <sys/resource.h> 68 #include <sys/resourcevar.h> 69 #include <sys/signal.h> 70 #include <sys/signalvar.h> 71 #include <sys/socket.h> 72 #include <sys/vnode.h> 73 #include <sys/uio.h> 74 #include <sys/wait.h> 75 #include <sys/utsname.h> 76 77 #include <miscfs/specfs/specdev.h> 78 79 #include <vm/vm.h> 80 81 struct sun_wait4_args { 82 int pid; 83 int *status; 84 int options; 85 struct rusage *rusage; 86 }; 87 sun_wait4(p, uap, retval) 88 struct proc *p; 89 struct sun_wait4_args *uap; 90 int *retval; 91 { 92 93 if (uap->pid == 0) 94 uap->pid = WAIT_ANY; 95 return (wait4(p, uap, retval)); 96 } 97 98 struct sun_creat_args { 99 char *fname; 100 int fmode; 101 }; 102 sun_creat(p, uap, retval) 103 struct proc *p; 104 struct sun_creat_args *uap; 105 int *retval; 106 { 107 struct args { 108 char *fname; 109 int mode; 110 int crtmode; 111 } openuap; 112 113 openuap.fname = uap->fname; 114 openuap.crtmode = uap->fmode; 115 openuap.mode = O_WRONLY | O_CREAT | O_TRUNC; 116 return (open(p, &openuap, retval)); 117 } 118 119 struct sun_execv_args { 120 char *fname; 121 char **argp; 122 char **envp; /* pseudo */ 123 }; 124 sun_execv(p, uap, retval) 125 struct proc *p; 126 struct sun_execv_args *uap; 127 int *retval; 128 { 129 130 uap->envp = NULL; 131 return (execve(p, uap, retval)); 132 } 133 134 struct sun_omsync_args { 135 caddr_t addr; 136 int len; 137 int flags; 138 }; 139 sun_omsync(p, uap, retval) 140 struct proc *p; 141 struct sun_omsync_args *uap; 142 int *retval; 143 { 144 145 if (uap->flags) 146 return (EINVAL); 147 return (msync(p, uap, retval)); 148 } 149 150 struct sun_unmount_args { 151 char *name; 152 int flags; /* pseudo */ 153 }; 154 sun_unmount(p, uap, retval) 155 struct proc *p; 156 struct sun_unmount_args *uap; 157 int *retval; 158 { 159 160 uap->flags = 0; 161 return (unmount(p, uap, retval)); 162 } 163 164 static int 165 gettype(tptr) 166 int *tptr; 167 { 168 int type, error; 169 char in[20]; 170 171 if (error = copyinstr((caddr_t)*tptr, in, sizeof in, (u_int *)0)) 172 return (error); 173 if (strcmp(in, "4.2") == 0 || strcmp(in, "ufs") == 0) 174 type = MOUNT_UFS; 175 else if (strcmp(in, "nfs") == 0) 176 type = MOUNT_NFS; 177 else 178 return (EINVAL); 179 *tptr = type; 180 return (0); 181 } 182 183 #define SUNM_RDONLY 0x01 /* mount fs read-only */ 184 #define SUNM_NOSUID 0x02 /* mount fs with setuid disallowed */ 185 #define SUNM_NEWTYPE 0x04 /* type is string (char *), not int */ 186 #define SUNM_GRPID 0x08 /* (bsd semantics; ignored) */ 187 #define SUNM_REMOUNT 0x10 /* update existing mount */ 188 #define SUNM_NOSUB 0x20 /* prevent submounts (rejected) */ 189 #define SUNM_MULTI 0x40 /* (ignored) */ 190 #define SUNM_SYS5 0x80 /* Sys 5-specific semantics (rejected) */ 191 192 struct sun_mount_args { 193 int type; 194 char *dir; 195 int flags; 196 caddr_t data; 197 }; 198 sun_mount(p, uap, retval) 199 struct proc *p; 200 struct sun_mount_args *uap; 201 int *retval; 202 { 203 int oflags = uap->flags, nflags, error; 204 205 if (oflags & (SUNM_NOSUB | SUNM_SYS5)) 206 return (EINVAL); 207 if (oflags & SUNM_NEWTYPE && (error = gettype(&uap->type))) 208 return (error); 209 nflags = 0; 210 if (oflags & SUNM_RDONLY) 211 nflags |= MNT_RDONLY; 212 if (oflags & SUNM_NOSUID) 213 nflags |= MNT_NOSUID; 214 if (oflags & SUNM_REMOUNT) 215 nflags |= MNT_UPDATE; 216 uap->flags = nflags; 217 return (mount(p, uap, retval)); 218 } 219 220 struct sun_sigpending_args { 221 int *mask; 222 }; 223 sun_sigpending(p, uap, retval) 224 struct proc *p; 225 struct sun_sigpending_args *uap; 226 int *retval; 227 { 228 int mask = p->p_sig & p->p_sigmask; 229 230 return (copyout((caddr_t)&mask, (caddr_t)uap->mask, sizeof(int))); 231 } 232 233 /* XXX: Temporary until sys/dir.h, include/dirent.h and sys/dirent.h are fixed */ 234 struct dirent { 235 u_long d_fileno; /* file number of entry */ 236 u_short d_reclen; /* length of this record */ 237 u_short d_namlen; /* length of string in d_name */ 238 char d_name[255 + 1]; /* name must be no longer than this */ 239 }; 240 241 /* 242 * Here is the sun layout. (Compare the BSD layout in <sys/dirent.h>.) 243 * We can assume big-endian, so the BSD d_type field is just the high 244 * byte of the SunOS d_namlen field, after adjusting for the extra "long". 245 */ 246 struct sun_dirent { 247 long d_off; 248 u_long d_fileno; 249 u_short d_reclen; 250 u_short d_namlen; 251 char d_name[256]; 252 }; 253 254 /* 255 * Read Sun-style directory entries. We suck them into kernel space so 256 * that they can be massaged before being copied out to user code. Like 257 * SunOS, we squish out `empty' entries. 258 * 259 * This is quite ugly, but what do you expect from compatibility code? 260 */ 261 struct sun_getdents_args { 262 int fd; 263 char *buf; 264 int nbytes; 265 }; 266 sun_getdents(p, uap, retval) 267 struct proc *p; 268 register struct sun_getdents_args *uap; 269 int *retval; 270 { 271 register struct vnode *vp; 272 register caddr_t inp, buf; /* BSD-format */ 273 register int len, reclen; /* BSD-format */ 274 register caddr_t outp; /* Sun-format */ 275 register int resid; /* Sun-format */ 276 struct file *fp; 277 struct uio auio; 278 struct iovec aiov; 279 off_t off; /* true file offset */ 280 long soff; /* Sun file offset */ 281 int buflen, error, eofflag; 282 #define BSD_DIRENT(cp) ((struct dirent *)(cp)) 283 #define SUN_RECLEN(reclen) (reclen + sizeof(long)) 284 285 if ((error = getvnode(p->p_fd, uap->fd, &fp)) != 0) 286 return (error); 287 if ((fp->f_flag & FREAD) == 0) 288 return (EBADF); 289 vp = (struct vnode *)fp->f_data; 290 if (vp->v_type != VDIR) /* XXX vnode readdir op should do this */ 291 return (EINVAL); 292 buflen = min(MAXBSIZE, uap->nbytes); 293 buf = malloc(buflen, M_TEMP, M_WAITOK); 294 VOP_LOCK(vp); 295 off = fp->f_offset; 296 again: 297 aiov.iov_base = buf; 298 aiov.iov_len = buflen; 299 auio.uio_iov = &aiov; 300 auio.uio_iovcnt = 1; 301 auio.uio_rw = UIO_READ; 302 auio.uio_segflg = UIO_SYSSPACE; 303 auio.uio_procp = p; 304 auio.uio_resid = buflen; 305 auio.uio_offset = off; 306 /* 307 * First we read into the malloc'ed buffer, then 308 * we massage it into user space, one record at a time. 309 */ 310 if (error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, NULL, 0)) 311 goto out; 312 inp = buf; 313 outp = uap->buf; 314 resid = uap->nbytes; 315 if ((len = buflen - auio.uio_resid) == 0) 316 goto eof; 317 for (; len > 0; len -= reclen) { 318 reclen = ((struct dirent *)inp)->d_reclen; 319 if (reclen & 3) 320 panic("sun_getdents"); 321 off += reclen; /* each entry points to next */ 322 if (BSD_DIRENT(inp)->d_fileno == 0) { 323 inp += reclen; /* it is a hole; squish it out */ 324 continue; 325 } 326 if (reclen > len || resid < SUN_RECLEN(reclen)) { 327 /* entry too big for buffer, so just stop */ 328 outp++; 329 break; 330 } 331 /* 332 * Massage in place to make a Sun-shaped dirent (otherwise 333 * we have to worry about touching user memory outside of 334 * the copyout() call). 335 */ 336 BSD_DIRENT(inp)->d_reclen = SUN_RECLEN(reclen); 337 #if notdef 338 BSD_DIRENT(inp)->d_type = 0; /* 4.4 specific */ 339 #endif 340 soff = off; 341 if ((error = copyout((caddr_t)&soff, outp, sizeof soff)) != 0 || 342 (error = copyout(inp, outp + sizeof soff, reclen)) != 0) 343 goto out; 344 /* advance past this real entry */ 345 inp += reclen; 346 /* advance output past Sun-shaped entry */ 347 outp += SUN_RECLEN(reclen); 348 resid -= SUN_RECLEN(reclen); 349 } 350 /* if we squished out the whole block, try again */ 351 if (outp == uap->buf) 352 goto again; 353 fp->f_offset = off; /* update the vnode offset */ 354 eof: 355 *retval = uap->nbytes - resid; 356 out: 357 VOP_UNLOCK(vp); 358 free(buf, M_TEMP); 359 return (error); 360 } 361 362 /* 363 * The Sun bit-style arguments are not in the same order as the 364 * NetBSD ones. We must remap them the bits. 365 */ 366 367 #if defined(sparc) 368 #define DEVZERO makedev(3, 12) /* major,minor of /dev/zero */ 369 #endif 370 #if defined(sun3) || defined(amiga) || defined(mac) || defined(hp300) 371 #define DEVZERO makedev(2, 12) /* major,minor of /dev/zero */ 372 #endif 373 374 #define SUN_PROT_READ 1 375 #define SUN_PROT_WRITE 2 376 #define SUN_PROT_EXEC 4 377 #define SUN_PROT_UALL (SUN_PROT_READ | SUN_PROT_WRITE | SUN_PROT_EXEC) 378 379 #define SUN__MAP_NEW 0x80000000 /* if not, old mmap & cannot handle */ 380 381 #define SUN_MAP_SHARED 1 382 #define SUN_MAP_PRIVATE 2 383 #define SUN_MAP_TYPE 0xf 384 #define SUN_MAP_FIXED 0x10 385 386 struct sun_mmap_args { 387 caddr_t addr; 388 size_t len; 389 int prot; 390 int flags; 391 int fd; 392 off_t off; 393 }; 394 sun_mmap(p, uap, retval) 395 register struct proc *p; 396 register struct sun_mmap_args *uap; 397 int *retval; 398 { 399 register int flags, prot, newflags, newprot; 400 register struct filedesc *fdp; 401 register struct file *fp; 402 register struct vnode *vp; 403 404 /* 405 * Verify and re-map the arguments. 406 */ 407 prot = uap->prot; 408 newprot = 0; 409 if (uap->prot & ~SUN_PROT_UALL) 410 return (EINVAL); 411 if (uap->prot & SUN_PROT_READ) 412 newprot |= PROT_READ; 413 if (uap->prot & SUN_PROT_WRITE) 414 newprot |= PROT_WRITE; 415 if (uap->prot & SUN_PROT_EXEC) 416 newprot |= PROT_EXEC; 417 418 flags = uap->flags; 419 newflags = 0; 420 if ((flags & SUN__MAP_NEW) == 0) 421 return (EINVAL); 422 423 switch (flags & SUN_MAP_TYPE) { 424 case SUN_MAP_SHARED: 425 newflags |= MAP_SHARED; 426 break; 427 case SUN_MAP_PRIVATE: 428 newflags |= MAP_PRIVATE; 429 break; 430 default: 431 return (EINVAL); 432 } 433 434 if (flags & SUN_MAP_FIXED) 435 newflags |= MAP_FIXED; 436 437 /* 438 * Special case: if fd refers to /dev/zero, map as MAP_ANON. (XXX) 439 */ 440 fdp = p->p_fd; 441 if ((unsigned)uap->fd < fdp->fd_nfiles && /*XXX*/ 442 (fp = fdp->fd_ofiles[uap->fd]) != NULL && /*XXX*/ 443 fp->f_type == DTYPE_VNODE && /*XXX*/ 444 (vp = (struct vnode *)fp->f_data)->v_type == VCHR && /*XXX*/ 445 vp->v_rdev == DEVZERO) { /*XXX*/ 446 newflags |= MAP_ANON; 447 uap->fd = -1; 448 } else 449 newflags |= MAP_FILE; 450 451 /* All done, fix up fields and go. */ 452 uap->flags = newflags; 453 uap->prot = newprot; 454 return (smmap(p, uap, retval)); 455 } 456 457 #define MC_SYNC 1 458 #define MC_LOCK 2 459 #define MC_UNLOCK 3 460 #define MC_ADVISE 4 461 #define MC_LOCKAS 5 462 #define MC_UNLOCKAS 6 463 464 struct sun_mctl_args { 465 caddr_t addr; 466 size_t len; 467 int func; 468 void *arg; 469 }; 470 sun_mctl(p, uap, retval) 471 register struct proc *p; 472 register struct sun_mctl_args *uap; 473 int *retval; 474 { 475 476 switch (uap->func) { 477 478 case MC_ADVISE: /* ignore for now */ 479 return (0); 480 481 case MC_SYNC: /* translate to msync */ 482 return (msync(p, uap, retval)); 483 484 default: 485 return (EINVAL); 486 } 487 } 488 489 struct sun_setsockopt_args { 490 int s; 491 int level; 492 int name; 493 caddr_t val; 494 int valsize; 495 }; 496 sun_setsockopt(p, uap, retval) 497 struct proc *p; 498 register struct sun_setsockopt_args *uap; 499 int *retval; 500 { 501 struct file *fp; 502 struct mbuf *m = NULL; 503 int error; 504 505 if (error = getsock(p->p_fd, uap->s, &fp)) 506 return (error); 507 #define SO_DONTLINGER (~SO_LINGER) 508 if (uap->name == SO_DONTLINGER) { 509 m = m_get(M_WAIT, MT_SOOPTS); 510 if (m == NULL) 511 return (ENOBUFS); 512 mtod(m, struct linger *)->l_onoff = 0; 513 m->m_len = sizeof(struct linger); 514 return (sosetopt((struct socket *)fp->f_data, uap->level, 515 SO_LINGER, m)); 516 } 517 if (uap->valsize > MLEN) 518 return (EINVAL); 519 if (uap->val) { 520 m = m_get(M_WAIT, MT_SOOPTS); 521 if (m == NULL) 522 return (ENOBUFS); 523 if (error = copyin(uap->val, mtod(m, caddr_t), 524 (u_int)uap->valsize)) { 525 (void) m_free(m); 526 return (error); 527 } 528 m->m_len = uap->valsize; 529 } 530 return (sosetopt((struct socket *)fp->f_data, uap->level, 531 uap->name, m)); 532 } 533 534 struct sun_fchroot_args { 535 int fdes; 536 }; 537 sun_fchroot(p, uap, retval) 538 register struct proc *p; 539 register struct sun_fchroot_args *uap; 540 int *retval; 541 { 542 register struct filedesc *fdp = p->p_fd; 543 register struct vnode *vp; 544 struct file *fp; 545 int error; 546 547 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 548 return (error); 549 if ((error = getvnode(fdp, uap->fdes, &fp)) != 0) 550 return (error); 551 vp = (struct vnode *)fp->f_data; 552 VOP_LOCK(vp); 553 if (vp->v_type != VDIR) 554 error = ENOTDIR; 555 else 556 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 557 VOP_UNLOCK(vp); 558 if (error) 559 return (error); 560 VREF(vp); 561 if (fdp->fd_rdir != NULL) 562 vrele(fdp->fd_rdir); 563 fdp->fd_rdir = vp; 564 return (0); 565 } 566 567 /* 568 * XXX: This needs cleaning up. 569 */ 570 sun_auditsys(...) 571 { 572 return 0; 573 } 574 575 struct sun_utsname { 576 char sysname[9]; 577 char nodename[9]; 578 char nodeext[65-9]; 579 char release[9]; 580 char version[9]; 581 char machine[9]; 582 }; 583 584 struct sun_uname_args { 585 struct sun_utsname *name; 586 }; 587 sun_uname(p, uap, retval) 588 struct proc *p; 589 struct sun_uname_args *uap; 590 int *retval; 591 { 592 struct sun_utsname sut; 593 594 /* first update utsname just as with NetBSD uname() */ 595 bcopy(hostname, utsname.nodename, sizeof(utsname.nodename)); 596 utsname.nodename[sizeof(utsname.nodename)-1] = '\0'; 597 598 /* then copy it over into SunOS struct utsname */ 599 bzero(&sut, sizeof(sut)); 600 bcopy(utsname.sysname, sut.sysname, sizeof(sut.sysname) - 1); 601 bcopy(utsname.nodename, sut.nodename, sizeof(sut.nodename) - 1); 602 bcopy(utsname.release, sut.release, sizeof(sut.release) - 1); 603 bcopy(utsname.version, sut.version, sizeof(sut.version) - 1); 604 bcopy(utsname.machine, sut.machine, sizeof(sut.machine) - 1); 605 606 return copyout((caddr_t)&sut, (caddr_t)uap->name, sizeof(struct sun_utsname)); 607 } 608 609 struct sun_setpgid_args { 610 int pid; /* target process id */ 611 int pgid; /* target pgrp id */ 612 }; 613 int 614 sun_setpgid(p, uap, retval) 615 struct proc *p; 616 struct sun_setpgid_args *uap; 617 int *retval; 618 { 619 /* 620 * difference to our setpgid call is to include backwards 621 * compatibility to pre-setsid() binaries. Do setsid() 622 * instead of setpgid() in those cases where the process 623 * tries to create a new session the old way. 624 */ 625 if (!uap->pgid && (!uap->pid || uap->pid == p->p_pid)) 626 return setsid(p, uap, retval); 627 else 628 return setpgid(p, uap, retval); 629 } 630 631 struct sun_open_args { 632 char *fname; 633 int fmode; 634 int crtmode; 635 }; 636 sun_open(p, uap, retval) 637 struct proc *p; 638 struct sun_open_args *uap; 639 int *retval; 640 { 641 int l, r; 642 int noctty = uap->fmode & 0x8000; 643 int ret; 644 645 /* convert mode into NetBSD mode */ 646 l = uap->fmode; 647 r = (l & (0x0001 | 0x0002 | 0x0008 | 0x0040 | 0x0200 | 0x0400 | 0x0800)); 648 r |= ((l & (0x0004 | 0x1000 | 0x4000)) ? O_NONBLOCK : 0); 649 r |= ((l & 0x0080) ? O_SHLOCK : 0); 650 r |= ((l & 0x0100) ? O_EXLOCK : 0); 651 r |= ((l & 0x2000) ? O_FSYNC : 0); 652 653 uap->fmode = r; 654 ret = open(p, uap, retval); 655 656 if (!ret && !noctty && SESS_LEADER(p) && !(p->p_flag & SCTTY)) { 657 struct filedesc *fdp = p->p_fd; 658 struct file *fp = fdp->fd_ofiles[*retval]; 659 660 /* ignore any error, just give it a try */ 661 if (fp->f_type == DTYPE_VNODE) 662 (fp->f_ops->fo_ioctl)(fp, TIOCSCTTY, (caddr_t) 0, p); 663 } 664 return ret; 665 } 666