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