155099Storek /* 255099Storek * Copyright (c) 1992 The Regents of the University of California. 355099Storek * All rights reserved. 455099Storek * 555099Storek * This software was developed by the Computer Systems Engineering group 655099Storek * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 755099Storek * contributed to Berkeley. 855099Storek * 955505Sbostic * All advertising materials mentioning features or use of this software 1055505Sbostic * must display the following acknowledgement: 1155505Sbostic * This product includes software developed by the University of 12*58995Storek * California, Lawrence Berkeley Laboratory. 1355505Sbostic * 1455099Storek * %sccs.include.redist.c% 1555099Storek * 16*58995Storek * @(#)sun_misc.c 7.5 (Berkeley) 04/06/93 1755099Storek * 18*58995Storek * from: $Header: sun_misc.c,v 1.16 93/04/07 02:46:27 torek Exp $ 1955099Storek */ 2055099Storek 2155099Storek /* 2255099Storek * SunOS compatibility module. 2355099Storek * 2455099Storek * SunOS system calls that are implemented differently in BSD are 2555099Storek * handled here. 2655099Storek */ 2755099Storek 2856543Sbostic #include <sys/param.h> 29*58995Storek #include <sys/systm.h> 30*58995Storek #include <sys/dirent.h> 3156543Sbostic #include <sys/proc.h> 3256543Sbostic #include <sys/file.h> 3356543Sbostic #include <sys/filedesc.h> 3456543Sbostic #include <sys/ioctl.h> 3556543Sbostic #include <sys/malloc.h> 3656543Sbostic #include <sys/mbuf.h> 3756543Sbostic #include <sys/mman.h> 3856543Sbostic #include <sys/mount.h> 3956543Sbostic #include <sys/resource.h> 4056543Sbostic #include <sys/resourcevar.h> 4156543Sbostic #include <sys/signal.h> 4256543Sbostic #include <sys/signalvar.h> 4356543Sbostic #include <sys/socket.h> 4456543Sbostic #include <sys/vnode.h> 4556543Sbostic #include <sys/uio.h> 4656543Sbostic #include <sys/wait.h> 4755099Storek 4856543Sbostic #include <miscfs/specfs/specdev.h> 4955174Storek 5056543Sbostic #include <vm/vm.h> 5155099Storek 5255099Storek struct sun_wait4_args { 5355099Storek int pid; 5455099Storek int *status; 5555099Storek int options; 5655099Storek struct rusage *rusage; 5755099Storek }; 5855099Storek sun_wait4(p, uap, retval) 5955099Storek struct proc *p; 6055099Storek struct sun_wait4_args *uap; 6155099Storek int *retval; 6255099Storek { 6355099Storek 6455099Storek if (uap->pid == 0) 6555099Storek uap->pid = WAIT_ANY; 6655099Storek return (wait4(p, uap, retval)); 6755099Storek } 6855099Storek 6955099Storek struct sun_creat_args { 7055099Storek char *fname; 7155099Storek int fmode; 7255099Storek }; 7355099Storek sun_creat(p, uap, retval) 7455099Storek struct proc *p; 7555099Storek struct sun_creat_args *uap; 7655099Storek int *retval; 7755099Storek { 7855099Storek struct args { 7955099Storek char *fname; 8055099Storek int mode; 8155099Storek int crtmode; 8255099Storek } openuap; 8355099Storek 8455099Storek openuap.fname = uap->fname; 8555099Storek openuap.crtmode = uap->fmode; 8655099Storek openuap.mode = O_WRONLY | O_CREAT | O_TRUNC; 8755099Storek return (open(p, &openuap, retval)); 8855099Storek } 8955099Storek 9055099Storek struct sun_execv_args { 9155099Storek char *fname; 9255099Storek char **argp; 9355099Storek char **envp; /* pseudo */ 9455099Storek }; 9555099Storek sun_execv(p, uap, retval) 9655099Storek struct proc *p; 9755099Storek struct sun_execv_args *uap; 9855099Storek int *retval; 9955099Storek { 10055099Storek 10155099Storek uap->envp = NULL; 10255099Storek return (execve(p, uap, retval)); 10355099Storek } 10455099Storek 10555099Storek struct sun_omsync_args { 10655099Storek caddr_t addr; 10755099Storek int len; 10855099Storek int flags; 10955099Storek }; 11055099Storek sun_omsync(p, uap, retval) 11155099Storek struct proc *p; 11255099Storek struct sun_omsync_args *uap; 11355099Storek int *retval; 11455099Storek { 11555099Storek 11655099Storek if (uap->flags) 11755099Storek return (EINVAL); 11855099Storek return (msync(p, uap, retval)); 11955099Storek } 12055099Storek 12155099Storek struct sun_unmount_args { 12255099Storek char *name; 12355099Storek int flags; /* pseudo */ 12455099Storek }; 12555099Storek sun_unmount(p, uap, retval) 12655099Storek struct proc *p; 12755099Storek struct sun_unmount_args *uap; 12855099Storek int *retval; 12955099Storek { 13055099Storek 131*58995Storek uap->flags = 0; 13255099Storek return (unmount(p, uap, retval)); 13355099Storek } 13455099Storek 13555099Storek static int 13655099Storek gettype(tptr) 13755099Storek int *tptr; 13855099Storek { 13955099Storek int type, error; 14055099Storek char in[20]; 14155099Storek 14255099Storek if (error = copyinstr((caddr_t)*tptr, in, sizeof in, (u_int *)0)) 14355099Storek return (error); 14455099Storek if (strcmp(in, "4.2") == 0 || strcmp(in, "ufs") == 0) 14555099Storek type = MOUNT_UFS; 14655099Storek else if (strcmp(in, "nfs") == 0) 14755099Storek type = MOUNT_NFS; 14855099Storek else 14955099Storek return (EINVAL); 15055099Storek *tptr = type; 15155099Storek return (0); 15255099Storek } 15355099Storek 15455099Storek #define SUNM_RDONLY 0x01 /* mount fs read-only */ 15555099Storek #define SUNM_NOSUID 0x02 /* mount fs with setuid disallowed */ 15655099Storek #define SUNM_NEWTYPE 0x04 /* type is string (char *), not int */ 15755099Storek #define SUNM_GRPID 0x08 /* (bsd semantics; ignored) */ 15855099Storek #define SUNM_REMOUNT 0x10 /* update existing mount */ 15955099Storek #define SUNM_NOSUB 0x20 /* prevent submounts (rejected) */ 16055099Storek #define SUNM_MULTI 0x40 /* (ignored) */ 16155099Storek #define SUNM_SYS5 0x80 /* Sys 5-specific semantics (rejected) */ 16255099Storek 16355099Storek struct sun_mount_args { 16455099Storek int type; 16555099Storek char *dir; 16655099Storek int flags; 16755099Storek caddr_t data; 16855099Storek }; 16955099Storek sun_mount(p, uap, retval) 17055099Storek struct proc *p; 17155099Storek struct sun_mount_args *uap; 17255099Storek int *retval; 17355099Storek { 17455099Storek int oflags = uap->flags, nflags, error; 17555099Storek 17655099Storek if (oflags & (SUNM_NOSUB | SUNM_SYS5)) 17755099Storek return (EINVAL); 17855099Storek if (oflags & SUNM_NEWTYPE && (error = gettype(&uap->type))) 17955099Storek return (error); 18055099Storek nflags = 0; 18155099Storek if (oflags & SUNM_RDONLY) 18255099Storek nflags |= MNT_RDONLY; 18355099Storek if (oflags & SUNM_NOSUID) 18455099Storek nflags |= MNT_NOSUID; 18555099Storek if (oflags & SUNM_REMOUNT) 18655099Storek nflags |= MNT_UPDATE; 18755099Storek uap->flags = nflags; 18855099Storek return (mount(p, uap, retval)); 18955099Storek } 19055099Storek 19155099Storek struct sun_sigpending_args { 19255099Storek int *mask; 19355099Storek }; 19455099Storek sun_sigpending(p, uap, retval) 19555099Storek struct proc *p; 19655099Storek struct sun_sigpending_args *uap; 19755099Storek int *retval; 19855099Storek { 19955099Storek int mask = p->p_sig & p->p_sigmask; 20055099Storek 20155099Storek return (copyout((caddr_t)&mask, (caddr_t)uap->mask, sizeof(int))); 20255099Storek } 20355099Storek 204*58995Storek /* 205*58995Storek * Here is the sun layout. (Compare the BSD layout in <sys/dirent.h>.) 206*58995Storek * We can assume big-endian, so the BSD d_type field is just the high 207*58995Storek * byte of the SunOS d_namlen field, after adjusting for the extra "long". 208*58995Storek */ 20955099Storek struct sun_dirent { 21055099Storek long d_off; 21155099Storek u_long d_fileno; 21255099Storek u_short d_reclen; 21355099Storek u_short d_namlen; 21455099Storek char d_name[256]; 21555099Storek }; 21655099Storek 21755099Storek /* 21855099Storek * Read Sun-style directory entries. We suck them into kernel space so 21955099Storek * that they can be massaged before being copied out to user code. Like 22055099Storek * SunOS, we squish out `empty' entries. 22155099Storek * 22255099Storek * This is quite ugly, but what do you expect from compatibility code? 22355099Storek */ 22455099Storek struct sun_getdents_args { 22555099Storek int fd; 22655099Storek char *buf; 22755099Storek int nbytes; 22855099Storek }; 22955099Storek sun_getdents(p, uap, retval) 23055099Storek struct proc *p; 23155099Storek register struct sun_getdents_args *uap; 23255099Storek int *retval; 23355099Storek { 23455099Storek register struct vnode *vp; 23555099Storek register caddr_t inp, buf; /* BSD-format */ 23655099Storek register int len, reclen; /* BSD-format */ 23755099Storek register caddr_t outp; /* Sun-format */ 23855099Storek register int resid; /* Sun-format */ 23955099Storek struct file *fp; 24055099Storek struct uio auio; 24155099Storek struct iovec aiov; 24255099Storek off_t off; /* true file offset */ 24355099Storek long soff; /* Sun file offset */ 24455099Storek int buflen, error, eofflag; 245*58995Storek #define BSD_DIRENT(cp) ((struct dirent *)(cp)) 24655099Storek #define SUN_RECLEN(reclen) (reclen + sizeof(long)) 24755099Storek 24855099Storek if ((error = getvnode(p->p_fd, uap->fd, &fp)) != 0) 24955099Storek return (error); 25055099Storek if ((fp->f_flag & FREAD) == 0) 25155099Storek return (EBADF); 25255099Storek vp = (struct vnode *)fp->f_data; 25355099Storek if (vp->v_type != VDIR) /* XXX vnode readdir op should do this */ 25455099Storek return (EINVAL); 25555099Storek buflen = min(MAXBSIZE, uap->nbytes); 25655099Storek buf = malloc(buflen, M_TEMP, M_WAITOK); 25755099Storek VOP_LOCK(vp); 25855099Storek off = fp->f_offset; 25955099Storek again: 26055099Storek aiov.iov_base = buf; 26155099Storek aiov.iov_len = buflen; 26255099Storek auio.uio_iov = &aiov; 26355099Storek auio.uio_iovcnt = 1; 26455099Storek auio.uio_rw = UIO_READ; 26555099Storek auio.uio_segflg = UIO_SYSSPACE; 26655099Storek auio.uio_procp = p; 26755099Storek auio.uio_resid = buflen; 26855099Storek auio.uio_offset = off; 26955099Storek /* 27055099Storek * First we read into the malloc'ed buffer, then 27155099Storek * we massage it into user space, one record at a time. 27255099Storek */ 27355099Storek if (error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag)) 27455099Storek goto out; 27555099Storek inp = buf; 27655099Storek outp = uap->buf; 27755099Storek resid = uap->nbytes; 27855099Storek if ((len = buflen - auio.uio_resid) == 0) 27955099Storek goto eof; 28055099Storek for (; len > 0; len -= reclen) { 281*58995Storek reclen = ((struct dirent *)inp)->d_reclen; 28255099Storek if (reclen & 3) 28355099Storek panic("sun_getdents"); 28455099Storek off += reclen; /* each entry points to next */ 285*58995Storek if (BSD_DIRENT(inp)->d_fileno == 0) { 28655099Storek inp += reclen; /* it is a hole; squish it out */ 28755099Storek continue; 28855099Storek } 28955099Storek if (reclen > len || resid < SUN_RECLEN(reclen)) { 29055099Storek /* entry too big for buffer, so just stop */ 29155099Storek outp++; 29255099Storek break; 29355099Storek } 294*58995Storek /* 295*58995Storek * Massage in place to make a Sun-shaped dirent (otherwise 296*58995Storek * we have to worry about touching user memory outside of 297*58995Storek * the copyout() call). 298*58995Storek */ 299*58995Storek BSD_DIRENT(inp)->d_reclen = SUN_RECLEN(reclen); 300*58995Storek BSD_DIRENT(inp)->d_type = 0; 30155099Storek soff = off; 30255099Storek if ((error = copyout((caddr_t)&soff, outp, sizeof soff)) != 0 || 30355099Storek (error = copyout(inp, outp + sizeof soff, reclen)) != 0) 30455099Storek goto out; 30555099Storek /* advance past this real entry */ 30655099Storek inp += reclen; 30755099Storek /* advance output past Sun-shaped entry */ 30855099Storek outp += SUN_RECLEN(reclen); 30955099Storek resid -= SUN_RECLEN(reclen); 31055099Storek } 31155099Storek /* if we squished out the whole block, try again */ 31255099Storek if (outp == uap->buf) 31355099Storek goto again; 31455099Storek fp->f_offset = off; /* update the vnode offset */ 31555099Storek eof: 31655099Storek *retval = uap->nbytes - resid; 31755099Storek out: 31855099Storek VOP_UNLOCK(vp); 31955099Storek free(buf, M_TEMP); 32055099Storek return (error); 32155099Storek } 32255099Storek 32355099Storek #define MAXDOMAINNAME 64 32455099Storek char sun_domainname[MAXDOMAINNAME]; 32555099Storek int sun_domainnamelen = 1; 32655099Storek 32755099Storek struct sun_getdomainname_args { 32855099Storek char *name; 32955099Storek int namelen; 33055099Storek }; 33155099Storek sun_getdomainname(p, uap, retval) 33255099Storek struct proc *p; 33355099Storek struct sun_getdomainname_args *uap; 33455099Storek int *retval; 33555099Storek { 33655099Storek register int l = min(uap->namelen, sun_domainnamelen + 1); 33755099Storek 33855099Storek return (copyout(sun_domainname, uap->name, l)); 33955099Storek } 34055099Storek 34155099Storek struct sun_setdomainname_args { 34255099Storek char *name; 34355099Storek int namelen; 34455099Storek }; 34555099Storek sun_setdomainname(p, uap, retval) 34655099Storek struct proc *p; 34755099Storek struct sun_setdomainname_args *uap; 34855099Storek int *retval; 34955099Storek { 35055099Storek register int l = uap->namelen, error; 35155099Storek 35255099Storek if (l >= MAXDOMAINNAME) 35355099Storek return (EINVAL); /* ??? ENAMETOOLONG? */ 35455099Storek if (error = suser(p->p_ucred, &p->p_acflag)) 35555099Storek return (error); 35655099Storek if (error = copyin(uap->name, sun_domainname, l)) 35755099Storek return (error); 35855099Storek sun_domainname[l] = 0; 35955099Storek return (0); 36055099Storek } 36155099Storek 36255099Storek #define SUN_MMAP_MASK 0xf /* mask for SHARED/PRIVATE */ 36355099Storek #define SUN_MMAP_CANDO 0x80000000 /* if not, old mmap & cannot handle */ 36455099Storek 36555099Storek #define DEVZERO makedev(3, 12) /* major,minor of /dev/zero */ 36655099Storek 36755099Storek #define SUN_MMAP_SAME (MAP_SHARED|MAP_PRIVATE|MAP_FIXED|MAP_INHERIT) 36855099Storek 36955099Storek struct sun_mmap_args { 37055099Storek caddr_t addr; 37155099Storek size_t len; 37255099Storek int prot; 37355099Storek int flags; 37455099Storek int fd; 37555099Storek long off; /* not off_t! */ 37655099Storek quad_t qoff; /* created here and fed to smmap() */ 37755099Storek }; 37855099Storek sun_mmap(p, uap, retval) 37955099Storek register struct proc *p; 38055099Storek register struct sun_mmap_args *uap; 38155099Storek int *retval; 38255099Storek { 38355099Storek register int flags; 38455099Storek register struct filedesc *fdp; 38555099Storek register struct file *fp; 38655099Storek register struct vnode *vp; 38755099Storek 38855099Storek /* 38955099Storek * Verify the arguments. 39055099Storek */ 39155099Storek flags = uap->flags; 39255099Storek if ((flags & SUN_MMAP_CANDO) == 0) 39355099Storek return (EINVAL); 39455099Storek if ((flags & SUN_MMAP_MASK) != MAP_SHARED && 39555099Storek (flags & SUN_MMAP_MASK) != MAP_PRIVATE) 39655099Storek return (EINVAL); 39755099Storek flags &= ~SUN_MMAP_CANDO; 39855099Storek 39955099Storek /* 40055099Storek * Special case: if fd refers to /dev/zero, map as MAP_ANON. (XXX) 40155099Storek */ 40255099Storek fdp = p->p_fd; 40355099Storek if ((unsigned)uap->fd < fdp->fd_nfiles && /*XXX*/ 40455099Storek (fp = fdp->fd_ofiles[uap->fd]) != NULL && /*XXX*/ 40555099Storek fp->f_type == DTYPE_VNODE && /*XXX*/ 40655099Storek (vp = (struct vnode *)fp->f_data)->v_type == VCHR && /*XXX*/ 40755099Storek vp->v_rdev == DEVZERO) { /*XXX*/ 40855099Storek flags |= MAP_ANON; 40955099Storek uap->fd = -1; 41055099Storek } 41155099Storek 41255099Storek /* All done, fix up fields and go. */ 41355099Storek uap->flags = flags; 41455099Storek uap->qoff = (quad_t)uap->off; 41555099Storek return (smmap(p, uap, retval)); 41655099Storek } 41755099Storek 41855099Storek #define MC_SYNC 1 41955099Storek #define MC_LOCK 2 42055099Storek #define MC_UNLOCK 3 42155099Storek #define MC_ADVISE 4 42255099Storek #define MC_LOCKAS 5 42355099Storek #define MC_UNLOCKAS 6 42455099Storek 42555099Storek struct sun_mctl_args { 42655099Storek caddr_t addr; 42755099Storek size_t len; 42855099Storek int func; 42955099Storek void *arg; 43055099Storek }; 43155099Storek sun_mctl(p, uap, retval) 43255099Storek register struct proc *p; 43355099Storek register struct sun_mctl_args *uap; 43455099Storek int *retval; 43555099Storek { 43655099Storek 43755099Storek switch (uap->func) { 43855099Storek 43955099Storek case MC_ADVISE: /* ignore for now */ 44055099Storek return (0); 44155099Storek 44255099Storek case MC_SYNC: /* translate to msync */ 44355099Storek return (msync(p, uap, retval)); 44455099Storek 44555099Storek default: 44655099Storek return (EINVAL); 44755099Storek } 44855099Storek } 44955099Storek 45055099Storek struct sun_setsockopt_args { 45155099Storek int s; 45255099Storek int level; 45355099Storek int name; 45455099Storek caddr_t val; 45555099Storek int valsize; 45655099Storek }; 45755099Storek sun_setsockopt(p, uap, retval) 45855099Storek struct proc *p; 45955099Storek register struct sun_setsockopt_args *uap; 46055099Storek int *retval; 46155099Storek { 46255099Storek struct file *fp; 46355099Storek struct mbuf *m = NULL; 46455099Storek int error; 46555099Storek 46655099Storek if (error = getsock(p->p_fd, uap->s, &fp)) 46755099Storek return (error); 46855099Storek #define SO_DONTLINGER (~SO_LINGER) 46955099Storek if (uap->name == SO_DONTLINGER) { 47055099Storek m = m_get(M_WAIT, MT_SOOPTS); 47155099Storek if (m == NULL) 47255099Storek return (ENOBUFS); 47355099Storek mtod(m, struct linger *)->l_onoff = 0; 47455099Storek m->m_len = sizeof(struct linger); 47555099Storek return (sosetopt((struct socket *)fp->f_data, uap->level, 47655099Storek SO_LINGER, m)); 47755099Storek } 47855099Storek if (uap->valsize > MLEN) 47955099Storek return (EINVAL); 48055099Storek if (uap->val) { 48155099Storek m = m_get(M_WAIT, MT_SOOPTS); 48255099Storek if (m == NULL) 48355099Storek return (ENOBUFS); 48455099Storek if (error = copyin(uap->val, mtod(m, caddr_t), 48555099Storek (u_int)uap->valsize)) { 48655099Storek (void) m_free(m); 48755099Storek return (error); 48855099Storek } 48955099Storek m->m_len = uap->valsize; 49055099Storek } 49155099Storek return (sosetopt((struct socket *)fp->f_data, uap->level, 49255099Storek uap->name, m)); 49355099Storek } 49455099Storek 49555099Storek struct sun_fchroot_args { 49655099Storek int fdes; 49755099Storek }; 49855099Storek sun_fchroot(p, uap, retval) 49955099Storek register struct proc *p; 50055099Storek register struct sun_fchroot_args *uap; 50155099Storek int *retval; 50255099Storek { 50355099Storek register struct filedesc *fdp = p->p_fd; 50455099Storek register struct vnode *vp; 50555099Storek struct file *fp; 50655099Storek int error; 50755099Storek 50855099Storek if ((error = suser(p->p_ucred, &p->p_acflag)) != 0) 50955099Storek return (error); 51055099Storek if ((error = getvnode(fdp, uap->fdes, &fp)) != 0) 51155099Storek return (error); 51255099Storek vp = (struct vnode *)fp->f_data; 51355099Storek VOP_LOCK(vp); 51455099Storek if (vp->v_type != VDIR) 51555099Storek error = ENOTDIR; 51655099Storek else 51755099Storek error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); 51855099Storek VOP_UNLOCK(vp); 51955099Storek if (error) 52055099Storek return (error); 52155099Storek VREF(vp); 52255099Storek if (fdp->fd_rdir != NULL) 52355099Storek vrele(fdp->fd_rdir); 52455099Storek fdp->fd_rdir = vp; 52555099Storek return (0); 52655099Storek } 527