svr4_fcntl.c revision 177633
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 177633 2008-03-26 15:23:12Z dfr $");
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_DUP2FD:
83		return F_DUP2FD;
84	case SVR4_F_GETFD:
85		return F_GETFD;
86	case SVR4_F_SETFD:
87		return F_SETFD;
88	case SVR4_F_GETFL:
89		return F_GETFL;
90	case SVR4_F_SETFL:
91		return F_SETFL;
92	case SVR4_F_GETLK:
93		return F_GETLK;
94	case SVR4_F_SETLK:
95		return F_SETLK;
96	case SVR4_F_SETLKW:
97		return F_SETLKW;
98	default:
99		return -1;
100	}
101}
102
103static int
104svr4_to_bsd_flags(l)
105	int	l;
106{
107	int	r = 0;
108	r |= (l & SVR4_O_RDONLY) ? O_RDONLY : 0;
109	r |= (l & SVR4_O_WRONLY) ? O_WRONLY : 0;
110	r |= (l & SVR4_O_RDWR) ? O_RDWR : 0;
111	r |= (l & SVR4_O_NDELAY) ? O_NONBLOCK : 0;
112	r |= (l & SVR4_O_APPEND) ? O_APPEND : 0;
113	r |= (l & SVR4_O_SYNC) ? O_FSYNC : 0;
114	r |= (l & SVR4_O_NONBLOCK) ? O_NONBLOCK : 0;
115	r |= (l & SVR4_O_PRIV) ? O_EXLOCK : 0;
116	r |= (l & SVR4_O_CREAT) ? O_CREAT : 0;
117	r |= (l & SVR4_O_TRUNC) ? O_TRUNC : 0;
118	r |= (l & SVR4_O_EXCL) ? O_EXCL : 0;
119	r |= (l & SVR4_O_NOCTTY) ? O_NOCTTY : 0;
120	return r;
121}
122
123static int
124bsd_to_svr4_flags(l)
125	int	l;
126{
127	int	r = 0;
128	r |= (l & O_RDONLY) ? SVR4_O_RDONLY : 0;
129	r |= (l & O_WRONLY) ? SVR4_O_WRONLY : 0;
130	r |= (l & O_RDWR) ? SVR4_O_RDWR : 0;
131	r |= (l & O_NDELAY) ? SVR4_O_NONBLOCK : 0;
132	r |= (l & O_APPEND) ? SVR4_O_APPEND : 0;
133	r |= (l & O_FSYNC) ? SVR4_O_SYNC : 0;
134	r |= (l & O_NONBLOCK) ? SVR4_O_NONBLOCK : 0;
135	r |= (l & O_EXLOCK) ? SVR4_O_PRIV : 0;
136	r |= (l & O_CREAT) ? SVR4_O_CREAT : 0;
137	r |= (l & O_TRUNC) ? SVR4_O_TRUNC : 0;
138	r |= (l & O_EXCL) ? SVR4_O_EXCL : 0;
139	r |= (l & O_NOCTTY) ? SVR4_O_NOCTTY : 0;
140	return r;
141}
142
143
144static void
145bsd_to_svr4_flock(iflp, oflp)
146	struct flock		*iflp;
147	struct svr4_flock	*oflp;
148{
149	switch (iflp->l_type) {
150	case F_RDLCK:
151		oflp->l_type = SVR4_F_RDLCK;
152		break;
153	case F_WRLCK:
154		oflp->l_type = SVR4_F_WRLCK;
155		break;
156	case F_UNLCK:
157		oflp->l_type = SVR4_F_UNLCK;
158		break;
159	default:
160		oflp->l_type = -1;
161		break;
162	}
163
164	oflp->l_whence = (short) iflp->l_whence;
165	oflp->l_start = (svr4_off_t) iflp->l_start;
166	oflp->l_len = (svr4_off_t) iflp->l_len;
167	oflp->l_sysid = 0;
168	oflp->l_pid = (svr4_pid_t) iflp->l_pid;
169}
170
171
172static void
173svr4_to_bsd_flock(iflp, oflp)
174	struct svr4_flock	*iflp;
175	struct flock		*oflp;
176{
177	switch (iflp->l_type) {
178	case SVR4_F_RDLCK:
179		oflp->l_type = F_RDLCK;
180		break;
181	case SVR4_F_WRLCK:
182		oflp->l_type = F_WRLCK;
183		break;
184	case SVR4_F_UNLCK:
185		oflp->l_type = F_UNLCK;
186		break;
187	default:
188		oflp->l_type = -1;
189		break;
190	}
191
192	oflp->l_whence = iflp->l_whence;
193	oflp->l_start = (off_t) iflp->l_start;
194	oflp->l_len = (off_t) iflp->l_len;
195	oflp->l_pid = (pid_t) iflp->l_pid;
196	oflp->l_sysid = iflp->l_sysid;
197}
198
199static void
200bsd_to_svr4_flock64(iflp, oflp)
201	struct flock		*iflp;
202	struct svr4_flock64	*oflp;
203{
204	switch (iflp->l_type) {
205	case F_RDLCK:
206		oflp->l_type = SVR4_F_RDLCK;
207		break;
208	case F_WRLCK:
209		oflp->l_type = SVR4_F_WRLCK;
210		break;
211	case F_UNLCK:
212		oflp->l_type = SVR4_F_UNLCK;
213		break;
214	default:
215		oflp->l_type = -1;
216		break;
217	}
218
219	oflp->l_whence = (short) iflp->l_whence;
220	oflp->l_start = (svr4_off64_t) iflp->l_start;
221	oflp->l_len = (svr4_off64_t) iflp->l_len;
222	oflp->l_sysid = iflp->l_sysid;
223	oflp->l_pid = (svr4_pid_t) iflp->l_pid;
224}
225
226
227static void
228svr4_to_bsd_flock64(iflp, oflp)
229	struct svr4_flock64	*iflp;
230	struct flock		*oflp;
231{
232	switch (iflp->l_type) {
233	case SVR4_F_RDLCK:
234		oflp->l_type = F_RDLCK;
235		break;
236	case SVR4_F_WRLCK:
237		oflp->l_type = F_WRLCK;
238		break;
239	case SVR4_F_UNLCK:
240		oflp->l_type = F_UNLCK;
241		break;
242	default:
243		oflp->l_type = -1;
244		break;
245	}
246
247	oflp->l_whence = iflp->l_whence;
248	oflp->l_start = (off_t) iflp->l_start;
249	oflp->l_len = (off_t) iflp->l_len;
250	oflp->l_pid = (pid_t) iflp->l_pid;
251
252}
253
254
255static int
256fd_revoke(td, fd)
257	struct thread *td;
258	int fd;
259{
260	struct vnode *vp;
261	struct mount *mp;
262	struct vattr vattr;
263	int error, *retval;
264
265	retval = td->td_retval;
266	if ((error = fgetvp(td, fd, &vp)) != 0)
267		return (error);
268
269	if (vp->v_type != VCHR && vp->v_type != VBLK) {
270		error = EINVAL;
271		goto out;
272	}
273
274#ifdef MAC
275	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
276	error = mac_vnode_check_revoke(td->td_ucred, vp);
277	VOP_UNLOCK(vp, 0);
278	if (error)
279		goto out;
280#endif
281
282	if ((error = VOP_GETATTR(vp, &vattr, td->td_ucred, td)) != 0)
283		goto out;
284
285	if (td->td_ucred->cr_uid != vattr.va_uid &&
286	    (error = priv_check(td, PRIV_VFS_ADMIN)) != 0)
287		goto out;
288
289	if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
290		goto out;
291	if (vcount(vp) > 1)
292		VOP_REVOKE(vp, REVOKEALL);
293	vn_finished_write(mp);
294out:
295	vrele(vp);
296	return error;
297}
298
299
300static int
301fd_truncate(td, fd, flp)
302	struct thread *td;
303	int fd;
304	struct flock *flp;
305{
306	off_t start, length;
307	struct file *fp;
308	struct vnode *vp;
309	struct vattr vattr;
310	int error, *retval;
311	struct ftruncate_args ft;
312
313	retval = td->td_retval;
314
315	/*
316	 * We only support truncating the file.
317	 */
318	if ((error = fget(td, fd, &fp)) != 0)
319		return (error);
320
321	vp = fp->f_vnode;
322
323	if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
324		fdrop(fp, td);
325		return ESPIPE;
326	}
327
328	if ((error = VOP_GETATTR(vp, &vattr, td->td_ucred, td)) != 0) {
329		fdrop(fp, td);
330		return error;
331	}
332
333	length = vattr.va_size;
334
335	switch (flp->l_whence) {
336	case SEEK_CUR:
337		start = fp->f_offset + flp->l_start;
338		break;
339
340	case SEEK_END:
341		start = flp->l_start + length;
342		break;
343
344	case SEEK_SET:
345		start = flp->l_start;
346		break;
347
348	default:
349		fdrop(fp, td);
350		return EINVAL;
351	}
352
353	if (start + flp->l_len < length) {
354		/* We don't support free'ing in the middle of the file */
355		fdrop(fp, td);
356		return EINVAL;
357	}
358
359	ft.fd = fd;
360	ft.length = start;
361
362	error = ftruncate(td, &ft);
363
364	fdrop(fp, td);
365	return (error);
366}
367
368int
369svr4_sys_open(td, uap)
370	register struct thread *td;
371	struct svr4_sys_open_args *uap;
372{
373	struct proc *p = td->td_proc;
374	char *newpath;
375	int bsd_flags, error, retval;
376
377	CHECKALTEXIST(td, uap->path, &newpath);
378
379	bsd_flags = svr4_to_bsd_flags(uap->flags);
380	error = kern_open(td, newpath, UIO_SYSSPACE, bsd_flags, uap->mode);
381	free(newpath, M_TEMP);
382
383	if (error) {
384	  /*	        uprintf("svr4_open(%s, 0x%0x, 0%o): %d\n", uap->path,
385			uap->flags, uap->mode, error);*/
386		return error;
387	}
388
389	retval = td->td_retval[0];
390
391	PROC_LOCK(p);
392	if (!(bsd_flags & O_NOCTTY) && SESS_LEADER(p) &&
393	    !(p->p_flag & P_CONTROLT)) {
394#if defined(NOTYET)
395		struct file	*fp;
396
397		error = fget(td, retval, &fp);
398		PROC_UNLOCK(p);
399		/*
400		 * we may have lost a race the above open() and
401		 * another thread issuing a close()
402		 */
403		if (error)
404			return (EBADF);	/* XXX: correct errno? */
405		/* ignore any error, just give it a try */
406		if (fp->f_type == DTYPE_VNODE)
407			fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0, td->td_ucred,
408			    td);
409		fdrop(fp, td);
410	} else {
411		PROC_UNLOCK(p);
412	}
413#else
414	}
415	PROC_UNLOCK(p);
416#endif
417	return error;
418}
419
420int
421svr4_sys_open64(td, uap)
422	register struct thread *td;
423	struct svr4_sys_open64_args *uap;
424{
425	return svr4_sys_open(td, (struct svr4_sys_open_args *)uap);
426}
427
428int
429svr4_sys_creat(td, uap)
430	register struct thread *td;
431	struct svr4_sys_creat_args *uap;
432{
433	char *newpath;
434	int error;
435
436	CHECKALTEXIST(td, uap->path, &newpath);
437
438	error = kern_open(td, newpath, UIO_SYSSPACE, O_WRONLY | O_CREAT |
439	    O_TRUNC, uap->mode);
440	free(newpath, M_TEMP);
441	return (error);
442}
443
444int
445svr4_sys_creat64(td, uap)
446	register struct thread *td;
447	struct svr4_sys_creat64_args *uap;
448{
449	return svr4_sys_creat(td, (struct svr4_sys_creat_args *)uap);
450}
451
452int
453svr4_sys_llseek(td, uap)
454	register struct thread *td;
455	struct svr4_sys_llseek_args *uap;
456{
457	struct lseek_args ap;
458
459	ap.fd = uap->fd;
460
461#if BYTE_ORDER == BIG_ENDIAN
462	ap.offset = (((u_int64_t) uap->offset1) << 32) |
463		uap->offset2;
464#else
465	ap.offset = (((u_int64_t) uap->offset2) << 32) |
466		uap->offset1;
467#endif
468	ap.whence = uap->whence;
469
470	return lseek(td, &ap);
471}
472
473int
474svr4_sys_access(td, uap)
475	register struct thread *td;
476	struct svr4_sys_access_args *uap;
477{
478	char *newpath;
479	int error;
480
481	CHECKALTEXIST(td, uap->path, &newpath);
482	error = kern_access(td, newpath, UIO_SYSSPACE, uap->flags);
483	free(newpath, M_TEMP);
484	return (error);
485}
486
487#if defined(NOTYET)
488int
489svr4_sys_pread(td, uap)
490	register struct thread *td;
491	struct svr4_sys_pread_args *uap;
492{
493	struct pread_args pra;
494
495	/*
496	 * Just translate the args structure and call the NetBSD
497	 * pread(2) system call (offset type is 64-bit in NetBSD).
498	 */
499	pra.fd = uap->fd;
500	pra.buf = uap->buf;
501	pra.nbyte = uap->nbyte;
502	pra.offset = uap->off;
503
504	return pread(td, &pra);
505}
506#endif
507
508#if defined(NOTYET)
509int
510svr4_sys_pread64(td, v, retval)
511	register struct thread *td;
512	void *v;
513	register_t *retval;
514{
515
516	struct svr4_sys_pread64_args *uap = v;
517	struct sys_pread_args pra;
518
519	/*
520	 * Just translate the args structure and call the NetBSD
521	 * pread(2) system call (offset type is 64-bit in NetBSD).
522	 */
523	pra.fd = uap->fd;
524	pra.buf = uap->buf;
525	pra.nbyte = uap->nbyte;
526	pra.offset = uap->off;
527
528	return (sys_pread(td, &pra, retval));
529}
530#endif /* NOTYET */
531
532#if defined(NOTYET)
533int
534svr4_sys_pwrite(td, uap)
535	register struct thread *td;
536	struct svr4_sys_pwrite_args *uap;
537{
538	struct pwrite_args pwa;
539
540	/*
541	 * Just translate the args structure and call the NetBSD
542	 * pwrite(2) system call (offset type is 64-bit in NetBSD).
543	 */
544	pwa.fd = uap->fd;
545	pwa.buf = uap->buf;
546	pwa.nbyte = uap->nbyte;
547	pwa.offset = uap->off;
548
549	return pwrite(td, &pwa);
550}
551#endif
552
553#if defined(NOTYET)
554int
555svr4_sys_pwrite64(td, v, retval)
556	register struct thread *td;
557	void *v;
558	register_t *retval;
559{
560	struct svr4_sys_pwrite64_args *uap = v;
561	struct sys_pwrite_args pwa;
562
563	/*
564	 * Just translate the args structure and call the NetBSD
565	 * pwrite(2) system call (offset type is 64-bit in NetBSD).
566	 */
567	pwa.fd = uap->fd;
568	pwa.buf = uap->buf;
569	pwa.nbyte = uap->nbyte;
570	pwa.offset = uap->off;
571
572	return (sys_pwrite(td, &pwa, retval));
573}
574#endif /* NOTYET */
575
576int
577svr4_sys_fcntl(td, uap)
578	register struct thread *td;
579	struct svr4_sys_fcntl_args *uap;
580{
581	int cmd, error, *retval;
582
583	retval = td->td_retval;
584
585	cmd = svr4_to_bsd_cmd(uap->cmd);
586
587	switch (cmd) {
588	case F_DUPFD:
589	case F_DUP2FD:
590	case F_GETFD:
591	case F_SETFD:
592		return (kern_fcntl(td, uap->fd, cmd, (intptr_t)uap->arg));
593
594	case F_GETFL:
595		error = kern_fcntl(td, uap->fd, cmd, (intptr_t)uap->arg);
596		if (error)
597			return (error);
598		*retval = bsd_to_svr4_flags(*retval);
599		return (error);
600
601	case F_SETFL:
602		{
603			/*
604			 * we must save the O_ASYNC flag, as that is
605			 * handled by ioctl(_, I_SETSIG, _) emulation.
606			 */
607			int flags;
608
609			DPRINTF(("Setting flags %p\n", uap->arg));
610
611			error = kern_fcntl(td, uap->fd, F_GETFL, 0);
612			if (error)
613				return (error);
614			flags = *retval;
615			flags &= O_ASYNC;
616			flags |= svr4_to_bsd_flags((u_long) uap->arg);
617			return (kern_fcntl(td, uap->fd, F_SETFL, flags));
618		}
619
620	case F_GETLK:
621	case F_SETLK:
622	case F_SETLKW:
623		{
624			struct svr4_flock	ifl;
625			struct flock		fl;
626
627			error = copyin(uap->arg, &ifl, sizeof (ifl));
628			if (error)
629				return (error);
630
631			svr4_to_bsd_flock(&ifl, &fl);
632
633			error = kern_fcntl(td, uap->fd, cmd, (intptr_t)&fl);
634			if (error || cmd != F_GETLK)
635				return (error);
636
637			bsd_to_svr4_flock(&fl, &ifl);
638
639			return (copyout(&ifl, uap->arg, sizeof (ifl)));
640		}
641	case -1:
642		switch (uap->cmd) {
643		case SVR4_F_FREESP:
644			{
645				struct svr4_flock	 ifl;
646				struct flock		 fl;
647
648				error = copyin(uap->arg, &ifl,
649				    sizeof ifl);
650				if (error)
651					return error;
652				svr4_to_bsd_flock(&ifl, &fl);
653				return fd_truncate(td, uap->fd, &fl);
654			}
655
656		case SVR4_F_GETLK64:
657		case SVR4_F_SETLK64:
658		case SVR4_F_SETLKW64:
659			{
660				struct svr4_flock64	ifl;
661				struct flock		fl;
662
663				switch (uap->cmd) {
664				case SVR4_F_GETLK64:
665					cmd = F_GETLK;
666					break;
667				case SVR4_F_SETLK64:
668					cmd = F_SETLK;
669					break;
670				case SVR4_F_SETLKW64:
671					cmd = F_SETLKW;
672					break;
673				}
674				error = copyin(uap->arg, &ifl,
675				    sizeof (ifl));
676				if (error)
677					return (error);
678
679				svr4_to_bsd_flock64(&ifl, &fl);
680
681				error = kern_fcntl(td, uap->fd, cmd,
682				    (intptr_t)&fl);
683				if (error || cmd != F_GETLK)
684					return (error);
685
686				bsd_to_svr4_flock64(&fl, &ifl);
687
688				return (copyout(&ifl, uap->arg,
689				    sizeof (ifl)));
690			}
691
692		case SVR4_F_FREESP64:
693			{
694				struct svr4_flock64	 ifl;
695				struct flock		 fl;
696
697				error = copyin(uap->arg, &ifl,
698				    sizeof ifl);
699				if (error)
700					return error;
701				svr4_to_bsd_flock64(&ifl, &fl);
702				return fd_truncate(td, uap->fd, &fl);
703			}
704
705		case SVR4_F_REVOKE:
706			return fd_revoke(td, uap->fd);
707
708		default:
709			return ENOSYS;
710		}
711
712	default:
713		return ENOSYS;
714	}
715}
716