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