nfs: fix real/effective id mismatch in nfs_access
[dragonfly.git] / sys / emulation / linux / linux_file.c
blobb4402f70c9efc020a7c3cd273c8688c536073859
1 /*-
2 * Copyright (c) 1994-1995 Søren Schmidt
3 * All rights reserved.
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
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.
28 * $FreeBSD: src/sys/compat/linux/linux_file.c,v 1.41.2.6 2003/01/06 09:19:43 fjoe Exp $
29 * $DragonFly: src/sys/emulation/linux/linux_file.c,v 1.39 2008/09/28 05:08:16 dillon Exp $
32 #include "opt_compat.h"
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/conf.h>
37 #include <sys/dirent.h>
38 #include <sys/fcntl.h>
39 #include <sys/file.h>
40 #include <sys/stat.h>
41 #include <sys/filedesc.h>
42 #include <sys/kern_syscall.h>
43 #include <sys/lock.h>
44 #include <sys/malloc.h>
45 #include <sys/mount.h>
46 #include <sys/nlookup.h>
47 #include <sys/proc.h>
48 #include <sys/sysproto.h>
49 #include <sys/tty.h>
50 #include <sys/vnode.h>
52 #include <vfs/ufs/quota.h>
53 #include <vfs/ufs/ufsmount.h>
55 #include <sys/file2.h>
57 #include <arch_linux/linux.h>
58 #include <arch_linux/linux_proto.h>
59 #include "linux_util.h"
61 int
62 sys_linux_creat(struct linux_creat_args *args)
64 struct nlookupdata nd;
65 char *path;
66 int error;
68 error = linux_copyin_path(args->path, &path, LINUX_PATH_CREATE);
69 if (error)
70 return (error);
71 #ifdef DEBUG
72 if (ldebug(creat))
73 kprintf(ARGS(creat, "%s, %d"), path, args->mode);
74 #endif
75 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
76 if (error == 0) {
77 error = kern_open(&nd, O_WRONLY | O_CREAT | O_TRUNC,
78 args->mode, &args->sysmsg_iresult);
80 linux_free_path(&path);
81 return(error);
84 int
85 sys_linux_open(struct linux_open_args *args)
87 struct thread *td = curthread;
88 struct proc *p = td->td_proc;
89 struct nlookupdata nd;
90 char *path;
91 int error, flags;
93 KKASSERT(p);
95 if (args->flags & LINUX_O_CREAT) {
96 error = linux_copyin_path(args->path, &path,
97 LINUX_PATH_CREATE);
98 } else {
99 error = linux_copyin_path(args->path, &path,
100 LINUX_PATH_EXISTS);
102 if (error)
103 return (error);
105 #ifdef DEBUG
106 if (ldebug(open))
107 kprintf(ARGS(open, "%s, 0x%x, 0x%x"), path, args->flags,
108 args->mode);
109 #endif
110 flags = 0;
111 if (args->flags & LINUX_O_RDONLY)
112 flags |= O_RDONLY;
113 if (args->flags & LINUX_O_WRONLY)
114 flags |= O_WRONLY;
115 if (args->flags & LINUX_O_RDWR)
116 flags |= O_RDWR;
117 if (args->flags & LINUX_O_NDELAY)
118 flags |= O_NONBLOCK;
119 if (args->flags & LINUX_O_APPEND)
120 flags |= O_APPEND;
121 if (args->flags & LINUX_O_SYNC)
122 flags |= O_FSYNC;
123 if (args->flags & LINUX_O_NONBLOCK)
124 flags |= O_NONBLOCK;
125 if (args->flags & LINUX_FASYNC)
126 flags |= O_ASYNC;
127 if (args->flags & LINUX_O_CREAT)
128 flags |= O_CREAT;
129 if (args->flags & LINUX_O_TRUNC)
130 flags |= O_TRUNC;
131 if (args->flags & LINUX_O_EXCL)
132 flags |= O_EXCL;
133 if (args->flags & LINUX_O_NOCTTY)
134 flags |= O_NOCTTY;
135 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
136 if (error == 0) {
137 error = kern_open(&nd, flags,
138 args->mode, &args->sysmsg_iresult);
141 if (error == 0 && !(flags & O_NOCTTY) &&
142 SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
143 struct file *fp;
145 fp = holdfp(p->p_fd, args->sysmsg_iresult, -1);
146 if (fp) {
147 if (fp->f_type == DTYPE_VNODE)
148 fo_ioctl(fp, TIOCSCTTY, NULL, p->p_ucred, NULL);
149 fdrop(fp);
152 #ifdef DEBUG
153 if (ldebug(open))
154 kprintf(LMSG("open returns error %d"), error);
155 #endif
156 linux_free_path(&path);
157 return error;
161 sys_linux_lseek(struct linux_lseek_args *args)
163 int error;
165 #ifdef DEBUG
166 if (ldebug(lseek))
167 kprintf(ARGS(lseek, "%d, %ld, %d"),
168 args->fdes, (long)args->off, args->whence);
169 #endif
170 error = kern_lseek(args->fdes, args->off, args->whence,
171 &args->sysmsg_offset);
173 return error;
177 sys_linux_llseek(struct linux_llseek_args *args)
179 int error;
180 off_t off, res;
182 #ifdef DEBUG
183 if (ldebug(llseek))
184 kprintf(ARGS(llseek, "%d, %d:%d, %d"),
185 args->fd, args->ohigh, args->olow, args->whence);
186 #endif
187 off = (args->olow) | (((off_t) args->ohigh) << 32);
189 error = kern_lseek(args->fd, off, args->whence, &res);
191 if (error == 0)
192 error = copyout(&res, args->res, sizeof(res));
193 return (error);
197 sys_linux_readdir(struct linux_readdir_args *args)
199 struct linux_getdents_args lda;
200 int error;
202 lda.fd = args->fd;
203 lda.dent = args->dent;
204 lda.count = -1;
205 lda.sysmsg_iresult = 0;
206 error = sys_linux_getdents(&lda);
207 args->sysmsg_iresult = lda.sysmsg_iresult;
208 return(error);
212 * Note that linux_getdents(2) and linux_getdents64(2) have the same
213 * arguments. They only differ in the definition of struct dirent they
214 * operate on. We use this to common the code, with the exception of
215 * accessing struct dirent. Note that linux_readdir(2) is implemented
216 * by means of linux_getdents(2). In this case we never operate on
217 * struct dirent64 and thus don't need to handle it...
220 struct l_dirent {
221 l_long d_ino;
222 l_off_t d_off;
223 l_ushort d_reclen;
224 char d_name[LINUX_NAME_MAX + 1];
227 struct l_dirent64 {
228 uint64_t d_ino;
229 int64_t d_off;
230 l_ushort d_reclen;
231 u_char d_type;
232 char d_name[LINUX_NAME_MAX + 1];
235 #define LINUX_RECLEN(de,namlen) \
236 ALIGN((((char *)&(de)->d_name - (char *)de) + (namlen) + 1))
238 #define LINUX_DIRBLKSIZ 512
240 static int
241 getdents_common(struct linux_getdents64_args *args, int is64bit)
243 struct thread *td = curthread;
244 struct proc *p = td->td_proc;
245 struct dirent *bdp;
246 struct vnode *vp;
247 caddr_t inp, buf; /* BSD-format */
248 int reclen; /* BSD-format */
249 size_t len;
250 caddr_t outp; /* Linux-format */
251 int linuxreclen = 0; /* Linux-format */
252 size_t resid;
253 struct file *fp;
254 struct uio auio;
255 struct iovec aiov;
256 struct vattr va;
257 off_t off;
258 struct l_dirent linux_dirent;
259 struct l_dirent64 linux_dirent64;
260 int error, eofflag, justone;
261 size_t buflen, nbytes;
262 off_t *cookies = NULL, *cookiep;
263 int ncookies;
265 KKASSERT(p);
267 if ((error = holdvnode(p->p_fd, args->fd, &fp)) != 0)
268 return (error);
270 if ((fp->f_flag & FREAD) == 0) {
271 error = EBADF;
272 goto done;
275 vp = (struct vnode *) fp->f_data;
276 if (vp->v_type != VDIR) {
277 error = EINVAL;
278 goto done;
281 if ((error = VOP_GETATTR(vp, &va)) != 0)
282 goto done;
284 nbytes = args->count;
285 if (nbytes == (size_t)-1) {
286 /* readdir(2) case. Always struct dirent. */
287 if (is64bit) {
288 error = EINVAL;
289 goto done;
291 nbytes = sizeof(linux_dirent);
292 justone = 1;
293 } else {
294 justone = 0;
296 if ((size_t)nbytes < 0)
297 nbytes = 0;
299 off = fp->f_offset;
301 buflen = max(LINUX_DIRBLKSIZ, nbytes);
302 buflen = min(buflen, MAXBSIZE);
303 buf = kmalloc(buflen, M_TEMP, M_WAITOK);
305 again:
306 aiov.iov_base = buf;
307 aiov.iov_len = buflen;
308 auio.uio_iov = &aiov;
309 auio.uio_iovcnt = 1;
310 auio.uio_rw = UIO_READ;
311 auio.uio_segflg = UIO_SYSSPACE;
312 auio.uio_td = td;
313 auio.uio_resid = buflen;
314 auio.uio_offset = off;
316 if (cookies) {
317 kfree(cookies, M_TEMP);
318 cookies = NULL;
321 eofflag = 0;
322 ncookies = 0;
323 if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies,
324 &cookies)))
325 goto out;
327 inp = buf;
328 outp = (caddr_t)args->dirent;
329 resid = nbytes;
330 if (auio.uio_resid >= buflen)
331 goto eof;
332 len = buflen - auio.uio_resid;
333 cookiep = cookies;
335 if (cookies) {
337 * When using cookies, the vfs has the option of reading from
338 * a different offset than that supplied (UFS truncates the
339 * offset to a block boundary to make sure that it never reads
340 * partway through a directory entry, even if the directory
341 * has been compacted).
343 while (len > 0 && ncookies > 0 && *cookiep < off) {
344 bdp = (struct dirent *) inp;
345 len -= _DIRENT_DIRSIZ(bdp);
346 inp += _DIRENT_DIRSIZ(bdp);
347 cookiep++;
348 ncookies--;
352 while (len > 0) {
353 if (cookiep && ncookies == 0)
354 break;
355 bdp = (struct dirent *) inp;
356 reclen = _DIRENT_DIRSIZ(bdp);
357 if (reclen & 3) {
358 error = EFAULT;
359 goto out;
362 if (bdp->d_ino == 0) {
363 inp += reclen;
364 if (cookiep) {
365 off = *cookiep++;
366 ++off;
367 ncookies--;
368 } else {
369 off += reclen;
371 len -= reclen;
372 continue;
375 linuxreclen = (is64bit)
376 ? LINUX_RECLEN(&linux_dirent64, bdp->d_namlen)
377 : LINUX_RECLEN(&linux_dirent, bdp->d_namlen);
379 if (reclen > len || resid < linuxreclen) {
380 outp++;
381 break;
384 bzero(&linux_dirent, sizeof(linux_dirent));
385 bzero(&linux_dirent64, sizeof(linux_dirent64));
386 if (justone) {
387 /* readdir(2) case. */
388 linux_dirent.d_ino = (l_long)INO64TO32(bdp->d_ino);
389 linux_dirent.d_off = (l_off_t)linuxreclen;
390 linux_dirent.d_reclen = (l_ushort)bdp->d_namlen;
391 strcpy(linux_dirent.d_name, bdp->d_name);
392 error = copyout(&linux_dirent, outp, linuxreclen);
393 } else {
394 if (is64bit) {
395 linux_dirent64.d_ino = bdp->d_ino;
396 linux_dirent64.d_off = (cookiep)
397 ? (l_off_t)*cookiep
398 : (l_off_t)(off + reclen);
399 linux_dirent64.d_reclen =
400 (l_ushort)linuxreclen;
401 linux_dirent64.d_type = bdp->d_type;
402 strcpy(linux_dirent64.d_name, bdp->d_name);
403 error = copyout(&linux_dirent64, outp,
404 linuxreclen);
405 } else {
406 linux_dirent.d_ino = INO64TO32(bdp->d_ino);
407 linux_dirent.d_off = (cookiep)
408 ? (l_off_t)*cookiep
409 : (l_off_t)(off + reclen);
410 linux_dirent.d_reclen = (l_ushort)linuxreclen;
411 strcpy(linux_dirent.d_name, bdp->d_name);
412 error = copyout(&linux_dirent, outp,
413 linuxreclen);
416 if (error)
417 goto out;
419 inp += reclen;
420 if (cookiep) {
421 off = *cookiep++;
422 ++off;
423 ncookies--;
424 } else {
425 off += reclen;
428 outp += linuxreclen;
429 resid -= linuxreclen;
430 len -= reclen;
431 if (justone)
432 break;
435 if (outp == (caddr_t)args->dirent && eofflag == 0)
436 goto again;
438 fp->f_offset = off;
439 if (justone)
440 nbytes = resid + linuxreclen;
442 eof:
443 args->sysmsg_iresult = (int)(nbytes - resid);
445 out:
446 if (cookies)
447 kfree(cookies, M_TEMP);
449 kfree(buf, M_TEMP);
450 done:
451 fdrop(fp);
452 return (error);
456 sys_linux_getdents(struct linux_getdents_args *args)
458 #ifdef DEBUG
459 if (ldebug(getdents))
460 kprintf(ARGS(getdents, "%d, *, %d"), args->fd, args->count);
461 #endif
462 return (getdents_common((struct linux_getdents64_args*)args, 0));
466 sys_linux_getdents64(struct linux_getdents64_args *args)
468 #ifdef DEBUG
469 if (ldebug(getdents64))
470 kprintf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count);
471 #endif
472 return (getdents_common(args, 1));
476 * These exist mainly for hooks for doing /compat/linux translation.
480 sys_linux_access(struct linux_access_args *args)
482 struct nlookupdata nd;
483 char *path;
484 int error;
486 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
487 if (error)
488 return (error);
489 #ifdef DEBUG
490 if (ldebug(access))
491 kprintf(ARGS(access, "%s, %d"), path, args->flags);
492 #endif
493 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
494 if (error == 0)
495 error = kern_access(&nd, args->flags, 0);
496 nlookup_done(&nd);
497 linux_free_path(&path);
498 return(error);
502 sys_linux_unlink(struct linux_unlink_args *args)
504 struct nlookupdata nd;
505 char *path;
506 int error;
508 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
509 if (error)
510 return (error);
511 #ifdef DEBUG
512 if (ldebug(unlink))
513 kprintf(ARGS(unlink, "%s"), path);
514 #endif
515 error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
516 if (error == 0)
517 error = kern_unlink(&nd);
518 nlookup_done(&nd);
519 linux_free_path(&path);
520 return(error);
524 sys_linux_chdir(struct linux_chdir_args *args)
526 struct nlookupdata nd;
527 char *path;
528 int error;
530 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
531 if (error)
532 return (error);
533 #ifdef DEBUG
534 if (ldebug(chdir))
535 kprintf(ARGS(chdir, "%s"), path);
536 #endif
537 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
538 if (error == 0) {
539 error = kern_chdir(&nd);
540 nlookup_done(&nd);
542 linux_free_path(&path);
543 return(error);
547 sys_linux_chmod(struct linux_chmod_args *args)
549 struct nlookupdata nd;
550 char *path;
551 int error;
553 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
554 if (error)
555 return (error);
556 #ifdef DEBUG
557 if (ldebug(chmod))
558 kprintf(ARGS(chmod, "%s, %d"), path, args->mode);
559 #endif
560 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
561 if (error == 0)
562 error = kern_chmod(&nd, args->mode);
563 nlookup_done(&nd);
564 linux_free_path(&path);
565 return(error);
569 sys_linux_mkdir(struct linux_mkdir_args *args)
571 struct nlookupdata nd;
572 char *path;
573 int error;
575 error = linux_copyin_path(args->path, &path, LINUX_PATH_CREATE);
576 if (error)
577 return (error);
578 #ifdef DEBUG
579 if (ldebug(mkdir))
580 kprintf(ARGS(mkdir, "%s, %d"), path, args->mode);
581 #endif
582 error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
583 if (error == 0)
584 error = kern_mkdir(&nd, args->mode);
585 nlookup_done(&nd);
587 linux_free_path(&path);
588 return(error);
592 sys_linux_rmdir(struct linux_rmdir_args *args)
594 struct nlookupdata nd;
595 char *path;
596 int error;
598 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
599 if (error)
600 return (error);
601 #ifdef DEBUG
602 if (ldebug(rmdir))
603 kprintf(ARGS(rmdir, "%s"), path);
604 #endif
605 error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
606 if (error == 0)
607 error = kern_rmdir(&nd);
608 nlookup_done(&nd);
609 linux_free_path(&path);
610 return(error);
614 sys_linux_rename(struct linux_rename_args *args)
616 struct nlookupdata fromnd, tond;
617 char *from, *to;
618 int error;
620 error = linux_copyin_path(args->from, &from, LINUX_PATH_EXISTS);
621 if (error)
622 return (error);
623 error = linux_copyin_path(args->to, &to, LINUX_PATH_CREATE);
624 if (error) {
625 linux_free_path(&from);
626 return (error);
628 #ifdef DEBUG
629 if (ldebug(rename))
630 kprintf(ARGS(rename, "%s, %s"), from, to);
631 #endif
632 error = nlookup_init(&fromnd, from, UIO_SYSSPACE, 0);
633 if (error == 0) {
634 error = nlookup_init(&tond, to, UIO_SYSSPACE, 0);
635 if (error == 0)
636 error = kern_rename(&fromnd, &tond);
637 nlookup_done(&tond);
639 nlookup_done(&fromnd);
640 linux_free_path(&from);
641 linux_free_path(&to);
642 return(error);
646 sys_linux_symlink(struct linux_symlink_args *args)
648 struct thread *td = curthread;
649 struct nlookupdata nd;
650 char *path, *link;
651 int error;
652 int mode;
654 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
655 if (error)
656 return (error);
657 error = linux_copyin_path(args->to, &link, LINUX_PATH_CREATE);
658 if (error) {
659 linux_free_path(&path);
660 return (error);
662 #ifdef DEBUG
663 if (ldebug(symlink))
664 kprintf(ARGS(symlink, "%s, %s"), path, link);
665 #endif
666 error = nlookup_init(&nd, link, UIO_SYSSPACE, 0);
667 if (error == 0) {
668 mode = ACCESSPERMS & ~td->td_proc->p_fd->fd_cmask;
669 error = kern_symlink(&nd, path, mode);
671 nlookup_done(&nd);
672 linux_free_path(&path);
673 linux_free_path(&link);
674 return(error);
678 sys_linux_readlink(struct linux_readlink_args *args)
680 struct nlookupdata nd;
681 char *path;
682 int error;
684 error = linux_copyin_path(args->name, &path, LINUX_PATH_EXISTS);
685 if (error)
686 return (error);
687 #ifdef DEBUG
688 if (ldebug(readlink))
689 kprintf(ARGS(readlink, "%s, %p, %d"), path, (void *)args->buf,
690 args->count);
691 #endif
692 error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
693 if (error == 0) {
694 error = kern_readlink(&nd, args->buf, args->count,
695 &args->sysmsg_iresult);
697 nlookup_done(&nd);
698 linux_free_path(&path);
699 return(error);
703 sys_linux_truncate(struct linux_truncate_args *args)
705 struct nlookupdata nd;
706 char *path;
707 int error;
709 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
710 if (error)
711 return (error);
712 #ifdef DEBUG
713 if (ldebug(truncate))
714 kprintf(ARGS(truncate, "%s, %ld"), path,
715 (long)args->length);
716 #endif
717 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
718 if (error == 0)
719 error = kern_truncate(&nd, args->length);
720 nlookup_done(&nd);
721 linux_free_path(&path);
722 return(error);
726 sys_linux_truncate64(struct linux_truncate64_args *args)
728 struct nlookupdata nd;
729 char *path;
730 int error;
732 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
733 if (error)
734 return (error);
735 #ifdef DEBUG
736 if (ldebug(truncate64))
737 kprintf(ARGS(truncate64, "%s, %lld"), path,
738 (off_t)args->length);
739 #endif
740 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
741 if (error == 0)
742 error = kern_truncate(&nd, args->length);
743 nlookup_done(&nd);
744 linux_free_path(&path);
745 return error;
749 sys_linux_ftruncate(struct linux_ftruncate_args *args)
751 int error;
753 #ifdef DEBUG
754 if (ldebug(ftruncate))
755 kprintf(ARGS(ftruncate, "%d, %ld"), args->fd,
756 (long)args->length);
757 #endif
758 error = kern_ftruncate(args->fd, args->length);
760 return error;
764 sys_linux_ftruncate64(struct linux_ftruncate64_args *args)
766 int error;
768 #ifdef DEBUG
769 if (ldebug(ftruncate))
770 kprintf(ARGS(ftruncate64, "%d, %lld"), args->fd,
771 (off_t)args->length);
772 #endif
773 error = kern_ftruncate(args->fd, args->length);
775 return error;
779 sys_linux_link(struct linux_link_args *args)
781 struct nlookupdata nd, linknd;
782 char *path, *link;
783 int error;
785 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
786 if (error)
787 return (error);
788 error = linux_copyin_path(args->to, &link, LINUX_PATH_CREATE);
789 if (error) {
790 linux_free_path(&path);
791 return (error);
793 #ifdef DEBUG
794 if (ldebug(link))
795 kprintf(ARGS(link, "%s, %s"), path, link);
796 #endif
797 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
798 if (error == 0) {
799 error = nlookup_init(&linknd, link, UIO_SYSSPACE, 0);
800 if (error == 0)
801 error = kern_link(&nd, &linknd);
802 nlookup_done(&linknd);
804 nlookup_done(&nd);
805 linux_free_path(&path);
806 linux_free_path(&link);
807 return(error);
811 sys_linux_fdatasync(struct linux_fdatasync_args *uap)
813 struct fsync_args bsd;
814 int error;
816 bsd.fd = uap->fd;
817 bsd.sysmsg_iresult = 0;
819 error = sys_fsync(&bsd);
820 uap->sysmsg_iresult = bsd.sysmsg_iresult;
821 return(error);
825 sys_linux_pread(struct linux_pread_args *uap)
827 struct thread *td = curthread;
828 struct uio auio;
829 struct iovec aiov;
830 int error;
832 aiov.iov_base = uap->buf;
833 aiov.iov_len = uap->nbyte;
834 auio.uio_iov = &aiov;
835 auio.uio_iovcnt = 1;
836 auio.uio_offset = uap->offset;
837 auio.uio_resid = uap->nbyte;
838 auio.uio_rw = UIO_READ;
839 auio.uio_segflg = UIO_USERSPACE;
840 auio.uio_td = td;
842 if ((ssize_t)auio.uio_resid < 0) {
843 error = EINVAL;
844 } else {
845 error = kern_preadv(uap->fd, &auio, O_FOFFSET,
846 &uap->sysmsg_szresult);
848 return(error);
852 sys_linux_pwrite(struct linux_pwrite_args *uap)
854 struct thread *td = curthread;
855 struct uio auio;
856 struct iovec aiov;
857 int error;
859 aiov.iov_base = uap->buf;
860 aiov.iov_len = uap->nbyte;
861 auio.uio_iov = &aiov;
862 auio.uio_iovcnt = 1;
863 auio.uio_offset = uap->offset;
864 auio.uio_resid = uap->nbyte;
865 auio.uio_rw = UIO_WRITE;
866 auio.uio_segflg = UIO_USERSPACE;
867 auio.uio_td = td;
869 if ((ssize_t)auio.uio_resid < 0) {
870 error = EINVAL;
871 } else {
872 error = kern_pwritev(uap->fd, &auio, O_FOFFSET,
873 &uap->sysmsg_szresult);
875 return(error);
879 sys_linux_oldumount(struct linux_oldumount_args *args)
881 struct linux_umount_args args2;
882 int error;
884 args2.path = args->path;
885 args2.flags = 0;
886 args2.sysmsg_iresult = 0;
887 error = sys_linux_umount(&args2);
888 args->sysmsg_iresult = args2.sysmsg_iresult;
889 return(error);
893 sys_linux_umount(struct linux_umount_args *args)
895 struct unmount_args bsd;
896 int error;
898 bsd.path = args->path;
899 bsd.flags = args->flags; /* XXX correct? */
900 bsd.sysmsg_iresult = 0;
902 error = sys_unmount(&bsd);
903 args->sysmsg_iresult = bsd.sysmsg_iresult;
904 return(error);
908 * fcntl family of syscalls
911 struct l_flock {
912 l_short l_type;
913 l_short l_whence;
914 l_off_t l_start;
915 l_off_t l_len;
916 l_pid_t l_pid;
919 static void
920 linux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock)
922 switch (linux_flock->l_type) {
923 case LINUX_F_RDLCK:
924 bsd_flock->l_type = F_RDLCK;
925 break;
926 case LINUX_F_WRLCK:
927 bsd_flock->l_type = F_WRLCK;
928 break;
929 case LINUX_F_UNLCK:
930 bsd_flock->l_type = F_UNLCK;
931 break;
932 default:
933 bsd_flock->l_type = -1;
934 break;
936 bsd_flock->l_whence = linux_flock->l_whence;
937 bsd_flock->l_start = (off_t)linux_flock->l_start;
938 bsd_flock->l_len = (off_t)linux_flock->l_len;
939 bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
942 static void
943 bsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock)
945 switch (bsd_flock->l_type) {
946 case F_RDLCK:
947 linux_flock->l_type = LINUX_F_RDLCK;
948 break;
949 case F_WRLCK:
950 linux_flock->l_type = LINUX_F_WRLCK;
951 break;
952 case F_UNLCK:
953 linux_flock->l_type = LINUX_F_UNLCK;
954 break;
956 linux_flock->l_whence = bsd_flock->l_whence;
957 linux_flock->l_start = (l_off_t)bsd_flock->l_start;
958 linux_flock->l_len = (l_off_t)bsd_flock->l_len;
959 linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
962 #if defined(__i386__)
963 struct l_flock64 {
964 l_short l_type;
965 l_short l_whence;
966 l_loff_t l_start;
967 l_loff_t l_len;
968 l_pid_t l_pid;
971 static void
972 linux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock)
974 switch (linux_flock->l_type) {
975 case LINUX_F_RDLCK:
976 bsd_flock->l_type = F_RDLCK;
977 break;
978 case LINUX_F_WRLCK:
979 bsd_flock->l_type = F_WRLCK;
980 break;
981 case LINUX_F_UNLCK:
982 bsd_flock->l_type = F_UNLCK;
983 break;
984 default:
985 bsd_flock->l_type = -1;
986 break;
988 bsd_flock->l_whence = linux_flock->l_whence;
989 bsd_flock->l_start = (off_t)linux_flock->l_start;
990 bsd_flock->l_len = (off_t)linux_flock->l_len;
991 bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
994 static void
995 bsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock)
997 switch (bsd_flock->l_type) {
998 case F_RDLCK:
999 linux_flock->l_type = LINUX_F_RDLCK;
1000 break;
1001 case F_WRLCK:
1002 linux_flock->l_type = LINUX_F_WRLCK;
1003 break;
1004 case F_UNLCK:
1005 linux_flock->l_type = LINUX_F_UNLCK;
1006 break;
1008 linux_flock->l_whence = bsd_flock->l_whence;
1009 linux_flock->l_start = (l_loff_t)bsd_flock->l_start;
1010 linux_flock->l_len = (l_loff_t)bsd_flock->l_len;
1011 linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
1013 #endif /* __i386__ */
1015 static int
1016 linux_fcntl_common(struct linux_fcntl64_args *args)
1018 struct proc *p = curproc;
1019 struct l_flock linux_flock;
1020 struct file *fp;
1021 union fcntl_dat dat;
1022 int error, cmd;
1024 switch (args->cmd) {
1025 case LINUX_F_DUPFD:
1026 cmd = F_DUPFD;
1027 dat.fc_fd = args->arg;
1028 break;
1029 case LINUX_F_GETFD:
1030 cmd = F_GETFD;
1031 break;
1032 case LINUX_F_SETFD:
1033 cmd = F_SETFD;
1034 dat.fc_cloexec = args->arg;
1035 break;
1036 case LINUX_F_GETFL:
1037 cmd = F_GETFL;
1038 break;
1039 case LINUX_F_SETFL:
1040 cmd = F_SETFL;
1041 dat.fc_flags = 0;
1042 if (args->arg & LINUX_O_NDELAY)
1043 dat.fc_flags |= O_NONBLOCK;
1044 if (args->arg & LINUX_O_APPEND)
1045 dat.fc_flags |= O_APPEND;
1046 if (args->arg & LINUX_O_SYNC)
1047 dat.fc_flags |= O_FSYNC;
1048 if (args->arg & LINUX_FASYNC)
1049 dat.fc_flags |= O_ASYNC;
1050 break;
1051 case LINUX_F_GETLK:
1052 case LINUX_F_SETLK:
1053 case LINUX_F_SETLKW:
1054 cmd = F_GETLK;
1055 error = copyin((caddr_t)args->arg, &linux_flock,
1056 sizeof(linux_flock));
1057 if (error)
1058 return (error);
1059 linux_to_bsd_flock(&linux_flock, &dat.fc_flock);
1060 break;
1061 case LINUX_F_GETOWN:
1062 cmd = F_GETOWN;
1063 break;
1064 case LINUX_F_SETOWN:
1066 * XXX some Linux applications depend on F_SETOWN having no
1067 * significant effect for pipes (SIGIO is not delivered for
1068 * pipes under Linux-2.2.35 at least).
1070 fp = holdfp(p->p_fd, args->fd, -1);
1071 if (fp == NULL)
1072 return (EBADF);
1073 if (fp->f_type == DTYPE_PIPE) {
1074 fdrop(fp);
1075 return (EINVAL);
1077 fdrop(fp);
1078 cmd = F_SETOWN;
1079 dat.fc_owner = args->arg;
1080 break;
1081 default:
1082 return (EINVAL);
1085 error = kern_fcntl(args->fd, cmd, &dat, p->p_ucred);
1087 if (error == 0) {
1088 switch (args->cmd) {
1089 case LINUX_F_DUPFD:
1090 args->sysmsg_iresult = dat.fc_fd;
1091 break;
1092 case LINUX_F_GETFD:
1093 args->sysmsg_iresult = dat.fc_cloexec;
1094 break;
1095 case LINUX_F_SETFD:
1096 break;
1097 case LINUX_F_GETFL:
1098 args->sysmsg_iresult = 0;
1099 if (dat.fc_flags & O_RDONLY)
1100 args->sysmsg_iresult |= LINUX_O_RDONLY;
1101 if (dat.fc_flags & O_WRONLY)
1102 args->sysmsg_iresult |= LINUX_O_WRONLY;
1103 if (dat.fc_flags & O_RDWR)
1104 args->sysmsg_iresult |= LINUX_O_RDWR;
1105 if (dat.fc_flags & O_NDELAY)
1106 args->sysmsg_iresult |= LINUX_O_NONBLOCK;
1107 if (dat.fc_flags & O_APPEND)
1108 args->sysmsg_iresult |= LINUX_O_APPEND;
1109 if (dat.fc_flags & O_FSYNC)
1110 args->sysmsg_iresult |= LINUX_O_SYNC;
1111 if (dat.fc_flags & O_ASYNC)
1112 args->sysmsg_iresult |= LINUX_FASYNC;
1113 break;
1114 case LINUX_F_GETLK:
1115 bsd_to_linux_flock(&dat.fc_flock, &linux_flock);
1116 error = copyout(&linux_flock, (caddr_t)args->arg,
1117 sizeof(linux_flock));
1118 break;
1119 case LINUX_F_SETLK:
1120 case LINUX_F_SETLKW:
1121 break;
1122 case LINUX_F_GETOWN:
1123 args->sysmsg_iresult = dat.fc_owner;
1124 break;
1125 case LINUX_F_SETOWN:
1126 break;
1130 return(error);
1134 sys_linux_fcntl(struct linux_fcntl_args *args)
1136 struct linux_fcntl64_args args64;
1137 int error;
1139 #ifdef DEBUG
1140 if (ldebug(fcntl))
1141 kprintf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd);
1142 #endif
1144 args64.fd = args->fd;
1145 args64.cmd = args->cmd;
1146 args64.arg = args->arg;
1147 args64.sysmsg_iresult = 0;
1148 error = linux_fcntl_common(&args64);
1149 args->sysmsg_iresult = args64.sysmsg_iresult;
1150 return(error);
1153 #if defined(__i386__)
1155 sys_linux_fcntl64(struct linux_fcntl64_args *args)
1157 struct l_flock64 linux_flock;
1158 union fcntl_dat dat;
1159 int error, cmd = 0;
1161 #ifdef DEBUG
1162 if (ldebug(fcntl64))
1163 kprintf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd);
1164 #endif
1165 if (args->cmd == LINUX_F_GETLK64 || args->cmd == LINUX_F_SETLK64 ||
1166 args->cmd == LINUX_F_SETLKW64) {
1167 switch (args->cmd) {
1168 case LINUX_F_GETLK64:
1169 cmd = F_GETLK;
1170 break;
1171 case LINUX_F_SETLK64:
1172 cmd = F_SETLK;
1173 break;
1174 case LINUX_F_SETLKW64:
1175 cmd = F_SETLKW;
1176 break;
1179 error = copyin((caddr_t)args->arg, &linux_flock,
1180 sizeof(linux_flock));
1181 if (error)
1182 return (error);
1183 linux_to_bsd_flock64(&linux_flock, &dat.fc_flock);
1185 error = kern_fcntl(args->fd, cmd, &dat, curproc->p_ucred);
1187 if (error == 0 && args->cmd == LINUX_F_GETLK64) {
1188 bsd_to_linux_flock64(&dat.fc_flock, &linux_flock);
1189 error = copyout(&linux_flock, (caddr_t)args->arg,
1190 sizeof(linux_flock));
1192 } else {
1193 error = linux_fcntl_common(args);
1196 return (error);
1198 #endif /* __i386__ */
1201 sys_linux_chown(struct linux_chown_args *args)
1203 struct nlookupdata nd;
1204 char *path;
1205 int error;
1207 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
1208 if (error)
1209 return (error);
1210 #ifdef DEBUG
1211 if (ldebug(chown))
1212 kprintf(ARGS(chown, "%s, %d, %d"), path, args->uid, args->gid);
1213 #endif
1214 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
1215 if (error == 0)
1216 error = kern_chown(&nd, args->uid, args->gid);
1217 nlookup_done(&nd);
1218 linux_free_path(&path);
1219 return(error);
1223 sys_linux_lchown(struct linux_lchown_args *args)
1225 struct nlookupdata nd;
1226 char *path;
1227 int error;
1229 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
1230 if (error)
1231 return (error);
1232 #ifdef DEBUG
1233 if (ldebug(lchown))
1234 kprintf(ARGS(lchown, "%s, %d, %d"), path, args->uid, args->gid);
1235 #endif
1236 error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
1237 if (error == 0)
1238 error = kern_chown(&nd, args->uid, args->gid);
1239 nlookup_done(&nd);
1240 linux_free_path(&path);
1241 return(error);