svr4_fcntl.c revision 164033
1/*-
2 * Copyright (c) 1998 Mark Newton
3 * Copyright (c) 1994, 1997 Christos Zoulas.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 *    must display the following acknowledgement:
16 *	This product includes software developed by Christos Zoulas.
17 * 4. The name of the author may not be used to endorse or promote products
18 *    derived from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33__FBSDID("$FreeBSD: head/sys/compat/svr4/svr4_fcntl.c 164033 2006-11-06 13:42:10Z rwatson $");
34
35#include "opt_mac.h"
36
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/file.h>
40#include <sys/filedesc.h>
41/*#include <sys/ioctl.h>*/
42#include <sys/lock.h>
43#include <sys/malloc.h>
44#include <sys/mount.h>
45#include <sys/mutex.h>
46#include <sys/namei.h>
47#include <sys/priv.h>
48#include <sys/proc.h>
49#include <sys/stat.h>
50#include <sys/syscallsubr.h>
51#include <sys/unistd.h>
52#include <sys/vnode.h>
53
54#include <sys/sysproto.h>
55
56#include <compat/svr4/svr4.h>
57#include <compat/svr4/svr4_types.h>
58#include <compat/svr4/svr4_signal.h>
59#include <compat/svr4/svr4_proto.h>
60#include <compat/svr4/svr4_util.h>
61#include <compat/svr4/svr4_fcntl.h>
62
63#include <security/mac/mac_framework.h>
64
65static int svr4_to_bsd_flags(int);
66static u_long svr4_to_bsd_cmd(u_long);
67static int fd_revoke(struct thread *, int);
68static int fd_truncate(struct thread *, int, struct flock *);
69static int bsd_to_svr4_flags(int);
70static void bsd_to_svr4_flock(struct flock *, struct svr4_flock *);
71static void svr4_to_bsd_flock(struct svr4_flock *, struct flock *);
72static void bsd_to_svr4_flock64(struct flock *, struct svr4_flock64 *);
73static void svr4_to_bsd_flock64(struct svr4_flock64 *, struct flock *);
74
75static u_long
76svr4_to_bsd_cmd(cmd)
77	u_long	cmd;
78{
79	switch (cmd) {
80	case SVR4_F_DUPFD:
81		return F_DUPFD;
82	case SVR4_F_GETFD:
83		return F_GETFD;
84	case SVR4_F_SETFD:
85		return F_SETFD;
86	case SVR4_F_GETFL:
87		return F_GETFL;
88	case SVR4_F_SETFL:
89		return F_SETFL;
90	case SVR4_F_GETLK:
91		return F_GETLK;
92	case SVR4_F_SETLK:
93		return F_SETLK;
94	case SVR4_F_SETLKW:
95		return F_SETLKW;
96	default:
97		return -1;
98	}
99}
100
101static int
102svr4_to_bsd_flags(l)
103	int	l;
104{
105	int	r = 0;
106	r |= (l & SVR4_O_RDONLY) ? O_RDONLY : 0;
107	r |= (l & SVR4_O_WRONLY) ? O_WRONLY : 0;
108	r |= (l & SVR4_O_RDWR) ? O_RDWR : 0;
109	r |= (l & SVR4_O_NDELAY) ? O_NONBLOCK : 0;
110	r |= (l & SVR4_O_APPEND) ? O_APPEND : 0;
111	r |= (l & SVR4_O_SYNC) ? O_FSYNC : 0;
112	r |= (l & SVR4_O_NONBLOCK) ? O_NONBLOCK : 0;
113	r |= (l & SVR4_O_PRIV) ? O_EXLOCK : 0;
114	r |= (l & SVR4_O_CREAT) ? O_CREAT : 0;
115	r |= (l & SVR4_O_TRUNC) ? O_TRUNC : 0;
116	r |= (l & SVR4_O_EXCL) ? O_EXCL : 0;
117	r |= (l & SVR4_O_NOCTTY) ? O_NOCTTY : 0;
118	return r;
119}
120
121static int
122bsd_to_svr4_flags(l)
123	int	l;
124{
125	int	r = 0;
126	r |= (l & O_RDONLY) ? SVR4_O_RDONLY : 0;
127	r |= (l & O_WRONLY) ? SVR4_O_WRONLY : 0;
128	r |= (l & O_RDWR) ? SVR4_O_RDWR : 0;
129	r |= (l & O_NDELAY) ? SVR4_O_NONBLOCK : 0;
130	r |= (l & O_APPEND) ? SVR4_O_APPEND : 0;
131	r |= (l & O_FSYNC) ? SVR4_O_SYNC : 0;
132	r |= (l & O_NONBLOCK) ? SVR4_O_NONBLOCK : 0;
133	r |= (l & O_EXLOCK) ? SVR4_O_PRIV : 0;
134	r |= (l & O_CREAT) ? SVR4_O_CREAT : 0;
135	r |= (l & O_TRUNC) ? SVR4_O_TRUNC : 0;
136	r |= (l & O_EXCL) ? SVR4_O_EXCL : 0;
137	r |= (l & O_NOCTTY) ? SVR4_O_NOCTTY : 0;
138	return r;
139}
140
141
142static void
143bsd_to_svr4_flock(iflp, oflp)
144	struct flock		*iflp;
145	struct svr4_flock	*oflp;
146{
147	switch (iflp->l_type) {
148	case F_RDLCK:
149		oflp->l_type = SVR4_F_RDLCK;
150		break;
151	case F_WRLCK:
152		oflp->l_type = SVR4_F_WRLCK;
153		break;
154	case F_UNLCK:
155		oflp->l_type = SVR4_F_UNLCK;
156		break;
157	default:
158		oflp->l_type = -1;
159		break;
160	}
161
162	oflp->l_whence = (short) iflp->l_whence;
163	oflp->l_start = (svr4_off_t) iflp->l_start;
164	oflp->l_len = (svr4_off_t) iflp->l_len;
165	oflp->l_sysid = 0;
166	oflp->l_pid = (svr4_pid_t) iflp->l_pid;
167}
168
169
170static void
171svr4_to_bsd_flock(iflp, oflp)
172	struct svr4_flock	*iflp;
173	struct flock		*oflp;
174{
175	switch (iflp->l_type) {
176	case SVR4_F_RDLCK:
177		oflp->l_type = F_RDLCK;
178		break;
179	case SVR4_F_WRLCK:
180		oflp->l_type = F_WRLCK;
181		break;
182	case SVR4_F_UNLCK:
183		oflp->l_type = F_UNLCK;
184		break;
185	default:
186		oflp->l_type = -1;
187		break;
188	}
189
190	oflp->l_whence = iflp->l_whence;
191	oflp->l_start = (off_t) iflp->l_start;
192	oflp->l_len = (off_t) iflp->l_len;
193	oflp->l_pid = (pid_t) iflp->l_pid;
194
195}
196
197static void
198bsd_to_svr4_flock64(iflp, oflp)
199	struct flock		*iflp;
200	struct svr4_flock64	*oflp;
201{
202	switch (iflp->l_type) {
203	case F_RDLCK:
204		oflp->l_type = SVR4_F_RDLCK;
205		break;
206	case F_WRLCK:
207		oflp->l_type = SVR4_F_WRLCK;
208		break;
209	case F_UNLCK:
210		oflp->l_type = SVR4_F_UNLCK;
211		break;
212	default:
213		oflp->l_type = -1;
214		break;
215	}
216
217	oflp->l_whence = (short) iflp->l_whence;
218	oflp->l_start = (svr4_off64_t) iflp->l_start;
219	oflp->l_len = (svr4_off64_t) iflp->l_len;
220	oflp->l_sysid = 0;
221	oflp->l_pid = (svr4_pid_t) iflp->l_pid;
222}
223
224
225static void
226svr4_to_bsd_flock64(iflp, oflp)
227	struct svr4_flock64	*iflp;
228	struct flock		*oflp;
229{
230	switch (iflp->l_type) {
231	case SVR4_F_RDLCK:
232		oflp->l_type = F_RDLCK;
233		break;
234	case SVR4_F_WRLCK:
235		oflp->l_type = F_WRLCK;
236		break;
237	case SVR4_F_UNLCK:
238		oflp->l_type = F_UNLCK;
239		break;
240	default:
241		oflp->l_type = -1;
242		break;
243	}
244
245	oflp->l_whence = iflp->l_whence;
246	oflp->l_start = (off_t) iflp->l_start;
247	oflp->l_len = (off_t) iflp->l_len;
248	oflp->l_pid = (pid_t) iflp->l_pid;
249
250}
251
252
253static int
254fd_revoke(td, fd)
255	struct thread *td;
256	int fd;
257{
258	struct vnode *vp;
259	struct mount *mp;
260	struct vattr vattr;
261	int error, *retval;
262
263	retval = td->td_retval;
264	if ((error = fgetvp(td, fd, &vp)) != 0)
265		return (error);
266
267	if (vp->v_type != VCHR && vp->v_type != VBLK) {
268		error = EINVAL;
269		goto out;
270	}
271
272#ifdef MAC
273	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
274	error = mac_check_vnode_revoke(td->td_ucred, vp);
275	VOP_UNLOCK(vp, 0, td);
276	if (error)
277		goto out;
278#endif
279
280	if ((error = VOP_GETATTR(vp, &vattr, td->td_ucred, td)) != 0)
281		goto out;
282
283	if (td->td_ucred->cr_uid != vattr.va_uid &&
284	    (error = priv_check_cred(td->td_ucred, PRIV_VFS_ADMIN,
285	    SUSER_ALLOWJAIL)) != 0)
286		goto out;
287
288	if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
289		goto out;
290	if (vcount(vp) > 1)
291		VOP_REVOKE(vp, REVOKEALL);
292	vn_finished_write(mp);
293out:
294	vrele(vp);
295	return error;
296}
297
298
299static int
300fd_truncate(td, fd, flp)
301	struct thread *td;
302	int fd;
303	struct flock *flp;
304{
305	off_t start, length;
306	struct file *fp;
307	struct vnode *vp;
308	struct vattr vattr;
309	int error, *retval;
310	struct ftruncate_args ft;
311
312	retval = td->td_retval;
313
314	/*
315	 * We only support truncating the file.
316	 */
317	if ((error = fget(td, fd, &fp)) != 0)
318		return (error);
319
320	vp = fp->f_vnode;
321
322	if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
323		fdrop(fp, td);
324		return ESPIPE;
325	}
326
327	if ((error = VOP_GETATTR(vp, &vattr, td->td_ucred, td)) != 0) {
328		fdrop(fp, td);
329		return error;
330	}
331
332	length = vattr.va_size;
333
334	switch (flp->l_whence) {
335	case SEEK_CUR:
336		start = fp->f_offset + flp->l_start;
337		break;
338
339	case SEEK_END:
340		start = flp->l_start + length;
341		break;
342
343	case SEEK_SET:
344		start = flp->l_start;
345		break;
346
347	default:
348		fdrop(fp, td);
349		return EINVAL;
350	}
351
352	if (start + flp->l_len < length) {
353		/* We don't support free'ing in the middle of the file */
354		fdrop(fp, td);
355		return EINVAL;
356	}
357
358	ft.fd = fd;
359	ft.length = start;
360
361	error = ftruncate(td, &ft);
362
363	fdrop(fp, td);
364	return (error);
365}
366
367int
368svr4_sys_open(td, uap)
369	register struct thread *td;
370	struct svr4_sys_open_args *uap;
371{
372	struct proc *p = td->td_proc;
373	char *newpath;
374	int bsd_flags, error, retval;
375
376	CHECKALTEXIST(td, uap->path, &newpath);
377
378	bsd_flags = svr4_to_bsd_flags(uap->flags);
379	error = kern_open(td, newpath, UIO_SYSSPACE, bsd_flags, uap->mode);
380	free(newpath, M_TEMP);
381
382	if (error) {
383	  /*	        uprintf("svr4_open(%s, 0x%0x, 0%o): %d\n", uap->path,
384			uap->flags, uap->mode, error);*/
385		return error;
386	}
387
388	retval = td->td_retval[0];
389
390	PROC_LOCK(p);
391	if (!(bsd_flags & O_NOCTTY) && SESS_LEADER(p) &&
392	    !(p->p_flag & P_CONTROLT)) {
393#if defined(NOTYET)
394		struct file	*fp;
395
396		error = fget(td, retval, &fp);
397		PROC_UNLOCK(p);
398		/*
399		 * we may have lost a race the above open() and
400		 * another thread issuing a close()
401		 */
402		if (error)
403			return (EBADF);	/* XXX: correct errno? */
404		/* ignore any error, just give it a try */
405		if (fp->f_type == DTYPE_VNODE)
406			fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0, td->td_ucred,
407			    td);
408		fdrop(fp, td);
409	} else {
410		PROC_UNLOCK(p);
411	}
412#else
413	}
414	PROC_UNLOCK(p);
415#endif
416	return error;
417}
418
419int
420svr4_sys_open64(td, uap)
421	register struct thread *td;
422	struct svr4_sys_open64_args *uap;
423{
424	return svr4_sys_open(td, (struct svr4_sys_open_args *)uap);
425}
426
427int
428svr4_sys_creat(td, uap)
429	register struct thread *td;
430	struct svr4_sys_creat_args *uap;
431{
432	char *newpath;
433	int error;
434
435	CHECKALTEXIST(td, uap->path, &newpath);
436
437	error = kern_open(td, newpath, UIO_SYSSPACE, O_WRONLY | O_CREAT |
438	    O_TRUNC, uap->mode);
439	free(newpath, M_TEMP);
440	return (error);
441}
442
443int
444svr4_sys_creat64(td, uap)
445	register struct thread *td;
446	struct svr4_sys_creat64_args *uap;
447{
448	return svr4_sys_creat(td, (struct svr4_sys_creat_args *)uap);
449}
450
451int
452svr4_sys_llseek(td, uap)
453	register struct thread *td;
454	struct svr4_sys_llseek_args *uap;
455{
456	struct lseek_args ap;
457
458	ap.fd = uap->fd;
459
460#if BYTE_ORDER == BIG_ENDIAN
461	ap.offset = (((u_int64_t) uap->offset1) << 32) |
462		uap->offset2;
463#else
464	ap.offset = (((u_int64_t) uap->offset2) << 32) |
465		uap->offset1;
466#endif
467	ap.whence = uap->whence;
468
469	return lseek(td, &ap);
470}
471
472int
473svr4_sys_access(td, uap)
474	register struct thread *td;
475	struct svr4_sys_access_args *uap;
476{
477	char *newpath;
478	int error;
479
480	CHECKALTEXIST(td, uap->path, &newpath);
481	error = kern_access(td, newpath, UIO_SYSSPACE, uap->flags);
482	free(newpath, M_TEMP);
483	return (error);
484}
485
486#if defined(NOTYET)
487int
488svr4_sys_pread(td, uap)
489	register struct thread *td;
490	struct svr4_sys_pread_args *uap;
491{
492	struct pread_args pra;
493
494	/*
495	 * Just translate the args structure and call the NetBSD
496	 * pread(2) system call (offset type is 64-bit in NetBSD).
497	 */
498	pra.fd = uap->fd;
499	pra.buf = uap->buf;
500	pra.nbyte = uap->nbyte;
501	pra.offset = uap->off;
502
503	return pread(td, &pra);
504}
505#endif
506
507#if defined(NOTYET)
508int
509svr4_sys_pread64(td, v, retval)
510	register struct thread *td;
511	void *v;
512	register_t *retval;
513{
514
515	struct svr4_sys_pread64_args *uap = v;
516	struct sys_pread_args pra;
517
518	/*
519	 * Just translate the args structure and call the NetBSD
520	 * pread(2) system call (offset type is 64-bit in NetBSD).
521	 */
522	pra.fd = uap->fd;
523	pra.buf = uap->buf;
524	pra.nbyte = uap->nbyte;
525	pra.offset = uap->off;
526
527	return (sys_pread(td, &pra, retval));
528}
529#endif /* NOTYET */
530
531#if defined(NOTYET)
532int
533svr4_sys_pwrite(td, uap)
534	register struct thread *td;
535	struct svr4_sys_pwrite_args *uap;
536{
537	struct pwrite_args pwa;
538
539	/*
540	 * Just translate the args structure and call the NetBSD
541	 * pwrite(2) system call (offset type is 64-bit in NetBSD).
542	 */
543	pwa.fd = uap->fd;
544	pwa.buf = uap->buf;
545	pwa.nbyte = uap->nbyte;
546	pwa.offset = uap->off;
547
548	return pwrite(td, &pwa);
549}
550#endif
551
552#if defined(NOTYET)
553int
554svr4_sys_pwrite64(td, v, retval)
555	register struct thread *td;
556	void *v;
557	register_t *retval;
558{
559	struct svr4_sys_pwrite64_args *uap = v;
560	struct sys_pwrite_args pwa;
561
562	/*
563	 * Just translate the args structure and call the NetBSD
564	 * pwrite(2) system call (offset type is 64-bit in NetBSD).
565	 */
566	pwa.fd = uap->fd;
567	pwa.buf = uap->buf;
568	pwa.nbyte = uap->nbyte;
569	pwa.offset = uap->off;
570
571	return (sys_pwrite(td, &pwa, retval));
572}
573#endif /* NOTYET */
574
575int
576svr4_sys_fcntl(td, uap)
577	register struct thread *td;
578	struct svr4_sys_fcntl_args *uap;
579{
580	int cmd, error, *retval;
581
582	retval = td->td_retval;
583
584	cmd = svr4_to_bsd_cmd(uap->cmd);
585
586	switch (cmd) {
587	case F_DUPFD:
588	case F_GETFD:
589	case F_SETFD:
590		return (kern_fcntl(td, uap->fd, cmd, (intptr_t)uap->arg));
591
592	case F_GETFL:
593		error = kern_fcntl(td, uap->fd, cmd, (intptr_t)uap->arg);
594		if (error)
595			return (error);
596		*retval = bsd_to_svr4_flags(*retval);
597		return (error);
598
599	case F_SETFL:
600		{
601			/*
602			 * we must save the O_ASYNC flag, as that is
603			 * handled by ioctl(_, I_SETSIG, _) emulation.
604			 */
605			int flags;
606
607			DPRINTF(("Setting flags %p\n", uap->arg));
608
609			error = kern_fcntl(td, uap->fd, F_GETFL, 0);
610			if (error)
611				return (error);
612			flags = *retval;
613			flags &= O_ASYNC;
614			flags |= svr4_to_bsd_flags((u_long) uap->arg);
615			return (kern_fcntl(td, uap->fd, F_SETFL, flags));
616		}
617
618	case F_GETLK:
619	case F_SETLK:
620	case F_SETLKW:
621		{
622			struct svr4_flock	ifl;
623			struct flock		fl;
624
625			error = copyin(uap->arg, &ifl, sizeof (ifl));
626			if (error)
627				return (error);
628
629			svr4_to_bsd_flock(&ifl, &fl);
630
631			error = kern_fcntl(td, uap->fd, cmd, (intptr_t)&fl);
632			if (error || cmd != F_GETLK)
633				return (error);
634
635			bsd_to_svr4_flock(&fl, &ifl);
636
637			return (copyout(&ifl, uap->arg, sizeof (ifl)));
638		}
639	case -1:
640		switch (uap->cmd) {
641		case SVR4_F_DUP2FD:
642			{
643				struct dup2_args du;
644
645				du.from = uap->fd;
646				du.to = (int)uap->arg;
647				error = dup2(td, &du);
648				if (error)
649					return error;
650				*retval = du.to;
651				return 0;
652			}
653
654		case SVR4_F_FREESP:
655			{
656				struct svr4_flock	 ifl;
657				struct flock		 fl;
658
659				error = copyin(uap->arg, &ifl,
660				    sizeof ifl);
661				if (error)
662					return error;
663				svr4_to_bsd_flock(&ifl, &fl);
664				return fd_truncate(td, uap->fd, &fl);
665			}
666
667		case SVR4_F_GETLK64:
668		case SVR4_F_SETLK64:
669		case SVR4_F_SETLKW64:
670			{
671				struct svr4_flock64	ifl;
672				struct flock		fl;
673
674				switch (uap->cmd) {
675				case SVR4_F_GETLK64:
676					cmd = F_GETLK;
677					break;
678				case SVR4_F_SETLK64:
679					cmd = F_SETLK;
680					break;
681				case SVR4_F_SETLKW64:
682					cmd = F_SETLKW;
683					break;
684				}
685				error = copyin(uap->arg, &ifl,
686				    sizeof (ifl));
687				if (error)
688					return (error);
689
690				svr4_to_bsd_flock64(&ifl, &fl);
691
692				error = kern_fcntl(td, uap->fd, cmd,
693				    (intptr_t)&fl);
694				if (error || cmd != F_GETLK)
695					return (error);
696
697				bsd_to_svr4_flock64(&fl, &ifl);
698
699				return (copyout(&ifl, uap->arg,
700				    sizeof (ifl)));
701			}
702
703		case SVR4_F_FREESP64:
704			{
705				struct svr4_flock64	 ifl;
706				struct flock		 fl;
707
708				error = copyin(uap->arg, &ifl,
709				    sizeof ifl);
710				if (error)
711					return error;
712				svr4_to_bsd_flock64(&ifl, &fl);
713				return fd_truncate(td, uap->fd, &fl);
714			}
715
716		case SVR4_F_REVOKE:
717			return fd_revoke(td, uap->fd);
718
719		default:
720			return ENOSYS;
721		}
722
723	default:
724		return ENOSYS;
725	}
726}
727