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.5 (Berkeley) 05/14/95 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 = 1; /* old MOUNT_UFS */ 146 else if (strcmp(in, "nfs") == 0) 147 type = 2; /* old 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; 200 201 mask = p->p_siglist & p->p_sigmask; 202 return (copyout(&mask, uap->mask, sizeof(int))); 203 } 204 205 /* 206 * Here is the sun layout. (Compare the BSD layout in <sys/dirent.h>.) 207 * We can assume big-endian, so the BSD d_type field is just the high 208 * byte of the SunOS d_namlen field, after adjusting for the extra "long". 209 */ 210 struct sun_dirent { 211 long d_off; 212 u_long d_fileno; 213 u_short d_reclen; 214 u_short d_namlen; 215 char d_name[256]; 216 }; 217 218 /* 219 * Read Sun-style directory entries. We suck them into kernel space so 220 * that they can be massaged before being copied out to user code. Like 221 * SunOS, we squish out `empty' entries. 222 * 223 * This is quite ugly, but what do you expect from compatibility code? 224 */ 225 struct sun_getdents_args { 226 int fd; 227 char *buf; 228 int nbytes; 229 }; 230 sun_getdents(p, uap, retval) 231 struct proc *p; 232 register struct sun_getdents_args *uap; 233 int *retval; 234 { 235 register struct vnode *vp; 236 register caddr_t inp, buf; /* BSD-format */ 237 register int len, reclen; /* BSD-format */ 238 register caddr_t outp; /* Sun-format */ 239 register int resid; /* Sun-format */ 240 struct file *fp; 241 struct uio auio; 242 struct iovec aiov; 243 off_t off; /* true file offset */ 244 long soff; /* Sun file offset */ 245 int buflen, error, eofflag; 246 #define BSD_DIRENT(cp) ((struct dirent *)(cp)) 247 #define SUN_RECLEN(reclen) (reclen + sizeof(long)) 248 249 if ((error = getvnode(p->p_fd, uap->fd, &fp)) != 0) 250 return (error); 251 if ((fp->f_flag & FREAD) == 0) 252 return (EBADF); 253 vp = (struct vnode *)fp->f_data; 254 if (vp->v_type != VDIR) /* XXX vnode readdir op should do this */ 255 return (EINVAL); 256 buflen = min(MAXBSIZE, uap->nbytes); 257 buf = malloc(buflen, M_TEMP, M_WAITOK); 258 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p) 259 off = fp->f_offset; 260 again: 261 aiov.iov_base = buf; 262 aiov.iov_len = buflen; 263 auio.uio_iov = &aiov; 264 auio.uio_iovcnt = 1; 265 auio.uio_rw = UIO_READ; 266 auio.uio_segflg = UIO_SYSSPACE; 267 auio.uio_procp = p; 268 auio.uio_resid = buflen; 269 auio.uio_offset = off; 270 /* 271 * First we read into the malloc'ed buffer, then 272 * we massage it into user space, one record at a time. 273 */ 274 if (error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, (u_long *)0,0)) 275 goto out; 276 inp = buf; 277 outp = uap->buf; 278 resid = uap->nbytes; 279 if ((len = buflen - auio.uio_resid) == 0) 280 goto eof; 281 for (; len > 0; len -= reclen) { 282 reclen = ((struct dirent *)inp)->d_reclen; 283 if (reclen & 3) 284 panic("sun_getdents"); 285 off += reclen; /* each entry points to next */ 286 if (BSD_DIRENT(inp)->d_fileno == 0) { 287 inp += reclen; /* it is a hole; squish it out */ 288 continue; 289 } 290 if (reclen > len || resid < SUN_RECLEN(reclen)) { 291 /* entry too big for buffer, so just stop */ 292 outp++; 293 break; 294 } 295 /* 296 * Massage in place to make a Sun-shaped dirent (otherwise 297 * we have to worry about touching user memory outside of 298 * the copyout() call). 299 */ 300 BSD_DIRENT(inp)->d_reclen = SUN_RECLEN(reclen); 301 BSD_DIRENT(inp)->d_type = 0; 302 soff = off; 303 if ((error = copyout((caddr_t)&soff, outp, sizeof soff)) != 0 || 304 (error = copyout(inp, outp + sizeof soff, reclen)) != 0) 305 goto out; 306 /* advance past this real entry */ 307 inp += reclen; 308 /* advance output past Sun-shaped entry */ 309 outp += SUN_RECLEN(reclen); 310 resid -= SUN_RECLEN(reclen); 311 } 312 /* if we squished out the whole block, try again */ 313 if (outp == uap->buf) 314 goto again; 315 fp->f_offset = off; /* update the vnode offset */ 316 eof: 317 *retval = uap->nbytes - resid; 318 out: 319 VOP_UNLOCK(vp, 0, p); 320 free(buf, M_TEMP); 321 return (error); 322 } 323 324 #define MAXDOMAINNAME 64 325 char sun_domainname[MAXDOMAINNAME]; 326 int sun_domainnamelen = 1; 327 328 struct sun_getdomainname_args { 329 char *name; 330 int namelen; 331 }; 332 sun_getdomainname(p, uap, retval) 333 struct proc *p; 334 struct sun_getdomainname_args *uap; 335 int *retval; 336 { 337 register int l = min(uap->namelen, sun_domainnamelen + 1); 338 339 return (copyout(sun_domainname, uap->name, l)); 340 } 341 342 struct sun_setdomainname_args { 343 char *name; 344 int namelen; 345 }; 346 sun_setdomainname(p, uap, retval) 347 struct proc *p; 348 struct sun_setdomainname_args *uap; 349 int *retval; 350 { 351 register int l = uap->namelen, error; 352 353 if (l >= MAXDOMAINNAME) 354 return (EINVAL); /* ??? ENAMETOOLONG? */ 355 if (error = suser(p->p_ucred, &p->p_acflag)) 356 return (error); 357 if (error = copyin(uap->name, sun_domainname, l)) 358 return (error); 359 sun_domainname[l] = 0; 360 return (0); 361 } 362 363 #define SUN_MMAP_MASK 0xf /* mask for SHARED/PRIVATE */ 364 #define SUN_MMAP_CANDO 0x80000000 /* if not, old mmap & cannot handle */ 365 366 #define DEVZERO makedev(3, 12) /* major,minor of /dev/zero */ 367 368 #define SUN_MMAP_SAME (MAP_SHARED|MAP_PRIVATE|MAP_FIXED|MAP_INHERIT) 369 370 struct sun_mmap_args { 371 caddr_t addr; 372 size_t len; 373 int prot; 374 int flags; 375 int fd; 376 long off; /* not off_t! */ 377 quad_t qoff; /* created here and fed to mmap() */ 378 }; 379 sun_mmap(p, uap, retval) 380 register struct proc *p; 381 register struct sun_mmap_args *uap; 382 int *retval; 383 { 384 register int flags; 385 register struct filedesc *fdp; 386 register struct file *fp; 387 register struct vnode *vp; 388 389 /* 390 * Verify the arguments. 391 */ 392 flags = uap->flags; 393 if ((flags & SUN_MMAP_CANDO) == 0) 394 return (EINVAL); 395 if ((flags & SUN_MMAP_MASK) != MAP_SHARED && 396 (flags & SUN_MMAP_MASK) != MAP_PRIVATE) 397 return (EINVAL); 398 flags &= ~SUN_MMAP_CANDO; 399 400 /* 401 * Special case: if fd refers to /dev/zero, map as MAP_ANON. (XXX) 402 */ 403 fdp = p->p_fd; 404 if ((unsigned)uap->fd < fdp->fd_nfiles && /*XXX*/ 405 (fp = fdp->fd_ofiles[uap->fd]) != NULL && /*XXX*/ 406 fp->f_type == DTYPE_VNODE && /*XXX*/ 407 (vp = (struct vnode *)fp->f_data)->v_type == VCHR && /*XXX*/ 408 vp->v_rdev == DEVZERO) { /*XXX*/ 409 flags |= MAP_ANON; 410 uap->fd = -1; 411 } 412 413 /* All done, fix up fields and go. */ 414 uap->flags = flags; 415 uap->qoff = (quad_t)uap->off; 416 return (mmap(p, uap, retval)); 417 } 418 419 #define MC_SYNC 1 420 #define MC_LOCK 2 421 #define MC_UNLOCK 3 422 #define MC_ADVISE 4 423 #define MC_LOCKAS 5 424 #define MC_UNLOCKAS 6 425 426 struct sun_mctl_args { 427 caddr_t addr; 428 size_t len; 429 int func; 430 void *arg; 431 }; 432 sun_mctl(p, uap, retval) 433 register struct proc *p; 434 register struct sun_mctl_args *uap; 435 int *retval; 436 { 437 438 switch (uap->func) { 439 440 case MC_ADVISE: /* ignore for now */ 441 return (0); 442 443 case MC_SYNC: /* translate to msync */ 444 return (msync(p, uap, retval)); 445 446 default: 447 return (EINVAL); 448 } 449 } 450 451 struct sun_setsockopt_args { 452 int s; 453 int level; 454 int name; 455 caddr_t val; 456 int valsize; 457 }; 458 sun_setsockopt(p, uap, retval) 459 struct proc *p; 460 register struct sun_setsockopt_args *uap; 461 int *retval; 462 { 463 struct file *fp; 464 struct mbuf *m = NULL; 465 int error; 466 467 if (error = getsock(p->p_fd, uap->s, &fp)) 468 return (error); 469 #define SO_DONTLINGER (~SO_LINGER) 470 if (uap->name == SO_DONTLINGER) { 471 m = m_get(M_WAIT, MT_SOOPTS); 472 if (m == NULL) 473 return (ENOBUFS); 474 mtod(m, struct linger *)->l_onoff = 0; 475 m->m_len = sizeof(struct linger); 476 return (sosetopt((struct socket *)fp->f_data, uap->level, 477 SO_LINGER, m)); 478 } 479 if (uap->valsize > MLEN) 480 return (EINVAL); 481 if (uap->val) { 482 m = m_get(M_WAIT, MT_SOOPTS); 483 if (m == NULL) 484 return (ENOBUFS); 485 if (error = copyin(uap->val, mtod(m, caddr_t), 486 (u_int)uap->valsize)) { 487 (void) m_free(m); 488 return (error); 489 } 490 m->m_len = uap->valsize; 491 } 492 return (sosetopt((struct socket *)fp->f_data, uap->level, 493 uap->name, m)); 494 } 495 496 struct sun_fchroot_args { 497 int fdes; 498 }; 499 sun_fchroot(p, uap, retval) 500 register struct proc *p; 501 register struct sun_fchroot_args *uap; 502 int *retval; 503 { 504 register struct filedesc *fdp = p->p_fd; 505 register struct vnode *vp; 506 struct file *fp; 507 int error; 508 509 if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 510 return (error); 511 if ((error = getvnode(fdp, uap->fdes, &fp)) != 0) 512 return (error); 513 vp = (struct vnode *)fp->f_data; 514 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p) 515 if (vp->v_type != VDIR) 516 error = ENOTDIR; 517 else 518 error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 519 VOP_UNLOCK(vp, 0, p); 520 if (error) 521 return (error); 522 VREF(vp); 523 if (fdp->fd_rdir != NULL) 524 vrele(fdp->fd_rdir); 525 fdp->fd_rdir = vp; 526 return (0); 527 } 528