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