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