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