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