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