xref: /freebsd/sys/compat/linux/linux_file.c (revision 2357939bc239bd5334a169b62313806178dd8f30)
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 	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_vnode;
274 	if (vp->v_type != VDIR) {
275 		fdrop(fp, td);
276 		return (EINVAL);
277 	}
278 
279 	nbytes = args->count;
280 	if (nbytes == 1) {
281 		/* readdir(2) case. Always struct dirent. */
282 		if (is64bit) {
283 			fdrop(fp, td);
284 			return (EINVAL);
285 		}
286 		nbytes = sizeof(linux_dirent);
287 		justone = 1;
288 	} else
289 		justone = 0;
290 
291 	off = fp->f_offset;
292 
293 	buflen = max(LINUX_DIRBLKSIZ, nbytes);
294 	buflen = min(buflen, MAXBSIZE);
295 	buf = malloc(buflen, M_TEMP, M_WAITOK);
296 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
297 
298 again:
299 	aiov.iov_base = buf;
300 	aiov.iov_len = buflen;
301 	auio.uio_iov = &aiov;
302 	auio.uio_iovcnt = 1;
303 	auio.uio_rw = UIO_READ;
304 	auio.uio_segflg = UIO_SYSSPACE;
305 	auio.uio_td = td;
306 	auio.uio_resid = buflen;
307 	auio.uio_offset = off;
308 
309 	if (cookies) {
310 		free(cookies, M_TEMP);
311 		cookies = NULL;
312 	}
313 
314 #ifdef MAC
315 	/*
316 	 * Do directory search MAC check using non-cached credentials.
317 	 */
318 	if ((error = mac_check_vnode_readdir(td->td_ucred, vp)))
319 		goto out;
320 #endif /* MAC */
321 	if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies,
322 		 &cookies)))
323 		goto out;
324 
325 	inp = buf;
326 	outp = (caddr_t)args->dirent;
327 	resid = nbytes;
328 	if ((len = buflen - auio.uio_resid) <= 0)
329 		goto eof;
330 
331 	cookiep = cookies;
332 
333 	if (cookies) {
334 		/*
335 		 * When using cookies, the vfs has the option of reading from
336 		 * a different offset than that supplied (UFS truncates the
337 		 * offset to a block boundary to make sure that it never reads
338 		 * partway through a directory entry, even if the directory
339 		 * has been compacted).
340 		 */
341 		while (len > 0 && ncookies > 0 && *cookiep <= off) {
342 			bdp = (struct dirent *) inp;
343 			len -= bdp->d_reclen;
344 			inp += bdp->d_reclen;
345 			cookiep++;
346 			ncookies--;
347 		}
348 	}
349 
350 	while (len > 0) {
351 		if (cookiep && ncookies == 0)
352 			break;
353 		bdp = (struct dirent *) inp;
354 		reclen = bdp->d_reclen;
355 		if (reclen & 3) {
356 			error = EFAULT;
357 			goto out;
358 		}
359 
360 		if (bdp->d_fileno == 0) {
361 			inp += reclen;
362 			if (cookiep) {
363 				off = *cookiep++;
364 				ncookies--;
365 			} else
366 				off += reclen;
367 
368 			len -= reclen;
369 			continue;
370 		}
371 
372 		linuxreclen = (is64bit)
373 		    ? LINUX_RECLEN(&linux_dirent64, bdp->d_namlen)
374 		    : LINUX_RECLEN(&linux_dirent, bdp->d_namlen);
375 
376 		if (reclen > len || resid < linuxreclen) {
377 			outp++;
378 			break;
379 		}
380 
381 		if (justone) {
382 			/* readdir(2) case. */
383 			linux_dirent.d_ino = (l_long)bdp->d_fileno;
384 			linux_dirent.d_off = (l_off_t)linuxreclen;
385 			linux_dirent.d_reclen = (l_ushort)bdp->d_namlen;
386 			strcpy(linux_dirent.d_name, bdp->d_name);
387 			error = copyout(&linux_dirent, outp, linuxreclen);
388 		} else {
389 			if (is64bit) {
390 				linux_dirent64.d_ino = bdp->d_fileno;
391 				linux_dirent64.d_off = (cookiep)
392 				    ? (l_off_t)*cookiep
393 				    : (l_off_t)(off + reclen);
394 				linux_dirent64.d_reclen =
395 				    (l_ushort)linuxreclen;
396 				linux_dirent64.d_type = bdp->d_type;
397 				strcpy(linux_dirent64.d_name, bdp->d_name);
398 				error = copyout(&linux_dirent64, outp,
399 				    linuxreclen);
400 			} else {
401 				linux_dirent.d_ino = bdp->d_fileno;
402 				linux_dirent.d_off = (cookiep)
403 				    ? (l_off_t)*cookiep
404 				    : (l_off_t)(off + reclen);
405 				linux_dirent.d_reclen = (l_ushort)linuxreclen;
406 				strcpy(linux_dirent.d_name, bdp->d_name);
407 				error = copyout(&linux_dirent, outp,
408 				    linuxreclen);
409 			}
410 		}
411 		if (error)
412 			goto out;
413 
414 		inp += reclen;
415 		if (cookiep) {
416 			off = *cookiep++;
417 			ncookies--;
418 		} else
419 			off += reclen;
420 
421 		outp += linuxreclen;
422 		resid -= linuxreclen;
423 		len -= reclen;
424 		if (justone)
425 			break;
426 	}
427 
428 	if (outp == (caddr_t)args->dirent)
429 		goto again;
430 
431 	fp->f_offset = off;
432 	if (justone)
433 		nbytes = resid + linuxreclen;
434 
435 eof:
436 	td->td_retval[0] = nbytes - resid;
437 
438 out:
439 	if (cookies)
440 		free(cookies, M_TEMP);
441 
442 	VOP_UNLOCK(vp, 0, td);
443 	fdrop(fp, td);
444 	free(buf, M_TEMP);
445 	return (error);
446 }
447 
448 int
449 linux_getdents(struct thread *td, struct linux_getdents_args *args)
450 {
451 
452 #ifdef DEBUG
453 	if (ldebug(getdents))
454 		printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count);
455 #endif
456 
457 	return (getdents_common(td, (struct linux_getdents64_args*)args, 0));
458 }
459 
460 int
461 linux_getdents64(struct thread *td, struct linux_getdents64_args *args)
462 {
463 
464 #ifdef DEBUG
465 	if (ldebug(getdents64))
466 		printf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count);
467 #endif
468 
469 	return (getdents_common(td, args, 1));
470 }
471 
472 /*
473  * These exist mainly for hooks for doing /compat/linux translation.
474  */
475 
476 int
477 linux_access(struct thread *td, struct linux_access_args *args)
478 {
479 	char *path;
480 	int error;
481 
482 	LCONVPATHEXIST(td, args->path, &path);
483 
484 #ifdef DEBUG
485 	if (ldebug(access))
486 		printf(ARGS(access, "%s, %d"), path, args->flags);
487 #endif
488 	error = kern_access(td, path, UIO_SYSSPACE, args->flags);
489 	LFREEPATH(path);
490 	return (error);
491 }
492 
493 int
494 linux_unlink(struct thread *td, struct linux_unlink_args *args)
495 {
496 	char *path;
497 	int error;
498 
499 	LCONVPATHEXIST(td, args->path, &path);
500 
501 #ifdef DEBUG
502 	if (ldebug(unlink))
503 		printf(ARGS(unlink, "%s"), path);
504 #endif
505 
506 	error = kern_unlink(td, path, UIO_SYSSPACE);
507 	LFREEPATH(path);
508 	return (error);
509 }
510 
511 int
512 linux_chdir(struct thread *td, struct linux_chdir_args *args)
513 {
514 	char *path;
515 	int error;
516 
517 	LCONVPATHEXIST(td, args->path, &path);
518 
519 #ifdef DEBUG
520 	if (ldebug(chdir))
521 		printf(ARGS(chdir, "%s"), path);
522 #endif
523 	error = kern_chdir(td, path, UIO_SYSSPACE);
524 	LFREEPATH(path);
525 	return (error);
526 }
527 
528 int
529 linux_chmod(struct thread *td, struct linux_chmod_args *args)
530 {
531 	char *path;
532 	int error;
533 
534 	LCONVPATHEXIST(td, args->path, &path);
535 
536 #ifdef DEBUG
537 	if (ldebug(chmod))
538 		printf(ARGS(chmod, "%s, %d"), path, args->mode);
539 #endif
540 	error = kern_chmod(td, path, UIO_SYSSPACE, args->mode);
541 	LFREEPATH(path);
542 	return (error);
543 }
544 
545 int
546 linux_mkdir(struct thread *td, struct linux_mkdir_args *args)
547 {
548 	char *path;
549 	int error;
550 
551 	LCONVPATHCREAT(td, args->path, &path);
552 
553 #ifdef DEBUG
554 	if (ldebug(mkdir))
555 		printf(ARGS(mkdir, "%s, %d"), path, args->mode);
556 #endif
557 	error = kern_mkdir(td, path, UIO_SYSSPACE, args->mode);
558 	LFREEPATH(path);
559 	return (error);
560 }
561 
562 int
563 linux_rmdir(struct thread *td, struct linux_rmdir_args *args)
564 {
565 	char *path;
566 	int error;
567 
568 	LCONVPATHEXIST(td, args->path, &path);
569 
570 #ifdef DEBUG
571 	if (ldebug(rmdir))
572 		printf(ARGS(rmdir, "%s"), path);
573 #endif
574 	error = kern_rmdir(td, path, UIO_SYSSPACE);
575 	LFREEPATH(path);
576 	return (error);
577 }
578 
579 int
580 linux_rename(struct thread *td, struct linux_rename_args *args)
581 {
582 	char *from, *to;
583 	int error;
584 
585 	LCONVPATHEXIST(td, args->from, &from);
586 	/* Expand LCONVPATHCREATE so that `from' can be freed on errors */
587 	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1);
588 	if (to == NULL) {
589 		LFREEPATH(from);
590 		return (error);
591 	}
592 
593 #ifdef DEBUG
594 	if (ldebug(rename))
595 		printf(ARGS(rename, "%s, %s"), from, to);
596 #endif
597 	error = kern_rename(td, from, to, UIO_SYSSPACE);
598 	LFREEPATH(from);
599 	LFREEPATH(to);
600 	return (error);
601 }
602 
603 int
604 linux_symlink(struct thread *td, struct linux_symlink_args *args)
605 {
606 	char *path, *to;
607 	int error;
608 
609 	LCONVPATHEXIST(td, args->path, &path);
610 	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
611 	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1);
612 	if (to == NULL) {
613 		LFREEPATH(path);
614 		return (error);
615 	}
616 
617 #ifdef DEBUG
618 	if (ldebug(symlink))
619 		printf(ARGS(symlink, "%s, %s"), path, to);
620 #endif
621 	error = kern_symlink(td, path, to, UIO_SYSSPACE);
622 	LFREEPATH(path);
623 	LFREEPATH(to);
624 	return (error);
625 }
626 
627 int
628 linux_readlink(struct thread *td, struct linux_readlink_args *args)
629 {
630 	char *name;
631 	int error;
632 
633 	LCONVPATHEXIST(td, args->name, &name);
634 
635 #ifdef DEBUG
636 	if (ldebug(readlink))
637 		printf(ARGS(readlink, "%s, %p, %d"), name, (void *)args->buf,
638 		    args->count);
639 #endif
640 	error = kern_readlink(td, name, UIO_SYSSPACE, args->buf, UIO_USERSPACE,
641 	    args->count);
642 	LFREEPATH(name);
643 	return (error);
644 }
645 
646 int
647 linux_truncate(struct thread *td, struct linux_truncate_args *args)
648 {
649 	char *path;
650 	int error;
651 
652 	LCONVPATHEXIST(td, args->path, &path);
653 
654 #ifdef DEBUG
655 	if (ldebug(truncate))
656 		printf(ARGS(truncate, "%s, %ld"), path, (long)args->length);
657 #endif
658 
659 	error = kern_truncate(td, path, UIO_SYSSPACE, args->length);
660 	LFREEPATH(path);
661 	return (error);
662 }
663 
664 int
665 linux_link(struct thread *td, struct linux_link_args *args)
666 {
667 	char *path, *to;
668 	int error;
669 
670 	LCONVPATHEXIST(td, args->path, &path);
671 	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
672 	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1);
673 	if (to == NULL) {
674 		LFREEPATH(path);
675 		return (error);
676 	}
677 
678 #ifdef DEBUG
679 	if (ldebug(link))
680 		printf(ARGS(link, "%s, %s"), path, to);
681 #endif
682 	error = kern_link(td, path, to, UIO_SYSSPACE);
683 	LFREEPATH(path);
684 	LFREEPATH(to);
685 	return (error);
686 }
687 
688 #ifndef __alpha__
689 int
690 linux_fdatasync(td, uap)
691 	struct thread *td;
692 	struct linux_fdatasync_args *uap;
693 {
694 	struct fsync_args bsd;
695 
696 	bsd.fd = uap->fd;
697 	return fsync(td, &bsd);
698 }
699 #endif /*!__alpha__*/
700 
701 int
702 linux_pread(td, uap)
703 	struct thread *td;
704 	struct linux_pread_args *uap;
705 {
706 	struct pread_args bsd;
707 
708 	bsd.fd = uap->fd;
709 	bsd.buf = uap->buf;
710 	bsd.nbyte = uap->nbyte;
711 	bsd.offset = uap->offset;
712 	return pread(td, &bsd);
713 }
714 
715 int
716 linux_pwrite(td, uap)
717 	struct thread *td;
718 	struct linux_pwrite_args *uap;
719 {
720 	struct pwrite_args bsd;
721 
722 	bsd.fd = uap->fd;
723 	bsd.buf = uap->buf;
724 	bsd.nbyte = uap->nbyte;
725 	bsd.offset = uap->offset;
726 	return pwrite(td, &bsd);
727 }
728 
729 int
730 linux_mount(struct thread *td, struct linux_mount_args *args)
731 {
732 	struct ufs_args ufs;
733 	char fstypename[MFSNAMELEN];
734 	char mntonname[MNAMELEN], mntfromname[MNAMELEN];
735 	struct uio auio;
736 	struct iovec iov[4];
737 	int error;
738 	int fsflags;
739 	void *fsdata;
740 
741 	error = copyinstr(args->filesystemtype, fstypename, MFSNAMELEN - 1,
742 	    NULL);
743 	if (error)
744 		return (error);
745 	error = copyinstr(args->specialfile, mntfromname, MNAMELEN - 1, NULL);
746 	if (error)
747 		return (error);
748 	error = copyinstr(args->dir, mntonname, MNAMELEN - 1, NULL);
749 	if (error)
750 		return (error);
751 
752 #ifdef DEBUG
753 	if (ldebug(mount))
754 		printf(ARGS(mount, "%s, %s, %s"),
755 		    fstypename, mntfromname, mntonname);
756 #endif
757 
758 	if (strcmp(fstypename, "ext2") == 0) {
759 		strcpy(fstypename, "ext2fs");
760 		fsdata = &ufs;
761 		ufs.fspec = mntfromname;
762 #define DEFAULT_ROOTID		-2
763 		ufs.export.ex_root = DEFAULT_ROOTID;
764 		ufs.export.ex_flags =
765 		    args->rwflag & LINUX_MS_RDONLY ? MNT_EXRDONLY : 0;
766 	} else if (strcmp(fstypename, "proc") == 0) {
767 		strcpy(fstypename, "linprocfs");
768 		fsdata = NULL;
769 	} else {
770 		return (ENODEV);
771 	}
772 
773 	fsflags = 0;
774 
775 	if ((args->rwflag & 0xffff0000) == 0xc0ed0000) {
776 		/*
777 		 * Linux SYNC flag is not included; the closest equivalent
778 		 * FreeBSD has is !ASYNC, which is our default.
779 		 */
780 		if (args->rwflag & LINUX_MS_RDONLY)
781 			fsflags |= MNT_RDONLY;
782 		if (args->rwflag & LINUX_MS_NOSUID)
783 			fsflags |= MNT_NOSUID;
784 		if (args->rwflag & LINUX_MS_NODEV)
785 			fsflags |= MNT_NODEV;
786 		if (args->rwflag & LINUX_MS_NOEXEC)
787 			fsflags |= MNT_NOEXEC;
788 		if (args->rwflag & LINUX_MS_REMOUNT)
789 			fsflags |= MNT_UPDATE;
790 	}
791 
792 	if (strcmp(fstypename, "linprocfs") == 0) {
793 		bzero(&auio, sizeof(auio));
794 		auio.uio_iov = iov;
795 		auio.uio_iovcnt = sizeof(iov) / sizeof(*iov);
796 		auio.uio_segflg = UIO_SYSSPACE;
797 		iov[0].iov_base = "fstype";
798 		iov[0].iov_len = sizeof("fstype");
799 		iov[1].iov_base = fstypename;
800 		iov[1].iov_len = strlen(fstypename) + 1;
801 		iov[2].iov_base = "fspath";
802 		iov[2].iov_len = sizeof("fspath");
803 		iov[3].iov_base = mntonname;
804 		iov[3].iov_len = strlen(mntonname) + 1;
805 		error = vfs_nmount(td, fsflags, &auio);
806 	} else
807 		error = vfs_mount(td, fstypename, mntonname, fsflags, fsdata);
808 	return (error);
809 }
810 
811 int
812 linux_oldumount(struct thread *td, struct linux_oldumount_args *args)
813 {
814 	struct linux_umount_args args2;
815 
816 	args2.path = args->path;
817 	args2.flags = 0;
818 	return (linux_umount(td, &args2));
819 }
820 
821 int
822 linux_umount(struct thread *td, struct linux_umount_args *args)
823 {
824 	struct unmount_args bsd;
825 
826 	bsd.path = args->path;
827 	bsd.flags = args->flags;	/* XXX correct? */
828 	return (unmount(td, &bsd));
829 }
830 
831 /*
832  * fcntl family of syscalls
833  */
834 
835 struct l_flock {
836 	l_short		l_type;
837 	l_short		l_whence;
838 	l_off_t		l_start;
839 	l_off_t		l_len;
840 	l_pid_t		l_pid;
841 };
842 
843 static void
844 linux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock)
845 {
846 	switch (linux_flock->l_type) {
847 	case LINUX_F_RDLCK:
848 		bsd_flock->l_type = F_RDLCK;
849 		break;
850 	case LINUX_F_WRLCK:
851 		bsd_flock->l_type = F_WRLCK;
852 		break;
853 	case LINUX_F_UNLCK:
854 		bsd_flock->l_type = F_UNLCK;
855 		break;
856 	default:
857 		bsd_flock->l_type = -1;
858 		break;
859 	}
860 	bsd_flock->l_whence = linux_flock->l_whence;
861 	bsd_flock->l_start = (off_t)linux_flock->l_start;
862 	bsd_flock->l_len = (off_t)linux_flock->l_len;
863 	bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
864 }
865 
866 static void
867 bsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock)
868 {
869 	switch (bsd_flock->l_type) {
870 	case F_RDLCK:
871 		linux_flock->l_type = LINUX_F_RDLCK;
872 		break;
873 	case F_WRLCK:
874 		linux_flock->l_type = LINUX_F_WRLCK;
875 		break;
876 	case F_UNLCK:
877 		linux_flock->l_type = LINUX_F_UNLCK;
878 		break;
879 	}
880 	linux_flock->l_whence = bsd_flock->l_whence;
881 	linux_flock->l_start = (l_off_t)bsd_flock->l_start;
882 	linux_flock->l_len = (l_off_t)bsd_flock->l_len;
883 	linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
884 }
885 
886 #if defined(__i386__)
887 struct l_flock64 {
888 	l_short		l_type;
889 	l_short		l_whence;
890 	l_loff_t	l_start;
891 	l_loff_t	l_len;
892 	l_pid_t		l_pid;
893 };
894 
895 static void
896 linux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock)
897 {
898 	switch (linux_flock->l_type) {
899 	case LINUX_F_RDLCK:
900 		bsd_flock->l_type = F_RDLCK;
901 		break;
902 	case LINUX_F_WRLCK:
903 		bsd_flock->l_type = F_WRLCK;
904 		break;
905 	case LINUX_F_UNLCK:
906 		bsd_flock->l_type = F_UNLCK;
907 		break;
908 	default:
909 		bsd_flock->l_type = -1;
910 		break;
911 	}
912 	bsd_flock->l_whence = linux_flock->l_whence;
913 	bsd_flock->l_start = (off_t)linux_flock->l_start;
914 	bsd_flock->l_len = (off_t)linux_flock->l_len;
915 	bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
916 }
917 
918 static void
919 bsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock)
920 {
921 	switch (bsd_flock->l_type) {
922 	case F_RDLCK:
923 		linux_flock->l_type = LINUX_F_RDLCK;
924 		break;
925 	case F_WRLCK:
926 		linux_flock->l_type = LINUX_F_WRLCK;
927 		break;
928 	case F_UNLCK:
929 		linux_flock->l_type = LINUX_F_UNLCK;
930 		break;
931 	}
932 	linux_flock->l_whence = bsd_flock->l_whence;
933 	linux_flock->l_start = (l_loff_t)bsd_flock->l_start;
934 	linux_flock->l_len = (l_loff_t)bsd_flock->l_len;
935 	linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
936 }
937 #endif /* __i386__ */
938 
939 #if defined(__alpha__)
940 #define	linux_fcntl64_args	linux_fcntl_args
941 #endif
942 
943 static int
944 fcntl_common(struct thread *td, struct linux_fcntl64_args *args)
945 {
946 	struct l_flock linux_flock;
947 	struct flock bsd_flock;
948 	struct file *fp;
949 	long arg;
950 	int error, result;
951 
952 	switch (args->cmd) {
953 	case LINUX_F_DUPFD:
954 		return (kern_fcntl(td, args->fd, F_DUPFD, args->arg));
955 
956 	case LINUX_F_GETFD:
957 		return (kern_fcntl(td, args->fd, F_GETFD, 0));
958 
959 	case LINUX_F_SETFD:
960 		return (kern_fcntl(td, args->fd, F_SETFD, args->arg));
961 
962 	case LINUX_F_GETFL:
963 		error = kern_fcntl(td, args->fd, F_GETFL, 0);
964 		result = td->td_retval[0];
965 		td->td_retval[0] = 0;
966 		if (result & O_RDONLY)
967 			td->td_retval[0] |= LINUX_O_RDONLY;
968 		if (result & O_WRONLY)
969 			td->td_retval[0] |= LINUX_O_WRONLY;
970 		if (result & O_RDWR)
971 			td->td_retval[0] |= LINUX_O_RDWR;
972 		if (result & O_NDELAY)
973 			td->td_retval[0] |= LINUX_O_NONBLOCK;
974 		if (result & O_APPEND)
975 			td->td_retval[0] |= LINUX_O_APPEND;
976 		if (result & O_FSYNC)
977 			td->td_retval[0] |= LINUX_O_SYNC;
978 		if (result & O_ASYNC)
979 			td->td_retval[0] |= LINUX_FASYNC;
980 		return (error);
981 
982 	case LINUX_F_SETFL:
983 		arg = 0;
984 		if (args->arg & LINUX_O_NDELAY)
985 			arg |= O_NONBLOCK;
986 		if (args->arg & LINUX_O_APPEND)
987 			arg |= O_APPEND;
988 		if (args->arg & LINUX_O_SYNC)
989 			arg |= O_FSYNC;
990 		if (args->arg & LINUX_FASYNC)
991 			arg |= O_ASYNC;
992 		return (kern_fcntl(td, args->fd, F_SETFL, arg));
993 
994 	case LINUX_F_GETLK:
995 		error = copyin((void *)args->arg, &linux_flock,
996 		    sizeof(linux_flock));
997 		if (error)
998 			return (error);
999 		linux_to_bsd_flock(&linux_flock, &bsd_flock);
1000 		error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock);
1001 		if (error)
1002 			return (error);
1003 		bsd_to_linux_flock(&bsd_flock, &linux_flock);
1004 		return (copyout(&linux_flock, (void *)args->arg,
1005 		    sizeof(linux_flock)));
1006 
1007 	case LINUX_F_SETLK:
1008 		error = copyin((void *)args->arg, &linux_flock,
1009 		    sizeof(linux_flock));
1010 		if (error)
1011 			return (error);
1012 		linux_to_bsd_flock(&linux_flock, &bsd_flock);
1013 		return (kern_fcntl(td, args->fd, F_SETLK,
1014 		    (intptr_t)&bsd_flock));
1015 
1016 	case LINUX_F_SETLKW:
1017 		error = copyin((void *)args->arg, &linux_flock,
1018 		    sizeof(linux_flock));
1019 		if (error)
1020 			return (error);
1021 		linux_to_bsd_flock(&linux_flock, &bsd_flock);
1022 		return (kern_fcntl(td, args->fd, F_SETLKW,
1023 		     (intptr_t)&bsd_flock));
1024 
1025 	case LINUX_F_GETOWN:
1026 		return (kern_fcntl(td, args->fd, F_GETOWN, 0));
1027 
1028 	case LINUX_F_SETOWN:
1029 		/*
1030 		 * XXX some Linux applications depend on F_SETOWN having no
1031 		 * significant effect for pipes (SIGIO is not delivered for
1032 		 * pipes under Linux-2.2.35 at least).
1033 		 */
1034 		error = fget(td, args->fd, &fp);
1035 		if (error)
1036 			return (error);
1037 		if (fp->f_type == DTYPE_PIPE) {
1038 			fdrop(fp, td);
1039 			return (EINVAL);
1040 		}
1041 		fdrop(fp, td);
1042 
1043 		return (kern_fcntl(td, args->fd, F_SETOWN, args->arg));
1044 	}
1045 
1046 	return (EINVAL);
1047 }
1048 
1049 int
1050 linux_fcntl(struct thread *td, struct linux_fcntl_args *args)
1051 {
1052 	struct linux_fcntl64_args args64;
1053 
1054 #ifdef DEBUG
1055 	if (ldebug(fcntl))
1056 		printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd);
1057 #endif
1058 
1059 	args64.fd = args->fd;
1060 	args64.cmd = args->cmd;
1061 	args64.arg = args->arg;
1062 	return (fcntl_common(td, &args64));
1063 }
1064 
1065 #if defined(__i386__)
1066 int
1067 linux_fcntl64(struct thread *td, struct linux_fcntl64_args *args)
1068 {
1069 	struct l_flock64 linux_flock;
1070 	struct flock bsd_flock;
1071 	int error;
1072 
1073 #ifdef DEBUG
1074 	if (ldebug(fcntl64))
1075 		printf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd);
1076 #endif
1077 
1078 	switch (args->cmd) {
1079 	case LINUX_F_GETLK64:
1080 		error = copyin((void *)args->arg, &linux_flock,
1081 		    sizeof(linux_flock));
1082 		if (error)
1083 			return (error);
1084 		linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1085 		error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock);
1086 		if (error)
1087 			return (error);
1088 		bsd_to_linux_flock64(&bsd_flock, &linux_flock);
1089 		return (copyout(&linux_flock, (void *)args->arg,
1090 			    sizeof(linux_flock)));
1091 
1092 	case LINUX_F_SETLK64:
1093 		error = copyin((void *)args->arg, &linux_flock,
1094 		    sizeof(linux_flock));
1095 		if (error)
1096 			return (error);
1097 		linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1098 		return (kern_fcntl(td, args->fd, F_SETLK,
1099 		    (intptr_t)&bsd_flock));
1100 
1101 	case LINUX_F_SETLKW64:
1102 		error = copyin((void *)args->arg, &linux_flock,
1103 		    sizeof(linux_flock));
1104 		if (error)
1105 			return (error);
1106 		linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1107 		return (kern_fcntl(td, args->fd, F_SETLKW,
1108 		    (intptr_t)&bsd_flock));
1109 	}
1110 
1111 	return (fcntl_common(td, args));
1112 }
1113 #endif /* __i386__ */
1114 
1115 int
1116 linux_chown(struct thread *td, struct linux_chown_args *args)
1117 {
1118 	char *path;
1119 	int error;
1120 
1121 	LCONVPATHEXIST(td, args->path, &path);
1122 
1123 #ifdef DEBUG
1124 	if (ldebug(chown))
1125 		printf(ARGS(chown, "%s, %d, %d"), path, args->uid, args->gid);
1126 #endif
1127 	error = kern_chown(td, path, UIO_SYSSPACE, args->uid, args->gid);
1128 	LFREEPATH(path);
1129 	return (error);
1130 }
1131 
1132 int
1133 linux_lchown(struct thread *td, struct linux_lchown_args *args)
1134 {
1135 	char *path;
1136 	int error;
1137 
1138 	LCONVPATHEXIST(td, args->path, &path);
1139 
1140 #ifdef DEBUG
1141 	if (ldebug(lchown))
1142 		printf(ARGS(lchown, "%s, %d, %d"), path, args->uid, args->gid);
1143 #endif
1144 	error = kern_lchown(td, path, UIO_SYSSPACE, args->uid, args->gid);
1145 	LFREEPATH(path);
1146 	return (error);
1147 }
1148