xref: /freebsd/sys/compat/linux/linux_file.c (revision d72a078647de20e31ab09295e671f1b8b4ad89b2)
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/stat.h>
49 #include <sys/syscallsubr.h>
50 #include <sys/sysproto.h>
51 #include <sys/tty.h>
52 #include <sys/vnode.h>
53 
54 #include <ufs/ufs/extattr.h>
55 #include <ufs/ufs/quota.h>
56 #include <ufs/ufs/ufsmount.h>
57 
58 #ifdef COMPAT_LINUX32
59 #include <machine/../linux32/linux.h>
60 #include <machine/../linux32/linux32_proto.h>
61 #else
62 #include <machine/../linux/linux.h>
63 #include <machine/../linux/linux_proto.h>
64 #endif
65 #include <compat/linux/linux_util.h>
66 
67 int
68 linux_creat(struct thread *td, struct linux_creat_args *args)
69 {
70     char *path;
71     int error;
72 
73     LCONVPATHEXIST(td, args->path, &path);
74 
75 #ifdef DEBUG
76 	if (ldebug(creat))
77 		printf(ARGS(creat, "%s, %d"), path, args->mode);
78 #endif
79     error = kern_open(td, path, UIO_SYSSPACE, O_WRONLY | O_CREAT | O_TRUNC,
80 	args->mode);
81     LFREEPATH(path);
82     return (error);
83 }
84 
85 int
86 linux_open(struct thread *td, struct linux_open_args *args)
87 {
88     struct proc *p = td->td_proc;
89     char *path;
90     int bsd_flags, error;
91 
92     if (args->flags & LINUX_O_CREAT)
93 	LCONVPATHCREAT(td, args->path, &path);
94     else
95 	LCONVPATHEXIST(td, args->path, &path);
96 
97 #ifdef DEBUG
98 	if (ldebug(open))
99 		printf(ARGS(open, "%s, 0x%x, 0x%x"),
100 		    path, args->flags, args->mode);
101 #endif
102     bsd_flags = 0;
103     if (args->flags & LINUX_O_RDONLY)
104 	bsd_flags |= O_RDONLY;
105     if (args->flags & LINUX_O_WRONLY)
106 	bsd_flags |= O_WRONLY;
107     if (args->flags & LINUX_O_RDWR)
108 	bsd_flags |= O_RDWR;
109     if (args->flags & LINUX_O_NDELAY)
110 	bsd_flags |= O_NONBLOCK;
111     if (args->flags & LINUX_O_APPEND)
112 	bsd_flags |= O_APPEND;
113     if (args->flags & LINUX_O_SYNC)
114 	bsd_flags |= O_FSYNC;
115     if (args->flags & LINUX_O_NONBLOCK)
116 	bsd_flags |= O_NONBLOCK;
117     if (args->flags & LINUX_FASYNC)
118 	bsd_flags |= O_ASYNC;
119     if (args->flags & LINUX_O_CREAT)
120 	bsd_flags |= O_CREAT;
121     if (args->flags & LINUX_O_TRUNC)
122 	bsd_flags |= O_TRUNC;
123     if (args->flags & LINUX_O_EXCL)
124 	bsd_flags |= O_EXCL;
125     if (args->flags & LINUX_O_NOCTTY)
126 	bsd_flags |= O_NOCTTY;
127 
128     error = kern_open(td, path, UIO_SYSSPACE, bsd_flags, args->mode);
129     PROC_LOCK(p);
130     if (!error && !(bsd_flags & O_NOCTTY) &&
131 	SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
132 	struct file *fp;
133 
134 	PROC_UNLOCK(p);
135 	error = fget(td, td->td_retval[0], &fp);
136 	if (!error) {
137 		if (fp->f_type == DTYPE_VNODE)
138 			fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0, td->td_ucred,
139 			    td);
140 	    fdrop(fp, td);
141 	}
142     } else {
143 	PROC_UNLOCK(p);
144 #ifdef DEBUG
145 	if (ldebug(open))
146 		printf(LMSG("open returns error %d"), error);
147 #endif
148     }
149     LFREEPATH(path);
150     return error;
151 }
152 
153 int
154 linux_lseek(struct thread *td, struct linux_lseek_args *args)
155 {
156 
157     struct lseek_args /* {
158 	int fd;
159 	int pad;
160 	off_t offset;
161 	int whence;
162     } */ tmp_args;
163     int error;
164 
165 #ifdef DEBUG
166 	if (ldebug(lseek))
167 		printf(ARGS(lseek, "%d, %ld, %d"),
168 		    args->fdes, (long)args->off, args->whence);
169 #endif
170     tmp_args.fd = args->fdes;
171     tmp_args.offset = (off_t)args->off;
172     tmp_args.whence = args->whence;
173     error = lseek(td, &tmp_args);
174     return error;
175 }
176 
177 int
178 linux_llseek(struct thread *td, struct linux_llseek_args *args)
179 {
180 	struct lseek_args bsd_args;
181 	int error;
182 	off_t off;
183 
184 #ifdef DEBUG
185 	if (ldebug(llseek))
186 		printf(ARGS(llseek, "%d, %d:%d, %d"),
187 		    args->fd, args->ohigh, args->olow, args->whence);
188 #endif
189 	off = (args->olow) | (((off_t) args->ohigh) << 32);
190 
191 	bsd_args.fd = args->fd;
192 	bsd_args.offset = off;
193 	bsd_args.whence = args->whence;
194 
195 	if ((error = lseek(td, &bsd_args)))
196 		return error;
197 
198 	if ((error = copyout(td->td_retval, args->res, sizeof (off_t))))
199 		return error;
200 
201 	td->td_retval[0] = 0;
202 	return 0;
203 }
204 
205 int
206 linux_readdir(struct thread *td, struct linux_readdir_args *args)
207 {
208 	struct linux_getdents_args lda;
209 
210 	lda.fd = args->fd;
211 	lda.dent = args->dent;
212 	lda.count = 1;
213 	return linux_getdents(td, &lda);
214 }
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, vfslocked;
264 
265 	nbytes = args->count;
266 	if (nbytes == 1) {
267 		/* readdir(2) case. Always struct dirent. */
268 		if (is64bit)
269 			return (EINVAL);
270 		nbytes = sizeof(linux_dirent);
271 		justone = 1;
272 	} else
273 		justone = 0;
274 
275 	if ((error = getvnode(td->td_proc->p_fd, args->fd, &fp)) != 0)
276 		return (error);
277 
278 	if ((fp->f_flag & FREAD) == 0) {
279 		fdrop(fp, td);
280 		return (EBADF);
281 	}
282 
283 	vp = fp->f_vnode;
284 	vfslocked = VFS_LOCK_GIANT(vp->v_mount);
285 	if (vp->v_type != VDIR) {
286 		VFS_UNLOCK_GIANT(vfslocked);
287 		fdrop(fp, td);
288 		return (EINVAL);
289 	}
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 	VFS_UNLOCK_GIANT(vfslocked);
444 	fdrop(fp, td);
445 	free(buf, M_TEMP);
446 	return (error);
447 }
448 
449 int
450 linux_getdents(struct thread *td, struct linux_getdents_args *args)
451 {
452 
453 #ifdef DEBUG
454 	if (ldebug(getdents))
455 		printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count);
456 #endif
457 
458 	return (getdents_common(td, (struct linux_getdents64_args*)args, 0));
459 }
460 
461 int
462 linux_getdents64(struct thread *td, struct linux_getdents64_args *args)
463 {
464 
465 #ifdef DEBUG
466 	if (ldebug(getdents64))
467 		printf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count);
468 #endif
469 
470 	return (getdents_common(td, args, 1));
471 }
472 
473 /*
474  * These exist mainly for hooks for doing /compat/linux translation.
475  */
476 
477 int
478 linux_access(struct thread *td, struct linux_access_args *args)
479 {
480 	char *path;
481 	int error;
482 
483 	LCONVPATHEXIST(td, args->path, &path);
484 
485 #ifdef DEBUG
486 	if (ldebug(access))
487 		printf(ARGS(access, "%s, %d"), path, args->flags);
488 #endif
489 	error = kern_access(td, path, UIO_SYSSPACE, args->flags);
490 	LFREEPATH(path);
491 	return (error);
492 }
493 
494 int
495 linux_unlink(struct thread *td, struct linux_unlink_args *args)
496 {
497 	char *path;
498 	int error;
499 	struct stat st;
500 
501 	LCONVPATHEXIST(td, args->path, &path);
502 
503 #ifdef DEBUG
504 	if (ldebug(unlink))
505 		printf(ARGS(unlink, "%s"), path);
506 #endif
507 
508 	error = kern_unlink(td, path, UIO_SYSSPACE);
509 	if (error == EPERM)
510 		/* Introduce POSIX noncompliant behaviour of Linux */
511 		if (kern_stat(td, path, UIO_SYSSPACE, &st) == 0)
512 			if (S_ISDIR(st.st_mode))
513 				error = EISDIR;
514 	LFREEPATH(path);
515 	return (error);
516 }
517 
518 int
519 linux_chdir(struct thread *td, struct linux_chdir_args *args)
520 {
521 	char *path;
522 	int error;
523 
524 	LCONVPATHEXIST(td, args->path, &path);
525 
526 #ifdef DEBUG
527 	if (ldebug(chdir))
528 		printf(ARGS(chdir, "%s"), path);
529 #endif
530 	error = kern_chdir(td, path, UIO_SYSSPACE);
531 	LFREEPATH(path);
532 	return (error);
533 }
534 
535 int
536 linux_chmod(struct thread *td, struct linux_chmod_args *args)
537 {
538 	char *path;
539 	int error;
540 
541 	LCONVPATHEXIST(td, args->path, &path);
542 
543 #ifdef DEBUG
544 	if (ldebug(chmod))
545 		printf(ARGS(chmod, "%s, %d"), path, args->mode);
546 #endif
547 	error = kern_chmod(td, path, UIO_SYSSPACE, args->mode);
548 	LFREEPATH(path);
549 	return (error);
550 }
551 
552 int
553 linux_mkdir(struct thread *td, struct linux_mkdir_args *args)
554 {
555 	char *path;
556 	int error;
557 
558 	LCONVPATHCREAT(td, args->path, &path);
559 
560 #ifdef DEBUG
561 	if (ldebug(mkdir))
562 		printf(ARGS(mkdir, "%s, %d"), path, args->mode);
563 #endif
564 	error = kern_mkdir(td, path, UIO_SYSSPACE, args->mode);
565 	LFREEPATH(path);
566 	return (error);
567 }
568 
569 int
570 linux_rmdir(struct thread *td, struct linux_rmdir_args *args)
571 {
572 	char *path;
573 	int error;
574 
575 	LCONVPATHEXIST(td, args->path, &path);
576 
577 #ifdef DEBUG
578 	if (ldebug(rmdir))
579 		printf(ARGS(rmdir, "%s"), path);
580 #endif
581 	error = kern_rmdir(td, path, UIO_SYSSPACE);
582 	LFREEPATH(path);
583 	return (error);
584 }
585 
586 int
587 linux_rename(struct thread *td, struct linux_rename_args *args)
588 {
589 	char *from, *to;
590 	int error;
591 
592 	LCONVPATHEXIST(td, args->from, &from);
593 	/* Expand LCONVPATHCREATE so that `from' can be freed on errors */
594 	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1);
595 	if (to == NULL) {
596 		LFREEPATH(from);
597 		return (error);
598 	}
599 
600 #ifdef DEBUG
601 	if (ldebug(rename))
602 		printf(ARGS(rename, "%s, %s"), from, to);
603 #endif
604 	error = kern_rename(td, from, to, UIO_SYSSPACE);
605 	LFREEPATH(from);
606 	LFREEPATH(to);
607 	return (error);
608 }
609 
610 int
611 linux_symlink(struct thread *td, struct linux_symlink_args *args)
612 {
613 	char *path, *to;
614 	int error;
615 
616 	LCONVPATHEXIST(td, args->path, &path);
617 	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
618 	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1);
619 	if (to == NULL) {
620 		LFREEPATH(path);
621 		return (error);
622 	}
623 
624 #ifdef DEBUG
625 	if (ldebug(symlink))
626 		printf(ARGS(symlink, "%s, %s"), path, to);
627 #endif
628 	error = kern_symlink(td, path, to, UIO_SYSSPACE);
629 	LFREEPATH(path);
630 	LFREEPATH(to);
631 	return (error);
632 }
633 
634 int
635 linux_readlink(struct thread *td, struct linux_readlink_args *args)
636 {
637 	char *name;
638 	int error;
639 
640 	LCONVPATHEXIST(td, args->name, &name);
641 
642 #ifdef DEBUG
643 	if (ldebug(readlink))
644 		printf(ARGS(readlink, "%s, %p, %d"), name, (void *)args->buf,
645 		    args->count);
646 #endif
647 	error = kern_readlink(td, name, UIO_SYSSPACE, args->buf, UIO_USERSPACE,
648 	    args->count);
649 	LFREEPATH(name);
650 	return (error);
651 }
652 
653 int
654 linux_truncate(struct thread *td, struct linux_truncate_args *args)
655 {
656 	char *path;
657 	int error;
658 
659 	LCONVPATHEXIST(td, args->path, &path);
660 
661 #ifdef DEBUG
662 	if (ldebug(truncate))
663 		printf(ARGS(truncate, "%s, %ld"), path, (long)args->length);
664 #endif
665 
666 	error = kern_truncate(td, path, UIO_SYSSPACE, args->length);
667 	LFREEPATH(path);
668 	return (error);
669 }
670 
671 int
672 linux_ftruncate(struct thread *td, struct linux_ftruncate_args *args)
673 {
674 	struct ftruncate_args /* {
675 		int fd;
676 		int pad;
677 		off_t length;
678 		} */ nuap;
679 
680 	nuap.fd = args->fd;
681 	nuap.pad = 0;
682 	nuap.length = args->length;
683 	return (ftruncate(td, &nuap));
684 }
685 
686 int
687 linux_link(struct thread *td, struct linux_link_args *args)
688 {
689 	char *path, *to;
690 	int error;
691 
692 	LCONVPATHEXIST(td, args->path, &path);
693 	/* Expand LCONVPATHCREATE so that `path' can be freed on errors */
694 	error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1);
695 	if (to == NULL) {
696 		LFREEPATH(path);
697 		return (error);
698 	}
699 
700 #ifdef DEBUG
701 	if (ldebug(link))
702 		printf(ARGS(link, "%s, %s"), path, to);
703 #endif
704 	error = kern_link(td, path, to, UIO_SYSSPACE);
705 	LFREEPATH(path);
706 	LFREEPATH(to);
707 	return (error);
708 }
709 
710 int
711 linux_fdatasync(td, uap)
712 	struct thread *td;
713 	struct linux_fdatasync_args *uap;
714 {
715 	struct fsync_args bsd;
716 
717 	bsd.fd = uap->fd;
718 	return fsync(td, &bsd);
719 }
720 
721 int
722 linux_pread(td, uap)
723 	struct thread *td;
724 	struct linux_pread_args *uap;
725 {
726 	struct pread_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 pread(td, &bsd);
733 }
734 
735 int
736 linux_pwrite(td, uap)
737 	struct thread *td;
738 	struct linux_pwrite_args *uap;
739 {
740 	struct pwrite_args bsd;
741 
742 	bsd.fd = uap->fd;
743 	bsd.buf = uap->buf;
744 	bsd.nbyte = uap->nbyte;
745 	bsd.offset = uap->offset;
746 	return pwrite(td, &bsd);
747 }
748 
749 int
750 linux_mount(struct thread *td, struct linux_mount_args *args)
751 {
752 	struct ufs_args ufs;
753 	char fstypename[MFSNAMELEN];
754 	char mntonname[MNAMELEN], mntfromname[MNAMELEN];
755 	int error;
756 	int fsflags;
757 	void *fsdata;
758 
759 	error = copyinstr(args->filesystemtype, fstypename, MFSNAMELEN - 1,
760 	    NULL);
761 	if (error)
762 		return (error);
763 	error = copyinstr(args->specialfile, mntfromname, MNAMELEN - 1, NULL);
764 	if (error)
765 		return (error);
766 	error = copyinstr(args->dir, mntonname, MNAMELEN - 1, NULL);
767 	if (error)
768 		return (error);
769 
770 #ifdef DEBUG
771 	if (ldebug(mount))
772 		printf(ARGS(mount, "%s, %s, %s"),
773 		    fstypename, mntfromname, mntonname);
774 #endif
775 
776 	if (strcmp(fstypename, "ext2") == 0) {
777 		strcpy(fstypename, "ext2fs");
778 		fsdata = &ufs;
779 		ufs.fspec = mntfromname;
780 #define DEFAULT_ROOTID		-2
781 		ufs.export.ex_root = DEFAULT_ROOTID;
782 		ufs.export.ex_flags =
783 		    args->rwflag & LINUX_MS_RDONLY ? MNT_EXRDONLY : 0;
784 	} else if (strcmp(fstypename, "proc") == 0) {
785 		strcpy(fstypename, "linprocfs");
786 		fsdata = NULL;
787 	} else {
788 		return (ENODEV);
789 	}
790 
791 	fsflags = 0;
792 
793 	if ((args->rwflag & 0xffff0000) == 0xc0ed0000) {
794 		/*
795 		 * Linux SYNC flag is not included; the closest equivalent
796 		 * FreeBSD has is !ASYNC, which is our default.
797 		 */
798 		if (args->rwflag & LINUX_MS_RDONLY)
799 			fsflags |= MNT_RDONLY;
800 		if (args->rwflag & LINUX_MS_NOSUID)
801 			fsflags |= MNT_NOSUID;
802 		if (args->rwflag & LINUX_MS_NOEXEC)
803 			fsflags |= MNT_NOEXEC;
804 		if (args->rwflag & LINUX_MS_REMOUNT)
805 			fsflags |= MNT_UPDATE;
806 	}
807 
808 	if (strcmp(fstypename, "linprocfs") == 0) {
809 		error = kernel_vmount(fsflags,
810 			"fstype", fstypename,
811 			"fspath", mntonname,
812 			NULL);
813 	} else
814 		error = EOPNOTSUPP;
815 	return (error);
816 }
817 
818 int
819 linux_oldumount(struct thread *td, struct linux_oldumount_args *args)
820 {
821 	struct linux_umount_args args2;
822 
823 	args2.path = args->path;
824 	args2.flags = 0;
825 	return (linux_umount(td, &args2));
826 }
827 
828 int
829 linux_umount(struct thread *td, struct linux_umount_args *args)
830 {
831 	struct unmount_args bsd;
832 
833 	bsd.path = args->path;
834 	bsd.flags = args->flags;	/* XXX correct? */
835 	return (unmount(td, &bsd));
836 }
837 
838 /*
839  * fcntl family of syscalls
840  */
841 
842 struct l_flock {
843 	l_short		l_type;
844 	l_short		l_whence;
845 	l_off_t		l_start;
846 	l_off_t		l_len;
847 	l_pid_t		l_pid;
848 }
849 #if defined(__amd64__) && defined(COMPAT_LINUX32)
850 __packed
851 #endif
852 ;
853 
854 static void
855 linux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock)
856 {
857 	switch (linux_flock->l_type) {
858 	case LINUX_F_RDLCK:
859 		bsd_flock->l_type = F_RDLCK;
860 		break;
861 	case LINUX_F_WRLCK:
862 		bsd_flock->l_type = F_WRLCK;
863 		break;
864 	case LINUX_F_UNLCK:
865 		bsd_flock->l_type = F_UNLCK;
866 		break;
867 	default:
868 		bsd_flock->l_type = -1;
869 		break;
870 	}
871 	bsd_flock->l_whence = linux_flock->l_whence;
872 	bsd_flock->l_start = (off_t)linux_flock->l_start;
873 	bsd_flock->l_len = (off_t)linux_flock->l_len;
874 	bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
875 }
876 
877 static void
878 bsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock)
879 {
880 	switch (bsd_flock->l_type) {
881 	case F_RDLCK:
882 		linux_flock->l_type = LINUX_F_RDLCK;
883 		break;
884 	case F_WRLCK:
885 		linux_flock->l_type = LINUX_F_WRLCK;
886 		break;
887 	case F_UNLCK:
888 		linux_flock->l_type = LINUX_F_UNLCK;
889 		break;
890 	}
891 	linux_flock->l_whence = bsd_flock->l_whence;
892 	linux_flock->l_start = (l_off_t)bsd_flock->l_start;
893 	linux_flock->l_len = (l_off_t)bsd_flock->l_len;
894 	linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
895 }
896 
897 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
898 struct l_flock64 {
899 	l_short		l_type;
900 	l_short		l_whence;
901 	l_loff_t	l_start;
902 	l_loff_t	l_len;
903 	l_pid_t		l_pid;
904 }
905 #if defined(__amd64__) && defined(COMPAT_LINUX32)
906 __packed
907 #endif
908 ;
909 
910 static void
911 linux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock)
912 {
913 	switch (linux_flock->l_type) {
914 	case LINUX_F_RDLCK:
915 		bsd_flock->l_type = F_RDLCK;
916 		break;
917 	case LINUX_F_WRLCK:
918 		bsd_flock->l_type = F_WRLCK;
919 		break;
920 	case LINUX_F_UNLCK:
921 		bsd_flock->l_type = F_UNLCK;
922 		break;
923 	default:
924 		bsd_flock->l_type = -1;
925 		break;
926 	}
927 	bsd_flock->l_whence = linux_flock->l_whence;
928 	bsd_flock->l_start = (off_t)linux_flock->l_start;
929 	bsd_flock->l_len = (off_t)linux_flock->l_len;
930 	bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
931 }
932 
933 static void
934 bsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock)
935 {
936 	switch (bsd_flock->l_type) {
937 	case F_RDLCK:
938 		linux_flock->l_type = LINUX_F_RDLCK;
939 		break;
940 	case F_WRLCK:
941 		linux_flock->l_type = LINUX_F_WRLCK;
942 		break;
943 	case F_UNLCK:
944 		linux_flock->l_type = LINUX_F_UNLCK;
945 		break;
946 	}
947 	linux_flock->l_whence = bsd_flock->l_whence;
948 	linux_flock->l_start = (l_loff_t)bsd_flock->l_start;
949 	linux_flock->l_len = (l_loff_t)bsd_flock->l_len;
950 	linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
951 }
952 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
953 
954 static int
955 fcntl_common(struct thread *td, struct linux_fcntl64_args *args)
956 {
957 	struct l_flock linux_flock;
958 	struct flock bsd_flock;
959 	struct file *fp;
960 	long arg;
961 	int error, result;
962 
963 	switch (args->cmd) {
964 	case LINUX_F_DUPFD:
965 		return (kern_fcntl(td, args->fd, F_DUPFD, args->arg));
966 
967 	case LINUX_F_GETFD:
968 		return (kern_fcntl(td, args->fd, F_GETFD, 0));
969 
970 	case LINUX_F_SETFD:
971 		return (kern_fcntl(td, args->fd, F_SETFD, args->arg));
972 
973 	case LINUX_F_GETFL:
974 		error = kern_fcntl(td, args->fd, F_GETFL, 0);
975 		result = td->td_retval[0];
976 		td->td_retval[0] = 0;
977 		if (result & O_RDONLY)
978 			td->td_retval[0] |= LINUX_O_RDONLY;
979 		if (result & O_WRONLY)
980 			td->td_retval[0] |= LINUX_O_WRONLY;
981 		if (result & O_RDWR)
982 			td->td_retval[0] |= LINUX_O_RDWR;
983 		if (result & O_NDELAY)
984 			td->td_retval[0] |= LINUX_O_NONBLOCK;
985 		if (result & O_APPEND)
986 			td->td_retval[0] |= LINUX_O_APPEND;
987 		if (result & O_FSYNC)
988 			td->td_retval[0] |= LINUX_O_SYNC;
989 		if (result & O_ASYNC)
990 			td->td_retval[0] |= LINUX_FASYNC;
991 #ifdef LINUX_O_NOFOLLOW
992 		if (result & O_NOFOLLOW)
993 			td->td_retval[0] |= LINUX_O_NOFOLLOW;
994 #endif
995 #ifdef LINUX_O_DIRECT
996 		if (result & O_DIRECT)
997 			td->td_retval[0] |= LINUX_O_DIRECT;
998 #endif
999 		return (error);
1000 
1001 	case LINUX_F_SETFL:
1002 		arg = 0;
1003 		if (args->arg & LINUX_O_NDELAY)
1004 			arg |= O_NONBLOCK;
1005 		if (args->arg & LINUX_O_APPEND)
1006 			arg |= O_APPEND;
1007 		if (args->arg & LINUX_O_SYNC)
1008 			arg |= O_FSYNC;
1009 		if (args->arg & LINUX_FASYNC)
1010 			arg |= O_ASYNC;
1011 #ifdef LINUX_O_NOFOLLOW
1012 		if (args->arg & LINUX_O_NOFOLLOW)
1013 			arg |= O_NOFOLLOW;
1014 #endif
1015 #ifdef LINUX_O_DIRECT
1016 		if (args->arg & LINUX_O_DIRECT)
1017 			arg |= O_DIRECT;
1018 #endif
1019 		return (kern_fcntl(td, args->fd, F_SETFL, arg));
1020 
1021 	case LINUX_F_GETLK:
1022 		error = copyin((void *)args->arg, &linux_flock,
1023 		    sizeof(linux_flock));
1024 		if (error)
1025 			return (error);
1026 		linux_to_bsd_flock(&linux_flock, &bsd_flock);
1027 		error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock);
1028 		if (error)
1029 			return (error);
1030 		bsd_to_linux_flock(&bsd_flock, &linux_flock);
1031 		return (copyout(&linux_flock, (void *)args->arg,
1032 		    sizeof(linux_flock)));
1033 
1034 	case LINUX_F_SETLK:
1035 		error = copyin((void *)args->arg, &linux_flock,
1036 		    sizeof(linux_flock));
1037 		if (error)
1038 			return (error);
1039 		linux_to_bsd_flock(&linux_flock, &bsd_flock);
1040 		return (kern_fcntl(td, args->fd, F_SETLK,
1041 		    (intptr_t)&bsd_flock));
1042 
1043 	case LINUX_F_SETLKW:
1044 		error = copyin((void *)args->arg, &linux_flock,
1045 		    sizeof(linux_flock));
1046 		if (error)
1047 			return (error);
1048 		linux_to_bsd_flock(&linux_flock, &bsd_flock);
1049 		return (kern_fcntl(td, args->fd, F_SETLKW,
1050 		     (intptr_t)&bsd_flock));
1051 
1052 	case LINUX_F_GETOWN:
1053 		return (kern_fcntl(td, args->fd, F_GETOWN, 0));
1054 
1055 	case LINUX_F_SETOWN:
1056 		/*
1057 		 * XXX some Linux applications depend on F_SETOWN having no
1058 		 * significant effect for pipes (SIGIO is not delivered for
1059 		 * pipes under Linux-2.2.35 at least).
1060 		 */
1061 		error = fget(td, args->fd, &fp);
1062 		if (error)
1063 			return (error);
1064 		if (fp->f_type == DTYPE_PIPE) {
1065 			fdrop(fp, td);
1066 			return (EINVAL);
1067 		}
1068 		fdrop(fp, td);
1069 
1070 		return (kern_fcntl(td, args->fd, F_SETOWN, args->arg));
1071 	}
1072 
1073 	return (EINVAL);
1074 }
1075 
1076 int
1077 linux_fcntl(struct thread *td, struct linux_fcntl_args *args)
1078 {
1079 	struct linux_fcntl64_args args64;
1080 
1081 #ifdef DEBUG
1082 	if (ldebug(fcntl))
1083 		printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd);
1084 #endif
1085 
1086 	args64.fd = args->fd;
1087 	args64.cmd = args->cmd;
1088 	args64.arg = args->arg;
1089 	return (fcntl_common(td, &args64));
1090 }
1091 
1092 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
1093 int
1094 linux_fcntl64(struct thread *td, struct linux_fcntl64_args *args)
1095 {
1096 	struct l_flock64 linux_flock;
1097 	struct flock bsd_flock;
1098 	int error;
1099 
1100 #ifdef DEBUG
1101 	if (ldebug(fcntl64))
1102 		printf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd);
1103 #endif
1104 
1105 	switch (args->cmd) {
1106 	case LINUX_F_GETLK64:
1107 		error = copyin((void *)args->arg, &linux_flock,
1108 		    sizeof(linux_flock));
1109 		if (error)
1110 			return (error);
1111 		linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1112 		error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock);
1113 		if (error)
1114 			return (error);
1115 		bsd_to_linux_flock64(&bsd_flock, &linux_flock);
1116 		return (copyout(&linux_flock, (void *)args->arg,
1117 			    sizeof(linux_flock)));
1118 
1119 	case LINUX_F_SETLK64:
1120 		error = copyin((void *)args->arg, &linux_flock,
1121 		    sizeof(linux_flock));
1122 		if (error)
1123 			return (error);
1124 		linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1125 		return (kern_fcntl(td, args->fd, F_SETLK,
1126 		    (intptr_t)&bsd_flock));
1127 
1128 	case LINUX_F_SETLKW64:
1129 		error = copyin((void *)args->arg, &linux_flock,
1130 		    sizeof(linux_flock));
1131 		if (error)
1132 			return (error);
1133 		linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1134 		return (kern_fcntl(td, args->fd, F_SETLKW,
1135 		    (intptr_t)&bsd_flock));
1136 	}
1137 
1138 	return (fcntl_common(td, args));
1139 }
1140 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
1141 
1142 int
1143 linux_chown(struct thread *td, struct linux_chown_args *args)
1144 {
1145 	char *path;
1146 	int error;
1147 
1148 	LCONVPATHEXIST(td, args->path, &path);
1149 
1150 #ifdef DEBUG
1151 	if (ldebug(chown))
1152 		printf(ARGS(chown, "%s, %d, %d"), path, args->uid, args->gid);
1153 #endif
1154 	error = kern_chown(td, path, UIO_SYSSPACE, args->uid, args->gid);
1155 	LFREEPATH(path);
1156 	return (error);
1157 }
1158 
1159 int
1160 linux_lchown(struct thread *td, struct linux_lchown_args *args)
1161 {
1162 	char *path;
1163 	int error;
1164 
1165 	LCONVPATHEXIST(td, args->path, &path);
1166 
1167 #ifdef DEBUG
1168 	if (ldebug(lchown))
1169 		printf(ARGS(lchown, "%s, %d, %d"), path, args->uid, args->gid);
1170 #endif
1171 	error = kern_lchown(td, path, UIO_SYSSPACE, args->uid, args->gid);
1172 	LFREEPATH(path);
1173 	return (error);
1174 }
1175