xref: /freebsd/sys/compat/linux/linux_file.c (revision 40218a48e0a8dc7a6f4e9ba55f84586ce2014165)
1 /*-
2  * Copyright (c) 1994-1995 S�ren Schmidt
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer
10  *    in this position and unchanged.
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. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31 
32 #include "opt_compat.h"
33 #include "opt_mac.h"
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/conf.h>
38 #include <sys/dirent.h>
39 #include <sys/fcntl.h>
40 #include <sys/file.h>
41 #include <sys/filedesc.h>
42 #include <sys/lock.h>
43 #include <sys/mac.h>
44 #include <sys/malloc.h>
45 #include <sys/mount.h>
46 #include <sys/mutex.h>
47 #include <sys/proc.h>
48 #include <sys/stat.h>
49 #include <sys/syscallsubr.h>
50 #include <sys/sysproto.h>
51 #include <sys/tty.h>
52 #include <sys/unistd.h>
53 #include <sys/vnode.h>
54 
55 #include <ufs/ufs/extattr.h>
56 #include <ufs/ufs/quota.h>
57 #include <ufs/ufs/ufsmount.h>
58 
59 #ifdef COMPAT_LINUX32
60 #include <machine/../linux32/linux.h>
61 #include <machine/../linux32/linux32_proto.h>
62 #else
63 #include <machine/../linux/linux.h>
64 #include <machine/../linux/linux_proto.h>
65 #endif
66 #include <compat/linux/linux_util.h>
67 
68 int
69 linux_creat(struct thread *td, struct linux_creat_args *args)
70 {
71     char *path;
72     int error;
73 
74     LCONVPATHEXIST(td, args->path, &path);
75 
76 #ifdef DEBUG
77 	if (ldebug(creat))
78 		printf(ARGS(creat, "%s, %d"), path, args->mode);
79 #endif
80     error = kern_open(td, path, UIO_SYSSPACE, O_WRONLY | O_CREAT | O_TRUNC,
81 	args->mode);
82     LFREEPATH(path);
83     return (error);
84 }
85 
86 int
87 linux_open(struct thread *td, struct linux_open_args *args)
88 {
89     struct proc *p = td->td_proc;
90     char *path;
91     int bsd_flags, error;
92 
93     if (args->flags & LINUX_O_CREAT)
94 	LCONVPATHCREAT(td, args->path, &path);
95     else
96 	LCONVPATHEXIST(td, args->path, &path);
97 
98 #ifdef DEBUG
99 	if (ldebug(open))
100 		printf(ARGS(open, "%s, 0x%x, 0x%x"),
101 		    path, args->flags, args->mode);
102 #endif
103     bsd_flags = 0;
104     if (args->flags & LINUX_O_RDONLY)
105 	bsd_flags |= O_RDONLY;
106     if (args->flags & LINUX_O_WRONLY)
107 	bsd_flags |= O_WRONLY;
108     if (args->flags & LINUX_O_RDWR)
109 	bsd_flags |= O_RDWR;
110     if (args->flags & LINUX_O_NDELAY)
111 	bsd_flags |= O_NONBLOCK;
112     if (args->flags & LINUX_O_APPEND)
113 	bsd_flags |= O_APPEND;
114     if (args->flags & LINUX_O_SYNC)
115 	bsd_flags |= O_FSYNC;
116     if (args->flags & LINUX_O_NONBLOCK)
117 	bsd_flags |= O_NONBLOCK;
118     if (args->flags & LINUX_FASYNC)
119 	bsd_flags |= O_ASYNC;
120     if (args->flags & LINUX_O_CREAT)
121 	bsd_flags |= O_CREAT;
122     if (args->flags & LINUX_O_TRUNC)
123 	bsd_flags |= O_TRUNC;
124     if (args->flags & LINUX_O_EXCL)
125 	bsd_flags |= O_EXCL;
126     if (args->flags & LINUX_O_NOCTTY)
127 	bsd_flags |= O_NOCTTY;
128 
129     error = kern_open(td, path, UIO_SYSSPACE, bsd_flags, args->mode);
130     PROC_LOCK(p);
131     if (!error && !(bsd_flags & O_NOCTTY) &&
132 	SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
133 	struct file *fp;
134 
135 	PROC_UNLOCK(p);
136 	error = fget(td, td->td_retval[0], &fp);
137 	if (!error) {
138 		if (fp->f_type == DTYPE_VNODE)
139 			fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0, td->td_ucred,
140 			    td);
141 	    fdrop(fp, td);
142 	}
143     } else {
144 	PROC_UNLOCK(p);
145 #ifdef DEBUG
146 	if (ldebug(open))
147 		printf(LMSG("open returns error %d"), error);
148 #endif
149     }
150     LFREEPATH(path);
151     return error;
152 }
153 
154 int
155 linux_lseek(struct thread *td, struct linux_lseek_args *args)
156 {
157 
158     struct lseek_args /* {
159 	int fd;
160 	int pad;
161 	off_t offset;
162 	int whence;
163     } */ tmp_args;
164     int error;
165 
166 #ifdef DEBUG
167 	if (ldebug(lseek))
168 		printf(ARGS(lseek, "%d, %ld, %d"),
169 		    args->fdes, (long)args->off, args->whence);
170 #endif
171     tmp_args.fd = args->fdes;
172     tmp_args.offset = (off_t)args->off;
173     tmp_args.whence = args->whence;
174     error = lseek(td, &tmp_args);
175     return error;
176 }
177 
178 int
179 linux_llseek(struct thread *td, struct linux_llseek_args *args)
180 {
181 	struct lseek_args bsd_args;
182 	int error;
183 	off_t off;
184 
185 #ifdef DEBUG
186 	if (ldebug(llseek))
187 		printf(ARGS(llseek, "%d, %d:%d, %d"),
188 		    args->fd, args->ohigh, args->olow, args->whence);
189 #endif
190 	off = (args->olow) | (((off_t) args->ohigh) << 32);
191 
192 	bsd_args.fd = args->fd;
193 	bsd_args.offset = off;
194 	bsd_args.whence = args->whence;
195 
196 	if ((error = lseek(td, &bsd_args)))
197 		return error;
198 
199 	if ((error = copyout(td->td_retval, args->res, sizeof (off_t))))
200 		return error;
201 
202 	td->td_retval[0] = 0;
203 	return 0;
204 }
205 
206 int
207 linux_readdir(struct thread *td, struct linux_readdir_args *args)
208 {
209 	struct linux_getdents_args lda;
210 
211 	lda.fd = args->fd;
212 	lda.dent = args->dent;
213 	lda.count = 1;
214 	return linux_getdents(td, &lda);
215 }
216 
217 /*
218  * Note that linux_getdents(2) and linux_getdents64(2) have the same
219  * arguments. They only differ in the definition of struct dirent they
220  * operate on. We use this to common the code, with the exception of
221  * accessing struct dirent. Note that linux_readdir(2) is implemented
222  * by means of linux_getdents(2). In this case we never operate on
223  * struct dirent64 and thus don't need to handle it...
224  */
225 
226 struct l_dirent {
227 	l_long		d_ino;
228 	l_off_t		d_off;
229 	l_ushort	d_reclen;
230 	char		d_name[LINUX_NAME_MAX + 1];
231 };
232 
233 struct l_dirent64 {
234 	uint64_t	d_ino;
235 	int64_t		d_off;
236 	l_ushort	d_reclen;
237 	u_char		d_type;
238 	char		d_name[LINUX_NAME_MAX + 1];
239 };
240 
241 #define LINUX_RECLEN(de,namlen) \
242     ALIGN((((char *)&(de)->d_name - (char *)de) + (namlen) + 1))
243 
244 #define	LINUX_DIRBLKSIZ		512
245 
246 static int
247 getdents_common(struct thread *td, struct linux_getdents64_args *args,
248     int is64bit)
249 {
250 	struct dirent *bdp;
251 	struct vnode *vp;
252 	caddr_t inp, buf;		/* BSD-format */
253 	int len, reclen;		/* BSD-format */
254 	caddr_t outp;			/* Linux-format */
255 	int resid, linuxreclen=0;	/* Linux-format */
256 	struct file *fp;
257 	struct uio auio;
258 	struct iovec aiov;
259 	off_t off;
260 	struct l_dirent linux_dirent;
261 	struct l_dirent64 linux_dirent64;
262 	int buflen, error, eofflag, nbytes, justone;
263 	u_long *cookies = NULL, *cookiep;
264 	int ncookies, vfslocked;
265 
266 	nbytes = args->count;
267 	if (nbytes == 1) {
268 		/* readdir(2) case. Always struct dirent. */
269 		if (is64bit)
270 			return (EINVAL);
271 		nbytes = sizeof(linux_dirent);
272 		justone = 1;
273 	} else
274 		justone = 0;
275 
276 	if ((error = getvnode(td->td_proc->p_fd, args->fd, &fp)) != 0)
277 		return (error);
278 
279 	if ((fp->f_flag & FREAD) == 0) {
280 		fdrop(fp, td);
281 		return (EBADF);
282 	}
283 
284 	vp = fp->f_vnode;
285 	vfslocked = VFS_LOCK_GIANT(vp->v_mount);
286 	if (vp->v_type != VDIR) {
287 		VFS_UNLOCK_GIANT(vfslocked);
288 		fdrop(fp, td);
289 		return (EINVAL);
290 	}
291 
292 	off = fp->f_offset;
293 
294 	buflen = max(LINUX_DIRBLKSIZ, nbytes);
295 	buflen = min(buflen, MAXBSIZE);
296 	buf = malloc(buflen, M_TEMP, M_WAITOK);
297 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
298 
299 again:
300 	aiov.iov_base = buf;
301 	aiov.iov_len = buflen;
302 	auio.uio_iov = &aiov;
303 	auio.uio_iovcnt = 1;
304 	auio.uio_rw = UIO_READ;
305 	auio.uio_segflg = UIO_SYSSPACE;
306 	auio.uio_td = td;
307 	auio.uio_resid = buflen;
308 	auio.uio_offset = off;
309 
310 	if (cookies) {
311 		free(cookies, M_TEMP);
312 		cookies = NULL;
313 	}
314 
315 #ifdef MAC
316 	/*
317 	 * Do directory search MAC check using non-cached credentials.
318 	 */
319 	if ((error = mac_check_vnode_readdir(td->td_ucred, vp)))
320 		goto out;
321 #endif /* MAC */
322 	if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies,
323 		 &cookies)))
324 		goto out;
325 
326 	inp = buf;
327 	outp = (caddr_t)args->dirent;
328 	resid = nbytes;
329 	if ((len = buflen - auio.uio_resid) <= 0)
330 		goto eof;
331 
332 	cookiep = cookies;
333 
334 	if (cookies) {
335 		/*
336 		 * When using cookies, the vfs has the option of reading from
337 		 * a different offset than that supplied (UFS truncates the
338 		 * offset to a block boundary to make sure that it never reads
339 		 * partway through a directory entry, even if the directory
340 		 * has been compacted).
341 		 */
342 		while (len > 0 && ncookies > 0 && *cookiep <= off) {
343 			bdp = (struct dirent *) inp;
344 			len -= bdp->d_reclen;
345 			inp += bdp->d_reclen;
346 			cookiep++;
347 			ncookies--;
348 		}
349 	}
350 
351 	while (len > 0) {
352 		if (cookiep && ncookies == 0)
353 			break;
354 		bdp = (struct dirent *) inp;
355 		reclen = bdp->d_reclen;
356 		if (reclen & 3) {
357 			error = EFAULT;
358 			goto out;
359 		}
360 
361 		if (bdp->d_fileno == 0) {
362 			inp += reclen;
363 			if (cookiep) {
364 				off = *cookiep++;
365 				ncookies--;
366 			} else
367 				off += reclen;
368 
369 			len -= reclen;
370 			continue;
371 		}
372 
373 		linuxreclen = (is64bit)
374 		    ? LINUX_RECLEN(&linux_dirent64, bdp->d_namlen)
375 		    : LINUX_RECLEN(&linux_dirent, bdp->d_namlen);
376 
377 		if (reclen > len || resid < linuxreclen) {
378 			outp++;
379 			break;
380 		}
381 
382 		if (justone) {
383 			/* readdir(2) case. */
384 			linux_dirent.d_ino = (l_long)bdp->d_fileno;
385 			linux_dirent.d_off = (l_off_t)linuxreclen;
386 			linux_dirent.d_reclen = (l_ushort)bdp->d_namlen;
387 			strcpy(linux_dirent.d_name, bdp->d_name);
388 			error = copyout(&linux_dirent, outp, linuxreclen);
389 		} else {
390 			if (is64bit) {
391 				linux_dirent64.d_ino = bdp->d_fileno;
392 				linux_dirent64.d_off = (cookiep)
393 				    ? (l_off_t)*cookiep
394 				    : (l_off_t)(off + reclen);
395 				linux_dirent64.d_reclen =
396 				    (l_ushort)linuxreclen;
397 				linux_dirent64.d_type = bdp->d_type;
398 				strcpy(linux_dirent64.d_name, bdp->d_name);
399 				error = copyout(&linux_dirent64, outp,
400 				    linuxreclen);
401 			} else {
402 				linux_dirent.d_ino = bdp->d_fileno;
403 				linux_dirent.d_off = (cookiep)
404 				    ? (l_off_t)*cookiep
405 				    : (l_off_t)(off + reclen);
406 				linux_dirent.d_reclen = (l_ushort)linuxreclen;
407 				strcpy(linux_dirent.d_name, bdp->d_name);
408 				error = copyout(&linux_dirent, outp,
409 				    linuxreclen);
410 			}
411 		}
412 		if (error)
413 			goto out;
414 
415 		inp += reclen;
416 		if (cookiep) {
417 			off = *cookiep++;
418 			ncookies--;
419 		} else
420 			off += reclen;
421 
422 		outp += linuxreclen;
423 		resid -= linuxreclen;
424 		len -= reclen;
425 		if (justone)
426 			break;
427 	}
428 
429 	if (outp == (caddr_t)args->dirent)
430 		goto again;
431 
432 	fp->f_offset = off;
433 	if (justone)
434 		nbytes = resid + linuxreclen;
435 
436 eof:
437 	td->td_retval[0] = nbytes - resid;
438 
439 out:
440 	if (cookies)
441 		free(cookies, M_TEMP);
442 
443 	VOP_UNLOCK(vp, 0, td);
444 	VFS_UNLOCK_GIANT(vfslocked);
445 	fdrop(fp, td);
446 	free(buf, M_TEMP);
447 	return (error);
448 }
449 
450 int
451 linux_getdents(struct thread *td, struct linux_getdents_args *args)
452 {
453 
454 #ifdef DEBUG
455 	if (ldebug(getdents))
456 		printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count);
457 #endif
458 
459 	return (getdents_common(td, (struct linux_getdents64_args*)args, 0));
460 }
461 
462 int
463 linux_getdents64(struct thread *td, struct linux_getdents64_args *args)
464 {
465 
466 #ifdef DEBUG
467 	if (ldebug(getdents64))
468 		printf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count);
469 #endif
470 
471 	return (getdents_common(td, args, 1));
472 }
473 
474 /*
475  * These exist mainly for hooks for doing /compat/linux translation.
476  */
477 
478 int
479 linux_access(struct thread *td, struct linux_access_args *args)
480 {
481 	char *path;
482 	int error;
483 
484 	/* linux convention */
485 	if (args->flags & ~(F_OK | X_OK | W_OK | R_OK))
486 		return (EINVAL);
487 
488 	LCONVPATHEXIST(td, args->path, &path);
489 
490 #ifdef DEBUG
491 	if (ldebug(access))
492 		printf(ARGS(access, "%s, %d"), path, args->flags);
493 #endif
494 	error = kern_access(td, path, UIO_SYSSPACE, args->flags);
495 	LFREEPATH(path);
496 
497 	return (error);
498 }
499 
500 int
501 linux_unlink(struct thread *td, struct linux_unlink_args *args)
502 {
503 	char *path;
504 	int error;
505 	struct stat st;
506 
507 	LCONVPATHEXIST(td, args->path, &path);
508 
509 #ifdef DEBUG
510 	if (ldebug(unlink))
511 		printf(ARGS(unlink, "%s"), path);
512 #endif
513 
514 	error = kern_unlink(td, path, UIO_SYSSPACE);
515 	if (error == EPERM)
516 		/* Introduce POSIX noncompliant behaviour of Linux */
517 		if (kern_stat(td, path, UIO_SYSSPACE, &st) == 0)
518 			if (S_ISDIR(st.st_mode))
519 				error = EISDIR;
520 	LFREEPATH(path);
521 	return (error);
522 }
523 
524 int
525 linux_chdir(struct thread *td, struct linux_chdir_args *args)
526 {
527 	char *path;
528 	int error;
529 
530 	LCONVPATHEXIST(td, args->path, &path);
531 
532 #ifdef DEBUG
533 	if (ldebug(chdir))
534 		printf(ARGS(chdir, "%s"), path);
535 #endif
536 	error = kern_chdir(td, path, UIO_SYSSPACE);
537 	LFREEPATH(path);
538 	return (error);
539 }
540 
541 int
542 linux_chmod(struct thread *td, struct linux_chmod_args *args)
543 {
544 	char *path;
545 	int error;
546 
547 	LCONVPATHEXIST(td, args->path, &path);
548 
549 #ifdef DEBUG
550 	if (ldebug(chmod))
551 		printf(ARGS(chmod, "%s, %d"), path, args->mode);
552 #endif
553 	error = kern_chmod(td, path, UIO_SYSSPACE, args->mode);
554 	LFREEPATH(path);
555 	return (error);
556 }
557 
558 int
559 linux_mkdir(struct thread *td, struct linux_mkdir_args *args)
560 {
561 	char *path;
562 	int error;
563 
564 	LCONVPATHCREAT(td, args->path, &path);
565 
566 #ifdef DEBUG
567 	if (ldebug(mkdir))
568 		printf(ARGS(mkdir, "%s, %d"), path, args->mode);
569 #endif
570 	error = kern_mkdir(td, path, UIO_SYSSPACE, args->mode);
571 	LFREEPATH(path);
572 	return (error);
573 }
574 
575 int
576 linux_rmdir(struct thread *td, struct linux_rmdir_args *args)
577 {
578 	char *path;
579 	int error;
580 
581 	LCONVPATHEXIST(td, args->path, &path);
582 
583 #ifdef DEBUG
584 	if (ldebug(rmdir))
585 		printf(ARGS(rmdir, "%s"), path);
586 #endif
587 	error = kern_rmdir(td, path, UIO_SYSSPACE);
588 	LFREEPATH(path);
589 	return (error);
590 }
591 
592 int
593 linux_rename(struct thread *td, struct linux_rename_args *args)
594 {
595 	char *from, *to;
596 	int error;
597 
598 	LCONVPATHEXIST(td, args->from, &from);
599 	/* Expand LCONVPATHCREATE so that `from' can be freed on errors */
600 	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1);
601 	if (to == NULL) {
602 		LFREEPATH(from);
603 		return (error);
604 	}
605 
606 #ifdef DEBUG
607 	if (ldebug(rename))
608 		printf(ARGS(rename, "%s, %s"), from, to);
609 #endif
610 	error = kern_rename(td, from, to, UIO_SYSSPACE);
611 	LFREEPATH(from);
612 	LFREEPATH(to);
613 	return (error);
614 }
615 
616 int
617 linux_symlink(struct thread *td, struct linux_symlink_args *args)
618 {
619 	char *path, *to;
620 	int error;
621 
622 	LCONVPATHEXIST(td, args->path, &path);
623 	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
624 	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1);
625 	if (to == NULL) {
626 		LFREEPATH(path);
627 		return (error);
628 	}
629 
630 #ifdef DEBUG
631 	if (ldebug(symlink))
632 		printf(ARGS(symlink, "%s, %s"), path, to);
633 #endif
634 	error = kern_symlink(td, path, to, UIO_SYSSPACE);
635 	LFREEPATH(path);
636 	LFREEPATH(to);
637 	return (error);
638 }
639 
640 int
641 linux_readlink(struct thread *td, struct linux_readlink_args *args)
642 {
643 	char *name;
644 	int error;
645 
646 	LCONVPATHEXIST(td, args->name, &name);
647 
648 #ifdef DEBUG
649 	if (ldebug(readlink))
650 		printf(ARGS(readlink, "%s, %p, %d"), name, (void *)args->buf,
651 		    args->count);
652 #endif
653 	error = kern_readlink(td, name, UIO_SYSSPACE, args->buf, UIO_USERSPACE,
654 	    args->count);
655 	LFREEPATH(name);
656 	return (error);
657 }
658 
659 int
660 linux_truncate(struct thread *td, struct linux_truncate_args *args)
661 {
662 	char *path;
663 	int error;
664 
665 	LCONVPATHEXIST(td, args->path, &path);
666 
667 #ifdef DEBUG
668 	if (ldebug(truncate))
669 		printf(ARGS(truncate, "%s, %ld"), path, (long)args->length);
670 #endif
671 
672 	error = kern_truncate(td, path, UIO_SYSSPACE, args->length);
673 	LFREEPATH(path);
674 	return (error);
675 }
676 
677 int
678 linux_ftruncate(struct thread *td, struct linux_ftruncate_args *args)
679 {
680 	struct ftruncate_args /* {
681 		int fd;
682 		int pad;
683 		off_t length;
684 		} */ nuap;
685 
686 	nuap.fd = args->fd;
687 	nuap.pad = 0;
688 	nuap.length = args->length;
689 	return (ftruncate(td, &nuap));
690 }
691 
692 int
693 linux_link(struct thread *td, struct linux_link_args *args)
694 {
695 	char *path, *to;
696 	int error;
697 
698 	LCONVPATHEXIST(td, args->path, &path);
699 	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
700 	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1);
701 	if (to == NULL) {
702 		LFREEPATH(path);
703 		return (error);
704 	}
705 
706 #ifdef DEBUG
707 	if (ldebug(link))
708 		printf(ARGS(link, "%s, %s"), path, to);
709 #endif
710 	error = kern_link(td, path, to, UIO_SYSSPACE);
711 	LFREEPATH(path);
712 	LFREEPATH(to);
713 	return (error);
714 }
715 
716 int
717 linux_fdatasync(td, uap)
718 	struct thread *td;
719 	struct linux_fdatasync_args *uap;
720 {
721 	struct fsync_args bsd;
722 
723 	bsd.fd = uap->fd;
724 	return fsync(td, &bsd);
725 }
726 
727 int
728 linux_pread(td, uap)
729 	struct thread *td;
730 	struct linux_pread_args *uap;
731 {
732 	struct pread_args bsd;
733 	struct vnode *vp;
734 	int error;
735 
736 	bsd.fd = uap->fd;
737 	bsd.buf = uap->buf;
738 	bsd.nbyte = uap->nbyte;
739 	bsd.offset = uap->offset;
740 
741 	error = pread(td, &bsd);
742 
743 	if (error == 0) {
744    	   	/* This seems to violate POSIX but linux does it */
745    	   	if ((error = fgetvp(td, uap->fd, &vp)) != 0)
746    		   	return (error);
747 		if (vp->v_type == VDIR) {
748    		   	vrele(vp);
749 			return (EISDIR);
750 		}
751 		vrele(vp);
752 	}
753 
754 	return (error);
755 }
756 
757 int
758 linux_pwrite(td, uap)
759 	struct thread *td;
760 	struct linux_pwrite_args *uap;
761 {
762 	struct pwrite_args bsd;
763 
764 	bsd.fd = uap->fd;
765 	bsd.buf = uap->buf;
766 	bsd.nbyte = uap->nbyte;
767 	bsd.offset = uap->offset;
768 	return pwrite(td, &bsd);
769 }
770 
771 int
772 linux_mount(struct thread *td, struct linux_mount_args *args)
773 {
774 	struct ufs_args ufs;
775 	char fstypename[MFSNAMELEN];
776 	char mntonname[MNAMELEN], mntfromname[MNAMELEN];
777 	int error;
778 	int fsflags;
779 	void *fsdata;
780 
781 	error = copyinstr(args->filesystemtype, fstypename, MFSNAMELEN - 1,
782 	    NULL);
783 	if (error)
784 		return (error);
785 	error = copyinstr(args->specialfile, mntfromname, MNAMELEN - 1, NULL);
786 	if (error)
787 		return (error);
788 	error = copyinstr(args->dir, mntonname, MNAMELEN - 1, NULL);
789 	if (error)
790 		return (error);
791 
792 #ifdef DEBUG
793 	if (ldebug(mount))
794 		printf(ARGS(mount, "%s, %s, %s"),
795 		    fstypename, mntfromname, mntonname);
796 #endif
797 
798 	if (strcmp(fstypename, "ext2") == 0) {
799 		strcpy(fstypename, "ext2fs");
800 		fsdata = &ufs;
801 		ufs.fspec = mntfromname;
802 #define DEFAULT_ROOTID		-2
803 		ufs.export.ex_root = DEFAULT_ROOTID;
804 		ufs.export.ex_flags =
805 		    args->rwflag & LINUX_MS_RDONLY ? MNT_EXRDONLY : 0;
806 	} else if (strcmp(fstypename, "proc") == 0) {
807 		strcpy(fstypename, "linprocfs");
808 		fsdata = NULL;
809 	} else {
810 		return (ENODEV);
811 	}
812 
813 	fsflags = 0;
814 
815 	if ((args->rwflag & 0xffff0000) == 0xc0ed0000) {
816 		/*
817 		 * Linux SYNC flag is not included; the closest equivalent
818 		 * FreeBSD has is !ASYNC, which is our default.
819 		 */
820 		if (args->rwflag & LINUX_MS_RDONLY)
821 			fsflags |= MNT_RDONLY;
822 		if (args->rwflag & LINUX_MS_NOSUID)
823 			fsflags |= MNT_NOSUID;
824 		if (args->rwflag & LINUX_MS_NOEXEC)
825 			fsflags |= MNT_NOEXEC;
826 		if (args->rwflag & LINUX_MS_REMOUNT)
827 			fsflags |= MNT_UPDATE;
828 	}
829 
830 	if (strcmp(fstypename, "linprocfs") == 0) {
831 		error = kernel_vmount(fsflags,
832 			"fstype", fstypename,
833 			"fspath", mntonname,
834 			NULL);
835 	} else
836 		error = EOPNOTSUPP;
837 	return (error);
838 }
839 
840 int
841 linux_oldumount(struct thread *td, struct linux_oldumount_args *args)
842 {
843 	struct linux_umount_args args2;
844 
845 	args2.path = args->path;
846 	args2.flags = 0;
847 	return (linux_umount(td, &args2));
848 }
849 
850 int
851 linux_umount(struct thread *td, struct linux_umount_args *args)
852 {
853 	struct unmount_args bsd;
854 
855 	bsd.path = args->path;
856 	bsd.flags = args->flags;	/* XXX correct? */
857 	return (unmount(td, &bsd));
858 }
859 
860 /*
861  * fcntl family of syscalls
862  */
863 
864 struct l_flock {
865 	l_short		l_type;
866 	l_short		l_whence;
867 	l_off_t		l_start;
868 	l_off_t		l_len;
869 	l_pid_t		l_pid;
870 }
871 #if defined(__amd64__) && defined(COMPAT_LINUX32)
872 __packed
873 #endif
874 ;
875 
876 static void
877 linux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock)
878 {
879 	switch (linux_flock->l_type) {
880 	case LINUX_F_RDLCK:
881 		bsd_flock->l_type = F_RDLCK;
882 		break;
883 	case LINUX_F_WRLCK:
884 		bsd_flock->l_type = F_WRLCK;
885 		break;
886 	case LINUX_F_UNLCK:
887 		bsd_flock->l_type = F_UNLCK;
888 		break;
889 	default:
890 		bsd_flock->l_type = -1;
891 		break;
892 	}
893 	bsd_flock->l_whence = linux_flock->l_whence;
894 	bsd_flock->l_start = (off_t)linux_flock->l_start;
895 	bsd_flock->l_len = (off_t)linux_flock->l_len;
896 	bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
897 }
898 
899 static void
900 bsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock)
901 {
902 	switch (bsd_flock->l_type) {
903 	case F_RDLCK:
904 		linux_flock->l_type = LINUX_F_RDLCK;
905 		break;
906 	case F_WRLCK:
907 		linux_flock->l_type = LINUX_F_WRLCK;
908 		break;
909 	case F_UNLCK:
910 		linux_flock->l_type = LINUX_F_UNLCK;
911 		break;
912 	}
913 	linux_flock->l_whence = bsd_flock->l_whence;
914 	linux_flock->l_start = (l_off_t)bsd_flock->l_start;
915 	linux_flock->l_len = (l_off_t)bsd_flock->l_len;
916 	linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
917 }
918 
919 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
920 struct l_flock64 {
921 	l_short		l_type;
922 	l_short		l_whence;
923 	l_loff_t	l_start;
924 	l_loff_t	l_len;
925 	l_pid_t		l_pid;
926 }
927 #if defined(__amd64__) && defined(COMPAT_LINUX32)
928 __packed
929 #endif
930 ;
931 
932 static void
933 linux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock)
934 {
935 	switch (linux_flock->l_type) {
936 	case LINUX_F_RDLCK:
937 		bsd_flock->l_type = F_RDLCK;
938 		break;
939 	case LINUX_F_WRLCK:
940 		bsd_flock->l_type = F_WRLCK;
941 		break;
942 	case LINUX_F_UNLCK:
943 		bsd_flock->l_type = F_UNLCK;
944 		break;
945 	default:
946 		bsd_flock->l_type = -1;
947 		break;
948 	}
949 	bsd_flock->l_whence = linux_flock->l_whence;
950 	bsd_flock->l_start = (off_t)linux_flock->l_start;
951 	bsd_flock->l_len = (off_t)linux_flock->l_len;
952 	bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
953 }
954 
955 static void
956 bsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock)
957 {
958 	switch (bsd_flock->l_type) {
959 	case F_RDLCK:
960 		linux_flock->l_type = LINUX_F_RDLCK;
961 		break;
962 	case F_WRLCK:
963 		linux_flock->l_type = LINUX_F_WRLCK;
964 		break;
965 	case F_UNLCK:
966 		linux_flock->l_type = LINUX_F_UNLCK;
967 		break;
968 	}
969 	linux_flock->l_whence = bsd_flock->l_whence;
970 	linux_flock->l_start = (l_loff_t)bsd_flock->l_start;
971 	linux_flock->l_len = (l_loff_t)bsd_flock->l_len;
972 	linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
973 }
974 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
975 
976 static int
977 fcntl_common(struct thread *td, struct linux_fcntl64_args *args)
978 {
979 	struct l_flock linux_flock;
980 	struct flock bsd_flock;
981 	struct file *fp;
982 	long arg;
983 	int error, result;
984 
985 	switch (args->cmd) {
986 	case LINUX_F_DUPFD:
987 		return (kern_fcntl(td, args->fd, F_DUPFD, args->arg));
988 
989 	case LINUX_F_GETFD:
990 		return (kern_fcntl(td, args->fd, F_GETFD, 0));
991 
992 	case LINUX_F_SETFD:
993 		return (kern_fcntl(td, args->fd, F_SETFD, args->arg));
994 
995 	case LINUX_F_GETFL:
996 		error = kern_fcntl(td, args->fd, F_GETFL, 0);
997 		result = td->td_retval[0];
998 		td->td_retval[0] = 0;
999 		if (result & O_RDONLY)
1000 			td->td_retval[0] |= LINUX_O_RDONLY;
1001 		if (result & O_WRONLY)
1002 			td->td_retval[0] |= LINUX_O_WRONLY;
1003 		if (result & O_RDWR)
1004 			td->td_retval[0] |= LINUX_O_RDWR;
1005 		if (result & O_NDELAY)
1006 			td->td_retval[0] |= LINUX_O_NONBLOCK;
1007 		if (result & O_APPEND)
1008 			td->td_retval[0] |= LINUX_O_APPEND;
1009 		if (result & O_FSYNC)
1010 			td->td_retval[0] |= LINUX_O_SYNC;
1011 		if (result & O_ASYNC)
1012 			td->td_retval[0] |= LINUX_FASYNC;
1013 #ifdef LINUX_O_NOFOLLOW
1014 		if (result & O_NOFOLLOW)
1015 			td->td_retval[0] |= LINUX_O_NOFOLLOW;
1016 #endif
1017 #ifdef LINUX_O_DIRECT
1018 		if (result & O_DIRECT)
1019 			td->td_retval[0] |= LINUX_O_DIRECT;
1020 #endif
1021 		return (error);
1022 
1023 	case LINUX_F_SETFL:
1024 		arg = 0;
1025 		if (args->arg & LINUX_O_NDELAY)
1026 			arg |= O_NONBLOCK;
1027 		if (args->arg & LINUX_O_APPEND)
1028 			arg |= O_APPEND;
1029 		if (args->arg & LINUX_O_SYNC)
1030 			arg |= O_FSYNC;
1031 		if (args->arg & LINUX_FASYNC)
1032 			arg |= O_ASYNC;
1033 #ifdef LINUX_O_NOFOLLOW
1034 		if (args->arg & LINUX_O_NOFOLLOW)
1035 			arg |= O_NOFOLLOW;
1036 #endif
1037 #ifdef LINUX_O_DIRECT
1038 		if (args->arg & LINUX_O_DIRECT)
1039 			arg |= O_DIRECT;
1040 #endif
1041 		return (kern_fcntl(td, args->fd, F_SETFL, arg));
1042 
1043 	case LINUX_F_GETLK:
1044 		error = copyin((void *)args->arg, &linux_flock,
1045 		    sizeof(linux_flock));
1046 		if (error)
1047 			return (error);
1048 		linux_to_bsd_flock(&linux_flock, &bsd_flock);
1049 		error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock);
1050 		if (error)
1051 			return (error);
1052 		bsd_to_linux_flock(&bsd_flock, &linux_flock);
1053 		return (copyout(&linux_flock, (void *)args->arg,
1054 		    sizeof(linux_flock)));
1055 
1056 	case LINUX_F_SETLK:
1057 		error = copyin((void *)args->arg, &linux_flock,
1058 		    sizeof(linux_flock));
1059 		if (error)
1060 			return (error);
1061 		linux_to_bsd_flock(&linux_flock, &bsd_flock);
1062 		return (kern_fcntl(td, args->fd, F_SETLK,
1063 		    (intptr_t)&bsd_flock));
1064 
1065 	case LINUX_F_SETLKW:
1066 		error = copyin((void *)args->arg, &linux_flock,
1067 		    sizeof(linux_flock));
1068 		if (error)
1069 			return (error);
1070 		linux_to_bsd_flock(&linux_flock, &bsd_flock);
1071 		return (kern_fcntl(td, args->fd, F_SETLKW,
1072 		     (intptr_t)&bsd_flock));
1073 
1074 	case LINUX_F_GETOWN:
1075 		return (kern_fcntl(td, args->fd, F_GETOWN, 0));
1076 
1077 	case LINUX_F_SETOWN:
1078 		/*
1079 		 * XXX some Linux applications depend on F_SETOWN having no
1080 		 * significant effect for pipes (SIGIO is not delivered for
1081 		 * pipes under Linux-2.2.35 at least).
1082 		 */
1083 		error = fget(td, args->fd, &fp);
1084 		if (error)
1085 			return (error);
1086 		if (fp->f_type == DTYPE_PIPE) {
1087 			fdrop(fp, td);
1088 			return (EINVAL);
1089 		}
1090 		fdrop(fp, td);
1091 
1092 		return (kern_fcntl(td, args->fd, F_SETOWN, args->arg));
1093 	}
1094 
1095 	return (EINVAL);
1096 }
1097 
1098 int
1099 linux_fcntl(struct thread *td, struct linux_fcntl_args *args)
1100 {
1101 	struct linux_fcntl64_args args64;
1102 
1103 #ifdef DEBUG
1104 	if (ldebug(fcntl))
1105 		printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd);
1106 #endif
1107 
1108 	args64.fd = args->fd;
1109 	args64.cmd = args->cmd;
1110 	args64.arg = args->arg;
1111 	return (fcntl_common(td, &args64));
1112 }
1113 
1114 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
1115 int
1116 linux_fcntl64(struct thread *td, struct linux_fcntl64_args *args)
1117 {
1118 	struct l_flock64 linux_flock;
1119 	struct flock bsd_flock;
1120 	int error;
1121 
1122 #ifdef DEBUG
1123 	if (ldebug(fcntl64))
1124 		printf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd);
1125 #endif
1126 
1127 	switch (args->cmd) {
1128 	case LINUX_F_GETLK64:
1129 		error = copyin((void *)args->arg, &linux_flock,
1130 		    sizeof(linux_flock));
1131 		if (error)
1132 			return (error);
1133 		linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1134 		error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock);
1135 		if (error)
1136 			return (error);
1137 		bsd_to_linux_flock64(&bsd_flock, &linux_flock);
1138 		return (copyout(&linux_flock, (void *)args->arg,
1139 			    sizeof(linux_flock)));
1140 
1141 	case LINUX_F_SETLK64:
1142 		error = copyin((void *)args->arg, &linux_flock,
1143 		    sizeof(linux_flock));
1144 		if (error)
1145 			return (error);
1146 		linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1147 		return (kern_fcntl(td, args->fd, F_SETLK,
1148 		    (intptr_t)&bsd_flock));
1149 
1150 	case LINUX_F_SETLKW64:
1151 		error = copyin((void *)args->arg, &linux_flock,
1152 		    sizeof(linux_flock));
1153 		if (error)
1154 			return (error);
1155 		linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1156 		return (kern_fcntl(td, args->fd, F_SETLKW,
1157 		    (intptr_t)&bsd_flock));
1158 	}
1159 
1160 	return (fcntl_common(td, args));
1161 }
1162 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
1163 
1164 int
1165 linux_chown(struct thread *td, struct linux_chown_args *args)
1166 {
1167 	char *path;
1168 	int error;
1169 
1170 	LCONVPATHEXIST(td, args->path, &path);
1171 
1172 #ifdef DEBUG
1173 	if (ldebug(chown))
1174 		printf(ARGS(chown, "%s, %d, %d"), path, args->uid, args->gid);
1175 #endif
1176 	error = kern_chown(td, path, UIO_SYSSPACE, args->uid, args->gid);
1177 	LFREEPATH(path);
1178 	return (error);
1179 }
1180 
1181 int
1182 linux_lchown(struct thread *td, struct linux_lchown_args *args)
1183 {
1184 	char *path;
1185 	int error;
1186 
1187 	LCONVPATHEXIST(td, args->path, &path);
1188 
1189 #ifdef DEBUG
1190 	if (ldebug(lchown))
1191 		printf(ARGS(lchown, "%s, %d, %d"), path, args->uid, args->gid);
1192 #endif
1193 	error = kern_lchown(td, path, UIO_SYSSPACE, args->uid, args->gid);
1194 	LFREEPATH(path);
1195 	return (error);
1196 }
1197