155099Storek /*
263555Sbostic * Copyright (c) 1992, 1993
363555Sbostic * The Regents of the University of California. 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
1258995Storek * California, Lawrence Berkeley Laboratory.
1355505Sbostic *
1455099Storek * %sccs.include.redist.c%
1555099Storek *
16*69449Smckusick * @(#)sun_misc.c 8.5 (Berkeley) 05/14/95
1755099Storek *
1858995Storek * 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>
2958995Storek #include <sys/systm.h>
3058995Storek #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
13158995Storek uap->flags = 0;
13255099Storek return (unmount(p, uap, retval));
13355099Storek }
13455099Storek
13555099Storek static int
gettype(tptr)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)
14568714Smckusick type = 1; /* old MOUNT_UFS */
14655099Storek else if (strcmp(in, "nfs") == 0)
14768714Smckusick type = 2; /* old 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 {
19964635Sbostic int mask;
20055099Storek
20164635Sbostic mask = p->p_siglist & p->p_sigmask;
20264635Sbostic return (copyout(&mask, uap->mask, sizeof(int)));
20355099Storek }
20455099Storek
20558995Storek /*
20658995Storek * Here is the sun layout. (Compare the BSD layout in <sys/dirent.h>.)
20758995Storek * We can assume big-endian, so the BSD d_type field is just the high
20858995Storek * byte of the SunOS d_namlen field, after adjusting for the extra "long".
20958995Storek */
21055099Storek struct sun_dirent {
21155099Storek long d_off;
21255099Storek u_long d_fileno;
21355099Storek u_short d_reclen;
21455099Storek u_short d_namlen;
21555099Storek char d_name[256];
21655099Storek };
21755099Storek
21855099Storek /*
21955099Storek * Read Sun-style directory entries. We suck them into kernel space so
22055099Storek * that they can be massaged before being copied out to user code. Like
22155099Storek * SunOS, we squish out `empty' entries.
22255099Storek *
22355099Storek * This is quite ugly, but what do you expect from compatibility code?
22455099Storek */
22555099Storek struct sun_getdents_args {
22655099Storek int fd;
22755099Storek char *buf;
22855099Storek int nbytes;
22955099Storek };
23055099Storek sun_getdents(p, uap, retval)
23155099Storek struct proc *p;
23255099Storek register struct sun_getdents_args *uap;
23355099Storek int *retval;
23455099Storek {
23555099Storek register struct vnode *vp;
23655099Storek register caddr_t inp, buf; /* BSD-format */
23755099Storek register int len, reclen; /* BSD-format */
23855099Storek register caddr_t outp; /* Sun-format */
23955099Storek register int resid; /* Sun-format */
24055099Storek struct file *fp;
24155099Storek struct uio auio;
24255099Storek struct iovec aiov;
24355099Storek off_t off; /* true file offset */
24455099Storek long soff; /* Sun file offset */
24555099Storek int buflen, error, eofflag;
24658995Storek #define BSD_DIRENT(cp) ((struct dirent *)(cp))
24755099Storek #define SUN_RECLEN(reclen) (reclen + sizeof(long))
24855099Storek
24955099Storek if ((error = getvnode(p->p_fd, uap->fd, &fp)) != 0)
25055099Storek return (error);
25155099Storek if ((fp->f_flag & FREAD) == 0)
25255099Storek return (EBADF);
25355099Storek vp = (struct vnode *)fp->f_data;
25455099Storek if (vp->v_type != VDIR) /* XXX vnode readdir op should do this */
25555099Storek return (EINVAL);
25655099Storek buflen = min(MAXBSIZE, uap->nbytes);
25755099Storek buf = malloc(buflen, M_TEMP, M_WAITOK);
258*69449Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p)
25955099Storek off = fp->f_offset;
26055099Storek again:
26155099Storek aiov.iov_base = buf;
26255099Storek aiov.iov_len = buflen;
26355099Storek auio.uio_iov = &aiov;
26455099Storek auio.uio_iovcnt = 1;
26555099Storek auio.uio_rw = UIO_READ;
26655099Storek auio.uio_segflg = UIO_SYSSPACE;
26755099Storek auio.uio_procp = p;
26855099Storek auio.uio_resid = buflen;
26955099Storek auio.uio_offset = off;
27055099Storek /*
27155099Storek * First we read into the malloc'ed buffer, then
27255099Storek * we massage it into user space, one record at a time.
27355099Storek */
27467372Smckusick if (error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, (u_long *)0,0))
27555099Storek goto out;
27655099Storek inp = buf;
27755099Storek outp = uap->buf;
27855099Storek resid = uap->nbytes;
27955099Storek if ((len = buflen - auio.uio_resid) == 0)
28055099Storek goto eof;
28155099Storek for (; len > 0; len -= reclen) {
28258995Storek reclen = ((struct dirent *)inp)->d_reclen;
28355099Storek if (reclen & 3)
28455099Storek panic("sun_getdents");
28555099Storek off += reclen; /* each entry points to next */
28658995Storek if (BSD_DIRENT(inp)->d_fileno == 0) {
28755099Storek inp += reclen; /* it is a hole; squish it out */
28855099Storek continue;
28955099Storek }
29055099Storek if (reclen > len || resid < SUN_RECLEN(reclen)) {
29155099Storek /* entry too big for buffer, so just stop */
29255099Storek outp++;
29355099Storek break;
29455099Storek }
29558995Storek /*
29658995Storek * Massage in place to make a Sun-shaped dirent (otherwise
29758995Storek * we have to worry about touching user memory outside of
29858995Storek * the copyout() call).
29958995Storek */
30058995Storek BSD_DIRENT(inp)->d_reclen = SUN_RECLEN(reclen);
30158995Storek BSD_DIRENT(inp)->d_type = 0;
30255099Storek soff = off;
30355099Storek if ((error = copyout((caddr_t)&soff, outp, sizeof soff)) != 0 ||
30455099Storek (error = copyout(inp, outp + sizeof soff, reclen)) != 0)
30555099Storek goto out;
30655099Storek /* advance past this real entry */
30755099Storek inp += reclen;
30855099Storek /* advance output past Sun-shaped entry */
30955099Storek outp += SUN_RECLEN(reclen);
31055099Storek resid -= SUN_RECLEN(reclen);
31155099Storek }
31255099Storek /* if we squished out the whole block, try again */
31355099Storek if (outp == uap->buf)
31455099Storek goto again;
31555099Storek fp->f_offset = off; /* update the vnode offset */
31655099Storek eof:
31755099Storek *retval = uap->nbytes - resid;
31855099Storek out:
319*69449Smckusick VOP_UNLOCK(vp, 0, p);
32055099Storek free(buf, M_TEMP);
32155099Storek return (error);
32255099Storek }
32355099Storek
32455099Storek #define MAXDOMAINNAME 64
32555099Storek char sun_domainname[MAXDOMAINNAME];
32655099Storek int sun_domainnamelen = 1;
32755099Storek
32855099Storek struct sun_getdomainname_args {
32955099Storek char *name;
33055099Storek int namelen;
33155099Storek };
33255099Storek sun_getdomainname(p, uap, retval)
33355099Storek struct proc *p;
33455099Storek struct sun_getdomainname_args *uap;
33555099Storek int *retval;
33655099Storek {
33755099Storek register int l = min(uap->namelen, sun_domainnamelen + 1);
33855099Storek
33955099Storek return (copyout(sun_domainname, uap->name, l));
34055099Storek }
34155099Storek
34255099Storek struct sun_setdomainname_args {
34355099Storek char *name;
34455099Storek int namelen;
34555099Storek };
34655099Storek sun_setdomainname(p, uap, retval)
34755099Storek struct proc *p;
34855099Storek struct sun_setdomainname_args *uap;
34955099Storek int *retval;
35055099Storek {
35155099Storek register int l = uap->namelen, error;
35255099Storek
35355099Storek if (l >= MAXDOMAINNAME)
35455099Storek return (EINVAL); /* ??? ENAMETOOLONG? */
35555099Storek if (error = suser(p->p_ucred, &p->p_acflag))
35655099Storek return (error);
35755099Storek if (error = copyin(uap->name, sun_domainname, l))
35855099Storek return (error);
35955099Storek sun_domainname[l] = 0;
36055099Storek return (0);
36155099Storek }
36255099Storek
36355099Storek #define SUN_MMAP_MASK 0xf /* mask for SHARED/PRIVATE */
36455099Storek #define SUN_MMAP_CANDO 0x80000000 /* if not, old mmap & cannot handle */
36555099Storek
36655099Storek #define DEVZERO makedev(3, 12) /* major,minor of /dev/zero */
36755099Storek
36855099Storek #define SUN_MMAP_SAME (MAP_SHARED|MAP_PRIVATE|MAP_FIXED|MAP_INHERIT)
36955099Storek
37055099Storek struct sun_mmap_args {
37155099Storek caddr_t addr;
37255099Storek size_t len;
37355099Storek int prot;
37455099Storek int flags;
37555099Storek int fd;
37655099Storek long off; /* not off_t! */
37763554Smckusick quad_t qoff; /* created here and fed to mmap() */
37855099Storek };
sun_mmap(p,uap,retval)37955099Storek sun_mmap(p, uap, retval)
38055099Storek register struct proc *p;
38155099Storek register struct sun_mmap_args *uap;
38255099Storek int *retval;
38355099Storek {
38455099Storek register int flags;
38555099Storek register struct filedesc *fdp;
38655099Storek register struct file *fp;
38755099Storek register struct vnode *vp;
38855099Storek
38955099Storek /*
39055099Storek * Verify the arguments.
39155099Storek */
39255099Storek flags = uap->flags;
39355099Storek if ((flags & SUN_MMAP_CANDO) == 0)
39455099Storek return (EINVAL);
39555099Storek if ((flags & SUN_MMAP_MASK) != MAP_SHARED &&
39655099Storek (flags & SUN_MMAP_MASK) != MAP_PRIVATE)
39755099Storek return (EINVAL);
39855099Storek flags &= ~SUN_MMAP_CANDO;
39955099Storek
40055099Storek /*
40155099Storek * Special case: if fd refers to /dev/zero, map as MAP_ANON. (XXX)
40255099Storek */
40355099Storek fdp = p->p_fd;
40455099Storek if ((unsigned)uap->fd < fdp->fd_nfiles && /*XXX*/
40555099Storek (fp = fdp->fd_ofiles[uap->fd]) != NULL && /*XXX*/
40655099Storek fp->f_type == DTYPE_VNODE && /*XXX*/
40755099Storek (vp = (struct vnode *)fp->f_data)->v_type == VCHR && /*XXX*/
40855099Storek vp->v_rdev == DEVZERO) { /*XXX*/
40955099Storek flags |= MAP_ANON;
41055099Storek uap->fd = -1;
41155099Storek }
41255099Storek
41355099Storek /* All done, fix up fields and go. */
41455099Storek uap->flags = flags;
41555099Storek uap->qoff = (quad_t)uap->off;
41663554Smckusick return (mmap(p, uap, retval));
41755099Storek }
41855099Storek
41955099Storek #define MC_SYNC 1
42055099Storek #define MC_LOCK 2
42155099Storek #define MC_UNLOCK 3
42255099Storek #define MC_ADVISE 4
42355099Storek #define MC_LOCKAS 5
42455099Storek #define MC_UNLOCKAS 6
42555099Storek
42655099Storek struct sun_mctl_args {
42755099Storek caddr_t addr;
42855099Storek size_t len;
42955099Storek int func;
43055099Storek void *arg;
43155099Storek };
sun_mctl(p,uap,retval)43255099Storek sun_mctl(p, uap, retval)
43355099Storek register struct proc *p;
43455099Storek register struct sun_mctl_args *uap;
43555099Storek int *retval;
43655099Storek {
43755099Storek
43855099Storek switch (uap->func) {
43955099Storek
44055099Storek case MC_ADVISE: /* ignore for now */
44155099Storek return (0);
44255099Storek
44355099Storek case MC_SYNC: /* translate to msync */
44455099Storek return (msync(p, uap, retval));
44555099Storek
44655099Storek default:
44755099Storek return (EINVAL);
44855099Storek }
44955099Storek }
45055099Storek
45155099Storek struct sun_setsockopt_args {
45255099Storek int s;
45355099Storek int level;
45455099Storek int name;
45555099Storek caddr_t val;
45655099Storek int valsize;
45755099Storek };
45855099Storek sun_setsockopt(p, uap, retval)
45955099Storek struct proc *p;
46055099Storek register struct sun_setsockopt_args *uap;
46155099Storek int *retval;
46255099Storek {
46355099Storek struct file *fp;
46455099Storek struct mbuf *m = NULL;
46555099Storek int error;
46655099Storek
46755099Storek if (error = getsock(p->p_fd, uap->s, &fp))
46855099Storek return (error);
46955099Storek #define SO_DONTLINGER (~SO_LINGER)
47055099Storek if (uap->name == SO_DONTLINGER) {
47155099Storek m = m_get(M_WAIT, MT_SOOPTS);
47255099Storek if (m == NULL)
47355099Storek return (ENOBUFS);
47455099Storek mtod(m, struct linger *)->l_onoff = 0;
47555099Storek m->m_len = sizeof(struct linger);
47655099Storek return (sosetopt((struct socket *)fp->f_data, uap->level,
47755099Storek SO_LINGER, m));
47855099Storek }
47955099Storek if (uap->valsize > MLEN)
48055099Storek return (EINVAL);
48155099Storek if (uap->val) {
48255099Storek m = m_get(M_WAIT, MT_SOOPTS);
48355099Storek if (m == NULL)
48455099Storek return (ENOBUFS);
48555099Storek if (error = copyin(uap->val, mtod(m, caddr_t),
48655099Storek (u_int)uap->valsize)) {
48755099Storek (void) m_free(m);
48855099Storek return (error);
48955099Storek }
49055099Storek m->m_len = uap->valsize;
49155099Storek }
49255099Storek return (sosetopt((struct socket *)fp->f_data, uap->level,
49355099Storek uap->name, m));
49455099Storek }
49555099Storek
49655099Storek struct sun_fchroot_args {
49755099Storek int fdes;
49855099Storek };
sun_fchroot(p,uap,retval)49955099Storek sun_fchroot(p, uap, retval)
50055099Storek register struct proc *p;
50155099Storek register struct sun_fchroot_args *uap;
50255099Storek int *retval;
50355099Storek {
50455099Storek register struct filedesc *fdp = p->p_fd;
50555099Storek register struct vnode *vp;
50655099Storek struct file *fp;
50755099Storek int error;
50855099Storek
50955099Storek if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
51055099Storek return (error);
51155099Storek if ((error = getvnode(fdp, uap->fdes, &fp)) != 0)
51255099Storek return (error);
51355099Storek vp = (struct vnode *)fp->f_data;
514*69449Smckusick vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p)
51555099Storek if (vp->v_type != VDIR)
51655099Storek error = ENOTDIR;
51755099Storek else
51855099Storek error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p);
519*69449Smckusick VOP_UNLOCK(vp, 0, p);
52055099Storek if (error)
52155099Storek return (error);
52255099Storek VREF(vp);
52355099Storek if (fdp->fd_rdir != NULL)
52455099Storek vrele(fdp->fd_rdir);
52555099Storek fdp->fd_rdir = vp;
52655099Storek return (0);
52755099Storek }
528