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