1 /* 2 * Copyright (c) 1992 The Regents of the University of California. 3 * 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 Laboratories. 13 * 14 * %sccs.include.redist.c% 15 * 16 * @(#)sun_misc.c 7.4 (Berkeley) 10/11/92 17 * 18 * from: $Header: sun_misc.c,v 1.12 92/07/12 13:26:10 torek Exp $ 19 */ 20 21 /* 22 * SunOS compatibility module. 23 * 24 * SunOS system calls that are implemented differently in BSD are 25 * handled here. 26 */ 27 28 #include <sys/param.h> 29 #include <sys/proc.h> 30 #include <sys/file.h> 31 #include <sys/filedesc.h> 32 #include <sys/ioctl.h> 33 #include <sys/malloc.h> 34 #include <sys/mbuf.h> 35 #include <sys/mman.h> 36 #include <sys/mount.h> 37 #include <sys/resource.h> 38 #include <sys/resourcevar.h> 39 #include <sys/signal.h> 40 #include <sys/signalvar.h> 41 #include <sys/socket.h> 42 #include <sys/vnode.h> 43 #include <sys/uio.h> 44 #include <sys/wait.h> 45 46 #include <miscfs/specfs/specdev.h> 47 48 #include <vm/vm.h> 49 50 struct sun_wait4_args { 51 int pid; 52 int *status; 53 int options; 54 struct rusage *rusage; 55 }; 56 sun_wait4(p, uap, retval) 57 struct proc *p; 58 struct sun_wait4_args *uap; 59 int *retval; 60 { 61 62 if (uap->pid == 0) 63 uap->pid = WAIT_ANY; 64 return (wait4(p, uap, retval)); 65 } 66 67 struct sun_creat_args { 68 char *fname; 69 int fmode; 70 }; 71 sun_creat(p, uap, retval) 72 struct proc *p; 73 struct sun_creat_args *uap; 74 int *retval; 75 { 76 struct args { 77 char *fname; 78 int mode; 79 int crtmode; 80 } openuap; 81 82 openuap.fname = uap->fname; 83 openuap.crtmode = uap->fmode; 84 openuap.mode = O_WRONLY | O_CREAT | O_TRUNC; 85 return (open(p, &openuap, retval)); 86 } 87 88 struct sun_execv_args { 89 char *fname; 90 char **argp; 91 char **envp; /* pseudo */ 92 }; 93 sun_execv(p, uap, retval) 94 struct proc *p; 95 struct sun_execv_args *uap; 96 int *retval; 97 { 98 99 uap->envp = NULL; 100 return (execve(p, uap, retval)); 101 } 102 103 struct sun_omsync_args { 104 caddr_t addr; 105 int len; 106 int flags; 107 }; 108 sun_omsync(p, uap, retval) 109 struct proc *p; 110 struct sun_omsync_args *uap; 111 int *retval; 112 { 113 114 if (uap->flags) 115 return (EINVAL); 116 return (msync(p, uap, retval)); 117 } 118 119 struct sun_unmount_args { 120 char *name; 121 int flags; /* pseudo */ 122 }; 123 sun_unmount(p, uap, retval) 124 struct proc *p; 125 struct sun_unmount_args *uap; 126 int *retval; 127 { 128 129 uap->flags = MNT_NOFORCE; 130 return (unmount(p, uap, retval)); 131 } 132 133 static int 134 gettype(tptr) 135 int *tptr; 136 { 137 int type, error; 138 char in[20]; 139 140 if (error = copyinstr((caddr_t)*tptr, in, sizeof in, (u_int *)0)) 141 return (error); 142 if (strcmp(in, "4.2") == 0 || strcmp(in, "ufs") == 0) 143 type = MOUNT_UFS; 144 else if (strcmp(in, "nfs") == 0) 145 type = MOUNT_NFS; 146 else 147 return (EINVAL); 148 *tptr = type; 149 return (0); 150 } 151 152 #define SUNM_RDONLY 0x01 /* mount fs read-only */ 153 #define SUNM_NOSUID 0x02 /* mount fs with setuid disallowed */ 154 #define SUNM_NEWTYPE 0x04 /* type is string (char *), not int */ 155 #define SUNM_GRPID 0x08 /* (bsd semantics; ignored) */ 156 #define SUNM_REMOUNT 0x10 /* update existing mount */ 157 #define SUNM_NOSUB 0x20 /* prevent submounts (rejected) */ 158 #define SUNM_MULTI 0x40 /* (ignored) */ 159 #define SUNM_SYS5 0x80 /* Sys 5-specific semantics (rejected) */ 160 161 struct sun_mount_args { 162 int type; 163 char *dir; 164 int flags; 165 caddr_t data; 166 }; 167 sun_mount(p, uap, retval) 168 struct proc *p; 169 struct sun_mount_args *uap; 170 int *retval; 171 { 172 int oflags = uap->flags, nflags, error; 173 174 if (oflags & (SUNM_NOSUB | SUNM_SYS5)) 175 return (EINVAL); 176 if (oflags & SUNM_NEWTYPE && (error = gettype(&uap->type))) 177 return (error); 178 nflags = 0; 179 if (oflags & SUNM_RDONLY) 180 nflags |= MNT_RDONLY; 181 if (oflags & SUNM_NOSUID) 182 nflags |= MNT_NOSUID; 183 if (oflags & SUNM_REMOUNT) 184 nflags |= MNT_UPDATE; 185 uap->flags = nflags; 186 return (mount(p, uap, retval)); 187 } 188 189 struct sun_sigpending_args { 190 int *mask; 191 }; 192 sun_sigpending(p, uap, retval) 193 struct proc *p; 194 struct sun_sigpending_args *uap; 195 int *retval; 196 { 197 int mask = p->p_sig & p->p_sigmask; 198 199 return (copyout((caddr_t)&mask, (caddr_t)uap->mask, sizeof(int))); 200 } 201 202 #if 0 203 /* here is the sun layout (not used directly): */ 204 struct sun_dirent { 205 long d_off; 206 u_long d_fileno; 207 u_short d_reclen; 208 u_short d_namlen; 209 char d_name[256]; 210 }; 211 #endif 212 /* and the BSD layout: */ 213 struct bsd_dirent { 214 u_long d_fileno; 215 u_short d_reclen; 216 u_short d_namlen; 217 char d_name[256]; 218 }; 219 220 /* 221 * Read Sun-style directory entries. We suck them into kernel space so 222 * that they can be massaged before being copied out to user code. Like 223 * SunOS, we squish out `empty' entries. 224 * 225 * This is quite ugly, but what do you expect from compatibility code? 226 */ 227 struct sun_getdents_args { 228 int fd; 229 char *buf; 230 int nbytes; 231 }; 232 sun_getdents(p, uap, retval) 233 struct proc *p; 234 register struct sun_getdents_args *uap; 235 int *retval; 236 { 237 register struct vnode *vp; 238 register caddr_t inp, buf; /* BSD-format */ 239 register int len, reclen; /* BSD-format */ 240 register caddr_t outp; /* Sun-format */ 241 register int resid; /* Sun-format */ 242 struct file *fp; 243 struct uio auio; 244 struct iovec aiov; 245 off_t off; /* true file offset */ 246 long soff; /* Sun file offset */ 247 int buflen, error, eofflag; 248 #define SUN_RECLEN(reclen) (reclen + sizeof(long)) 249 250 if ((error = getvnode(p->p_fd, uap->fd, &fp)) != 0) 251 return (error); 252 if ((fp->f_flag & FREAD) == 0) 253 return (EBADF); 254 vp = (struct vnode *)fp->f_data; 255 if (vp->v_type != VDIR) /* XXX vnode readdir op should do this */ 256 return (EINVAL); 257 buflen = min(MAXBSIZE, uap->nbytes); 258 buf = malloc(buflen, M_TEMP, M_WAITOK); 259 VOP_LOCK(vp); 260 off = fp->f_offset; 261 again: 262 aiov.iov_base = buf; 263 aiov.iov_len = buflen; 264 auio.uio_iov = &aiov; 265 auio.uio_iovcnt = 1; 266 auio.uio_rw = UIO_READ; 267 auio.uio_segflg = UIO_SYSSPACE; 268 auio.uio_procp = p; 269 auio.uio_resid = buflen; 270 auio.uio_offset = off; 271 /* 272 * First we read into the malloc'ed buffer, then 273 * we massage it into user space, one record at a time. 274 */ 275 if (error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag)) 276 goto out; 277 inp = buf; 278 outp = uap->buf; 279 resid = uap->nbytes; 280 if ((len = buflen - auio.uio_resid) == 0) 281 goto eof; 282 for (; len > 0; len -= reclen) { 283 reclen = ((struct bsd_dirent *)inp)->d_reclen; 284 if (reclen & 3) 285 panic("sun_getdents"); 286 off += reclen; /* each entry points to next */ 287 if (((struct bsd_dirent *)inp)->d_fileno == 0) { 288 inp += reclen; /* it is a hole; squish it out */ 289 continue; 290 } 291 if (reclen > len || resid < SUN_RECLEN(reclen)) { 292 /* entry too big for buffer, so just stop */ 293 outp++; 294 break; 295 } 296 /* copy out a Sun-shaped dirent */ 297 ((struct bsd_dirent *)inp)->d_reclen = SUN_RECLEN(reclen); 298 soff = off; 299 if ((error = copyout((caddr_t)&soff, outp, sizeof soff)) != 0 || 300 (error = copyout(inp, outp + sizeof soff, reclen)) != 0) 301 goto out; 302 /* advance past this real entry */ 303 inp += reclen; 304 /* advance output past Sun-shaped entry */ 305 outp += SUN_RECLEN(reclen); 306 resid -= SUN_RECLEN(reclen); 307 } 308 /* if we squished out the whole block, try again */ 309 if (outp == uap->buf) 310 goto again; 311 fp->f_offset = off; /* update the vnode offset */ 312 eof: 313 *retval = uap->nbytes - resid; 314 out: 315 VOP_UNLOCK(vp); 316 free(buf, M_TEMP); 317 return (error); 318 } 319 320 #define MAXDOMAINNAME 64 321 char sun_domainname[MAXDOMAINNAME]; 322 int sun_domainnamelen = 1; 323 324 struct sun_getdomainname_args { 325 char *name; 326 int namelen; 327 }; 328 sun_getdomainname(p, uap, retval) 329 struct proc *p; 330 struct sun_getdomainname_args *uap; 331 int *retval; 332 { 333 register int l = min(uap->namelen, sun_domainnamelen + 1); 334 335 return (copyout(sun_domainname, uap->name, l)); 336 } 337 338 struct sun_setdomainname_args { 339 char *name; 340 int namelen; 341 }; 342 sun_setdomainname(p, uap, retval) 343 struct proc *p; 344 struct sun_setdomainname_args *uap; 345 int *retval; 346 { 347 register int l = uap->namelen, error; 348 349 if (l >= MAXDOMAINNAME) 350 return (EINVAL); /* ??? ENAMETOOLONG? */ 351 if (error = suser(p->p_ucred, &p->p_acflag)) 352 return (error); 353 if (error = copyin(uap->name, sun_domainname, l)) 354 return (error); 355 sun_domainname[l] = 0; 356 return (0); 357 } 358 359 #define SUN_MMAP_MASK 0xf /* mask for SHARED/PRIVATE */ 360 #define SUN_MMAP_CANDO 0x80000000 /* if not, old mmap & cannot handle */ 361 362 #define DEVZERO makedev(3, 12) /* major,minor of /dev/zero */ 363 364 #define SUN_MMAP_SAME (MAP_SHARED|MAP_PRIVATE|MAP_FIXED|MAP_INHERIT) 365 366 struct sun_mmap_args { 367 caddr_t addr; 368 size_t len; 369 int prot; 370 int flags; 371 int fd; 372 long off; /* not off_t! */ 373 quad_t qoff; /* created here and fed to smmap() */ 374 }; 375 sun_mmap(p, uap, retval) 376 register struct proc *p; 377 register struct sun_mmap_args *uap; 378 int *retval; 379 { 380 register int flags; 381 register struct filedesc *fdp; 382 register struct file *fp; 383 register struct vnode *vp; 384 385 /* 386 * Verify the arguments. 387 */ 388 flags = uap->flags; 389 if ((flags & SUN_MMAP_CANDO) == 0) 390 return (EINVAL); 391 if ((flags & SUN_MMAP_MASK) != MAP_SHARED && 392 (flags & SUN_MMAP_MASK) != MAP_PRIVATE) 393 return (EINVAL); 394 flags &= ~SUN_MMAP_CANDO; 395 396 /* 397 * Special case: if fd refers to /dev/zero, map as MAP_ANON. (XXX) 398 */ 399 fdp = p->p_fd; 400 if ((unsigned)uap->fd < fdp->fd_nfiles && /*XXX*/ 401 (fp = fdp->fd_ofiles[uap->fd]) != NULL && /*XXX*/ 402 fp->f_type == DTYPE_VNODE && /*XXX*/ 403 (vp = (struct vnode *)fp->f_data)->v_type == VCHR && /*XXX*/ 404 vp->v_rdev == DEVZERO) { /*XXX*/ 405 flags |= MAP_ANON; 406 uap->fd = -1; 407 } 408 409 /* All done, fix up fields and go. */ 410 uap->flags = flags; 411 uap->qoff = (quad_t)uap->off; 412 return (smmap(p, uap, retval)); 413 } 414 415 #define MC_SYNC 1 416 #define MC_LOCK 2 417 #define MC_UNLOCK 3 418 #define MC_ADVISE 4 419 #define MC_LOCKAS 5 420 #define MC_UNLOCKAS 6 421 422 struct sun_mctl_args { 423 caddr_t addr; 424 size_t len; 425 int func; 426 void *arg; 427 }; 428 sun_mctl(p, uap, retval) 429 register struct proc *p; 430 register struct sun_mctl_args *uap; 431 int *retval; 432 { 433 434 switch (uap->func) { 435 436 case MC_ADVISE: /* ignore for now */ 437 return (0); 438 439 case MC_SYNC: /* translate to msync */ 440 return (msync(p, uap, retval)); 441 442 default: 443 return (EINVAL); 444 } 445 } 446 447 struct sun_setreuid_args { 448 int ruid; /* not uid_t */ 449 int euid; 450 }; 451 sun_setreuid(p, uap, retval) 452 struct proc *p; 453 struct sun_setreuid_args *uap; 454 int *retval; 455 { 456 register struct pcred *pc = p->p_cred; 457 register uid_t ruid, euid; 458 int error; 459 460 if (uap->ruid == -1) 461 ruid = pc->p_ruid; 462 else 463 ruid = uap->ruid; 464 /* 465 * Allow setting real uid to previous effective, for swapping real and 466 * effective. This should be: 467 * 468 * if (ruid != pc->p_ruid && 469 * (error = suser(pc->pc_ucred, &p->p_acflag))) 470 */ 471 if (ruid != pc->p_ruid && ruid != pc->pc_ucred->cr_uid /* XXX */ && 472 (error = suser(pc->pc_ucred, &p->p_acflag))) 473 return (error); 474 if (uap->euid == -1) 475 euid = pc->pc_ucred->cr_uid; 476 else 477 euid = uap->euid; 478 if (euid != pc->pc_ucred->cr_uid && euid != pc->p_ruid && 479 euid != pc->p_svuid && (error = suser(pc->pc_ucred, &p->p_acflag))) 480 return (error); 481 /* 482 * Everything's okay, do it. Copy credentials so other references do 483 * not see our changes. 484 */ 485 pc->pc_ucred = crcopy(pc->pc_ucred); 486 pc->pc_ucred->cr_uid = euid; 487 pc->p_ruid = ruid; 488 p->p_flag |= SUGID; 489 return (0); 490 } 491 492 struct sun_setregid_args { 493 int rgid; /* not gid_t */ 494 int egid; 495 }; 496 sun_setregid(p, uap, retval) 497 struct proc *p; 498 struct sun_setregid_args *uap; 499 int *retval; 500 { 501 register struct pcred *pc = p->p_cred; 502 register gid_t rgid, egid; 503 int error; 504 505 if (uap->rgid == -1) 506 rgid = pc->p_rgid; 507 else 508 rgid = uap->rgid; 509 /* 510 * Allow setting real gid to previous effective, for swapping real and 511 * effective. This didn't really work correctly in 4.[23], but is 512 * preserved so old stuff doesn't fail. This should be: 513 * 514 * if (rgid != pc->p_rgid && 515 * (error = suser(pc->pc_ucred, &p->p_acflag))) 516 */ 517 if (rgid != pc->p_rgid && rgid != pc->pc_ucred->cr_groups[0] /* XXX */ && 518 (error = suser(pc->pc_ucred, &p->p_acflag))) 519 return (error); 520 if (uap->egid == -1) 521 egid = pc->pc_ucred->cr_groups[0]; 522 else 523 egid = uap->egid; 524 if (egid != pc->pc_ucred->cr_groups[0] && egid != pc->p_rgid && 525 egid != pc->p_svgid && (error = suser(pc->pc_ucred, &p->p_acflag))) 526 return (error); 527 pc->pc_ucred = crcopy(pc->pc_ucred); 528 pc->pc_ucred->cr_groups[0] = egid; 529 pc->p_rgid = rgid; 530 p->p_flag |= SUGID; 531 return (0); 532 } 533 534 struct sun_setsockopt_args { 535 int s; 536 int level; 537 int name; 538 caddr_t val; 539 int valsize; 540 }; 541 sun_setsockopt(p, uap, retval) 542 struct proc *p; 543 register struct sun_setsockopt_args *uap; 544 int *retval; 545 { 546 struct file *fp; 547 struct mbuf *m = NULL; 548 int error; 549 550 if (error = getsock(p->p_fd, uap->s, &fp)) 551 return (error); 552 #define SO_DONTLINGER (~SO_LINGER) 553 if (uap->name == SO_DONTLINGER) { 554 m = m_get(M_WAIT, MT_SOOPTS); 555 if (m == NULL) 556 return (ENOBUFS); 557 mtod(m, struct linger *)->l_onoff = 0; 558 m->m_len = sizeof(struct linger); 559 return (sosetopt((struct socket *)fp->f_data, uap->level, 560 SO_LINGER, m)); 561 } 562 if (uap->valsize > MLEN) 563 return (EINVAL); 564 if (uap->val) { 565 m = m_get(M_WAIT, MT_SOOPTS); 566 if (m == NULL) 567 return (ENOBUFS); 568 if (error = copyin(uap->val, mtod(m, caddr_t), 569 (u_int)uap->valsize)) { 570 (void) m_free(m); 571 return (error); 572 } 573 m->m_len = uap->valsize; 574 } 575 return (sosetopt((struct socket *)fp->f_data, uap->level, 576 uap->name, m)); 577 } 578 579 struct sun_fchroot_args { 580 int fdes; 581 }; 582 sun_fchroot(p, uap, retval) 583 register struct proc *p; 584 register struct sun_fchroot_args *uap; 585 int *retval; 586 { 587 register struct filedesc *fdp = p->p_fd; 588 register struct vnode *vp; 589 struct file *fp; 590 int error; 591 592 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 593 return (error); 594 if ((error = getvnode(fdp, uap->fdes, &fp)) != 0) 595 return (error); 596 vp = (struct vnode *)fp->f_data; 597 VOP_LOCK(vp); 598 if (vp->v_type != VDIR) 599 error = ENOTDIR; 600 else 601 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 602 VOP_UNLOCK(vp); 603 if (error) 604 return (error); 605 VREF(vp); 606 if (fdp->fd_rdir != NULL) 607 vrele(fdp->fd_rdir); 608 fdp->fd_rdir = vp; 609 return (0); 610 } 611