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