svr4_fcntl.c revision 172930
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 172930 2007-10-24 19:04:04Z 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_vnode_check_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(td, PRIV_VFS_ADMIN)) != 0)
285		goto out;
286
287	if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
288		goto out;
289	if (vcount(vp) > 1)
290		VOP_REVOKE(vp, REVOKEALL);
291	vn_finished_write(mp);
292out:
293	vrele(vp);
294	return error;
295}
296
297
298static int
299fd_truncate(td, fd, flp)
300	struct thread *td;
301	int fd;
302	struct flock *flp;
303{
304	off_t start, length;
305	struct file *fp;
306	struct vnode *vp;
307	struct vattr vattr;
308	int error, *retval;
309	struct ftruncate_args ft;
310
311	retval = td->td_retval;
312
313	/*
314	 * We only support truncating the file.
315	 */
316	if ((error = fget(td, fd, &fp)) != 0)
317		return (error);
318
319	vp = fp->f_vnode;
320
321	if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
322		fdrop(fp, td);
323		return ESPIPE;
324	}
325
326	if ((error = VOP_GETATTR(vp, &vattr, td->td_ucred, td)) != 0) {
327		fdrop(fp, td);
328		return error;
329	}
330
331	length = vattr.va_size;
332
333	switch (flp->l_whence) {
334	case SEEK_CUR:
335		start = fp->f_offset + flp->l_start;
336		break;
337
338	case SEEK_END:
339		start = flp->l_start + length;
340		break;
341
342	case SEEK_SET:
343		start = flp->l_start;
344		break;
345
346	default:
347		fdrop(fp, td);
348		return EINVAL;
349	}
350
351	if (start + flp->l_len < length) {
352		/* We don't support free'ing in the middle of the file */
353		fdrop(fp, td);
354		return EINVAL;
355	}
356
357	ft.fd = fd;
358	ft.length = start;
359
360	error = ftruncate(td, &ft);
361
362	fdrop(fp, td);
363	return (error);
364}
365
366int
367svr4_sys_open(td, uap)
368	register struct thread *td;
369	struct svr4_sys_open_args *uap;
370{
371	struct proc *p = td->td_proc;
372	char *newpath;
373	int bsd_flags, error, retval;
374
375	CHECKALTEXIST(td, uap->path, &newpath);
376
377	bsd_flags = svr4_to_bsd_flags(uap->flags);
378	error = kern_open(td, newpath, UIO_SYSSPACE, bsd_flags, uap->mode);
379	free(newpath, M_TEMP);
380
381	if (error) {
382	  /*	        uprintf("svr4_open(%s, 0x%0x, 0%o): %d\n", uap->path,
383			uap->flags, uap->mode, error);*/
384		return error;
385	}
386
387	retval = td->td_retval[0];
388
389	PROC_LOCK(p);
390	if (!(bsd_flags & O_NOCTTY) && SESS_LEADER(p) &&
391	    !(p->p_flag & P_CONTROLT)) {
392#if defined(NOTYET)
393		struct file	*fp;
394
395		error = fget(td, retval, &fp);
396		PROC_UNLOCK(p);
397		/*
398		 * we may have lost a race the above open() and
399		 * another thread issuing a close()
400		 */
401		if (error)
402			return (EBADF);	/* XXX: correct errno? */
403		/* ignore any error, just give it a try */
404		if (fp->f_type == DTYPE_VNODE)
405			fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0, td->td_ucred,
406			    td);
407		fdrop(fp, td);
408	} else {
409		PROC_UNLOCK(p);
410	}
411#else
412	}
413	PROC_UNLOCK(p);
414#endif
415	return error;
416}
417
418int
419svr4_sys_open64(td, uap)
420	register struct thread *td;
421	struct svr4_sys_open64_args *uap;
422{
423	return svr4_sys_open(td, (struct svr4_sys_open_args *)uap);
424}
425
426int
427svr4_sys_creat(td, uap)
428	register struct thread *td;
429	struct svr4_sys_creat_args *uap;
430{
431	char *newpath;
432	int error;
433
434	CHECKALTEXIST(td, uap->path, &newpath);
435
436	error = kern_open(td, newpath, UIO_SYSSPACE, O_WRONLY | O_CREAT |
437	    O_TRUNC, uap->mode);
438	free(newpath, M_TEMP);
439	return (error);
440}
441
442int
443svr4_sys_creat64(td, uap)
444	register struct thread *td;
445	struct svr4_sys_creat64_args *uap;
446{
447	return svr4_sys_creat(td, (struct svr4_sys_creat_args *)uap);
448}
449
450int
451svr4_sys_llseek(td, uap)
452	register struct thread *td;
453	struct svr4_sys_llseek_args *uap;
454{
455	struct lseek_args ap;
456
457	ap.fd = uap->fd;
458
459#if BYTE_ORDER == BIG_ENDIAN
460	ap.offset = (((u_int64_t) uap->offset1) << 32) |
461		uap->offset2;
462#else
463	ap.offset = (((u_int64_t) uap->offset2) << 32) |
464		uap->offset1;
465#endif
466	ap.whence = uap->whence;
467
468	return lseek(td, &ap);
469}
470
471int
472svr4_sys_access(td, uap)
473	register struct thread *td;
474	struct svr4_sys_access_args *uap;
475{
476	char *newpath;
477	int error;
478
479	CHECKALTEXIST(td, uap->path, &newpath);
480	error = kern_access(td, newpath, UIO_SYSSPACE, uap->flags);
481	free(newpath, M_TEMP);
482	return (error);
483}
484
485#if defined(NOTYET)
486int
487svr4_sys_pread(td, uap)
488	register struct thread *td;
489	struct svr4_sys_pread_args *uap;
490{
491	struct pread_args pra;
492
493	/*
494	 * Just translate the args structure and call the NetBSD
495	 * pread(2) system call (offset type is 64-bit in NetBSD).
496	 */
497	pra.fd = uap->fd;
498	pra.buf = uap->buf;
499	pra.nbyte = uap->nbyte;
500	pra.offset = uap->off;
501
502	return pread(td, &pra);
503}
504#endif
505
506#if defined(NOTYET)
507int
508svr4_sys_pread64(td, v, retval)
509	register struct thread *td;
510	void *v;
511	register_t *retval;
512{
513
514	struct svr4_sys_pread64_args *uap = v;
515	struct sys_pread_args pra;
516
517	/*
518	 * Just translate the args structure and call the NetBSD
519	 * pread(2) system call (offset type is 64-bit in NetBSD).
520	 */
521	pra.fd = uap->fd;
522	pra.buf = uap->buf;
523	pra.nbyte = uap->nbyte;
524	pra.offset = uap->off;
525
526	return (sys_pread(td, &pra, retval));
527}
528#endif /* NOTYET */
529
530#if defined(NOTYET)
531int
532svr4_sys_pwrite(td, uap)
533	register struct thread *td;
534	struct svr4_sys_pwrite_args *uap;
535{
536	struct pwrite_args pwa;
537
538	/*
539	 * Just translate the args structure and call the NetBSD
540	 * pwrite(2) system call (offset type is 64-bit in NetBSD).
541	 */
542	pwa.fd = uap->fd;
543	pwa.buf = uap->buf;
544	pwa.nbyte = uap->nbyte;
545	pwa.offset = uap->off;
546
547	return pwrite(td, &pwa);
548}
549#endif
550
551#if defined(NOTYET)
552int
553svr4_sys_pwrite64(td, v, retval)
554	register struct thread *td;
555	void *v;
556	register_t *retval;
557{
558	struct svr4_sys_pwrite64_args *uap = v;
559	struct sys_pwrite_args pwa;
560
561	/*
562	 * Just translate the args structure and call the NetBSD
563	 * pwrite(2) system call (offset type is 64-bit in NetBSD).
564	 */
565	pwa.fd = uap->fd;
566	pwa.buf = uap->buf;
567	pwa.nbyte = uap->nbyte;
568	pwa.offset = uap->off;
569
570	return (sys_pwrite(td, &pwa, retval));
571}
572#endif /* NOTYET */
573
574int
575svr4_sys_fcntl(td, uap)
576	register struct thread *td;
577	struct svr4_sys_fcntl_args *uap;
578{
579	int cmd, error, *retval;
580
581	retval = td->td_retval;
582
583	cmd = svr4_to_bsd_cmd(uap->cmd);
584
585	switch (cmd) {
586	case F_DUPFD:
587	case F_GETFD:
588	case F_SETFD:
589		return (kern_fcntl(td, uap->fd, cmd, (intptr_t)uap->arg));
590
591	case F_GETFL:
592		error = kern_fcntl(td, uap->fd, cmd, (intptr_t)uap->arg);
593		if (error)
594			return (error);
595		*retval = bsd_to_svr4_flags(*retval);
596		return (error);
597
598	case F_SETFL:
599		{
600			/*
601			 * we must save the O_ASYNC flag, as that is
602			 * handled by ioctl(_, I_SETSIG, _) emulation.
603			 */
604			int flags;
605
606			DPRINTF(("Setting flags %p\n", uap->arg));
607
608			error = kern_fcntl(td, uap->fd, F_GETFL, 0);
609			if (error)
610				return (error);
611			flags = *retval;
612			flags &= O_ASYNC;
613			flags |= svr4_to_bsd_flags((u_long) uap->arg);
614			return (kern_fcntl(td, uap->fd, F_SETFL, flags));
615		}
616
617	case F_GETLK:
618	case F_SETLK:
619	case F_SETLKW:
620		{
621			struct svr4_flock	ifl;
622			struct flock		fl;
623
624			error = copyin(uap->arg, &ifl, sizeof (ifl));
625			if (error)
626				return (error);
627
628			svr4_to_bsd_flock(&ifl, &fl);
629
630			error = kern_fcntl(td, uap->fd, cmd, (intptr_t)&fl);
631			if (error || cmd != F_GETLK)
632				return (error);
633
634			bsd_to_svr4_flock(&fl, &ifl);
635
636			return (copyout(&ifl, uap->arg, sizeof (ifl)));
637		}
638	case -1:
639		switch (uap->cmd) {
640		case SVR4_F_DUP2FD:
641			{
642				struct dup2_args du;
643
644				du.from = uap->fd;
645				du.to = (int)uap->arg;
646				error = dup2(td, &du);
647				if (error)
648					return error;
649				*retval = du.to;
650				return 0;
651			}
652
653		case SVR4_F_FREESP:
654			{
655				struct svr4_flock	 ifl;
656				struct flock		 fl;
657
658				error = copyin(uap->arg, &ifl,
659				    sizeof ifl);
660				if (error)
661					return error;
662				svr4_to_bsd_flock(&ifl, &fl);
663				return fd_truncate(td, uap->fd, &fl);
664			}
665
666		case SVR4_F_GETLK64:
667		case SVR4_F_SETLK64:
668		case SVR4_F_SETLKW64:
669			{
670				struct svr4_flock64	ifl;
671				struct flock		fl;
672
673				switch (uap->cmd) {
674				case SVR4_F_GETLK64:
675					cmd = F_GETLK;
676					break;
677				case SVR4_F_SETLK64:
678					cmd = F_SETLK;
679					break;
680				case SVR4_F_SETLKW64:
681					cmd = F_SETLKW;
682					break;
683				}
684				error = copyin(uap->arg, &ifl,
685				    sizeof (ifl));
686				if (error)
687					return (error);
688
689				svr4_to_bsd_flock64(&ifl, &fl);
690
691				error = kern_fcntl(td, uap->fd, cmd,
692				    (intptr_t)&fl);
693				if (error || cmd != F_GETLK)
694					return (error);
695
696				bsd_to_svr4_flock64(&fl, &ifl);
697
698				return (copyout(&ifl, uap->arg,
699				    sizeof (ifl)));
700			}
701
702		case SVR4_F_FREESP64:
703			{
704				struct svr4_flock64	 ifl;
705				struct flock		 fl;
706
707				error = copyin(uap->arg, &ifl,
708				    sizeof ifl);
709				if (error)
710					return error;
711				svr4_to_bsd_flock64(&ifl, &fl);
712				return fd_truncate(td, uap->fd, &fl);
713			}
714
715		case SVR4_F_REVOKE:
716			return fd_revoke(td, uap->fd);
717
718		default:
719			return ENOSYS;
720		}
721
722	default:
723		return ENOSYS;
724	}
725}
726