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