16c3edea3bae0dd652d04f8a43165457fb9290d1
[dragonfly.git] / sys / emulation / linux / linux_file.c
blob16c3edea3bae0dd652d04f8a43165457fb9290d1
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>
56 #include <sys/mplock2.h>
58 #include <arch_linux/linux.h>
59 #include <arch_linux/linux_proto.h>
60 #include "linux_util.h"
63 * MPALMOSTSAFE
65 int
66 sys_linux_creat(struct linux_creat_args *args)
68 struct nlookupdata nd;
69 char *path;
70 int error;
72 error = linux_copyin_path(args->path, &path, LINUX_PATH_CREATE);
73 if (error)
74 return (error);
75 #ifdef DEBUG
76 if (ldebug(creat))
77 kprintf(ARGS(creat, "%s, %d"), path, args->mode);
78 #endif
79 get_mplock();
80 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
81 if (error == 0) {
82 error = kern_open(&nd, O_WRONLY | O_CREAT | O_TRUNC,
83 args->mode, &args->sysmsg_iresult);
85 rel_mplock();
86 linux_free_path(&path);
87 return(error);
91 * MPALMOSTSAFE
93 int
94 sys_linux_open(struct linux_open_args *args)
96 struct thread *td = curthread;
97 struct proc *p = td->td_proc;
98 struct nlookupdata nd;
99 char *path;
100 int error, flags;
102 if (args->flags & LINUX_O_CREAT) {
103 error = linux_copyin_path(args->path, &path,
104 LINUX_PATH_CREATE);
105 } else {
106 error = linux_copyin_path(args->path, &path,
107 LINUX_PATH_EXISTS);
109 if (error)
110 return (error);
112 #ifdef DEBUG
113 if (ldebug(open))
114 kprintf(ARGS(open, "%s, 0x%x, 0x%x"), path, args->flags,
115 args->mode);
116 #endif
117 flags = 0;
118 if (args->flags & LINUX_O_RDONLY)
119 flags |= O_RDONLY;
120 if (args->flags & LINUX_O_WRONLY)
121 flags |= O_WRONLY;
122 if (args->flags & LINUX_O_RDWR)
123 flags |= O_RDWR;
124 if (args->flags & LINUX_O_NDELAY)
125 flags |= O_NONBLOCK;
126 if (args->flags & LINUX_O_APPEND)
127 flags |= O_APPEND;
128 if (args->flags & LINUX_O_SYNC)
129 flags |= O_FSYNC;
130 if (args->flags & LINUX_O_NONBLOCK)
131 flags |= O_NONBLOCK;
132 if (args->flags & LINUX_FASYNC)
133 flags |= O_ASYNC;
134 if (args->flags & LINUX_O_CREAT)
135 flags |= O_CREAT;
136 if (args->flags & LINUX_O_TRUNC)
137 flags |= O_TRUNC;
138 if (args->flags & LINUX_O_EXCL)
139 flags |= O_EXCL;
140 if (args->flags & LINUX_O_NOCTTY)
141 flags |= O_NOCTTY;
142 get_mplock();
143 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
144 if (error == 0) {
145 error = kern_open(&nd, flags,
146 args->mode, &args->sysmsg_iresult);
149 if (error == 0 && !(flags & O_NOCTTY) &&
150 SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
151 struct file *fp;
153 fp = holdfp(p->p_fd, args->sysmsg_iresult, -1);
154 if (fp) {
155 if (fp->f_type == DTYPE_VNODE) {
156 fo_ioctl(fp, TIOCSCTTY, NULL,
157 td->td_ucred, NULL);
159 fdrop(fp);
162 rel_mplock();
163 #ifdef DEBUG
164 if (ldebug(open))
165 kprintf(LMSG("open returns error %d"), error);
166 #endif
167 linux_free_path(&path);
168 return error;
172 * MPSAFE
175 sys_linux_lseek(struct linux_lseek_args *args)
177 int error;
179 #ifdef DEBUG
180 if (ldebug(lseek))
181 kprintf(ARGS(lseek, "%d, %ld, %d"),
182 args->fdes, (long)args->off, args->whence);
183 #endif
184 error = kern_lseek(args->fdes, args->off, args->whence,
185 &args->sysmsg_offset);
187 return error;
191 * MPSAFE
194 sys_linux_llseek(struct linux_llseek_args *args)
196 int error;
197 off_t off, res;
199 #ifdef DEBUG
200 if (ldebug(llseek))
201 kprintf(ARGS(llseek, "%d, %d:%d, %d"),
202 args->fd, args->ohigh, args->olow, args->whence);
203 #endif
204 off = (args->olow) | (((off_t) args->ohigh) << 32);
206 error = kern_lseek(args->fd, off, args->whence, &res);
208 if (error == 0)
209 error = copyout(&res, args->res, sizeof(res));
210 return (error);
214 * MPSAFE
217 sys_linux_readdir(struct linux_readdir_args *args)
219 struct linux_getdents_args lda;
220 int error;
222 lda.fd = args->fd;
223 lda.dent = args->dent;
224 lda.count = -1;
225 lda.sysmsg_iresult = 0;
226 error = sys_linux_getdents(&lda);
227 args->sysmsg_iresult = lda.sysmsg_iresult;
228 return(error);
232 * Note that linux_getdents(2) and linux_getdents64(2) have the same
233 * arguments. They only differ in the definition of struct dirent they
234 * operate on. We use this to common the code, with the exception of
235 * accessing struct dirent. Note that linux_readdir(2) is implemented
236 * by means of linux_getdents(2). In this case we never operate on
237 * struct dirent64 and thus don't need to handle it...
240 struct l_dirent {
241 l_long d_ino;
242 l_off_t d_off;
243 l_ushort d_reclen;
244 char d_name[LINUX_NAME_MAX + 1];
247 struct l_dirent64 {
248 uint64_t d_ino;
249 int64_t d_off;
250 l_ushort d_reclen;
251 u_char d_type;
252 char d_name[LINUX_NAME_MAX + 1];
255 #define LINUX_RECLEN(de,namlen) \
256 ALIGN((((char *)&(de)->d_name - (char *)de) + (namlen) + 1))
258 #define LINUX_DIRBLKSIZ 512
261 * MPALMOSTSAFE
263 static int
264 getdents_common(struct linux_getdents64_args *args, int is64bit)
266 struct thread *td = curthread;
267 struct proc *p = td->td_proc;
268 struct dirent *bdp;
269 struct vnode *vp;
270 caddr_t inp, buf; /* BSD-format */
271 int reclen; /* BSD-format */
272 size_t len;
273 caddr_t outp; /* Linux-format */
274 int linuxreclen = 0; /* Linux-format */
275 size_t resid;
276 struct file *fp;
277 struct uio auio;
278 struct iovec aiov;
279 struct vattr va;
280 off_t off;
281 struct l_dirent linux_dirent;
282 struct l_dirent64 linux_dirent64;
283 int error, eofflag, justone;
284 size_t buflen, nbytes;
285 off_t *cookies = NULL, *cookiep;
286 int ncookies;
288 if ((error = holdvnode(p->p_fd, args->fd, &fp)) != 0)
289 return (error);
291 get_mplock();
292 if ((fp->f_flag & FREAD) == 0) {
293 error = EBADF;
294 goto done;
297 vp = (struct vnode *) fp->f_data;
298 if (vp->v_type != VDIR) {
299 error = EINVAL;
300 goto done;
303 if ((error = VOP_GETATTR(vp, &va)) != 0)
304 goto done;
306 nbytes = args->count;
307 if (nbytes == (size_t)-1) {
308 /* readdir(2) case. Always struct dirent. */
309 if (is64bit) {
310 error = EINVAL;
311 goto done;
313 nbytes = sizeof(linux_dirent);
314 justone = 1;
315 } else {
316 justone = 0;
318 if ((size_t)nbytes < 0)
319 nbytes = 0;
321 off = fp->f_offset;
323 buflen = max(LINUX_DIRBLKSIZ, nbytes);
324 buflen = min(buflen, MAXBSIZE);
325 buf = kmalloc(buflen, M_TEMP, M_WAITOK);
327 again:
328 aiov.iov_base = buf;
329 aiov.iov_len = buflen;
330 auio.uio_iov = &aiov;
331 auio.uio_iovcnt = 1;
332 auio.uio_rw = UIO_READ;
333 auio.uio_segflg = UIO_SYSSPACE;
334 auio.uio_td = td;
335 auio.uio_resid = buflen;
336 auio.uio_offset = off;
338 if (cookies) {
339 kfree(cookies, M_TEMP);
340 cookies = NULL;
343 eofflag = 0;
344 ncookies = 0;
345 if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies,
346 &cookies)))
347 goto out;
349 inp = buf;
350 outp = (caddr_t)args->dirent;
351 resid = nbytes;
352 if (auio.uio_resid >= buflen)
353 goto eof;
354 len = buflen - auio.uio_resid;
355 cookiep = cookies;
357 if (cookies) {
359 * When using cookies, the vfs has the option of reading from
360 * a different offset than that supplied (UFS truncates the
361 * offset to a block boundary to make sure that it never reads
362 * partway through a directory entry, even if the directory
363 * has been compacted).
365 while (len > 0 && ncookies > 0 && *cookiep < off) {
366 bdp = (struct dirent *) inp;
367 len -= _DIRENT_DIRSIZ(bdp);
368 inp += _DIRENT_DIRSIZ(bdp);
369 cookiep++;
370 ncookies--;
374 while (len > 0) {
375 if (cookiep && ncookies == 0)
376 break;
377 bdp = (struct dirent *) inp;
378 reclen = _DIRENT_DIRSIZ(bdp);
379 if (reclen & 3) {
380 error = EFAULT;
381 goto out;
384 if (bdp->d_ino == 0) {
385 inp += reclen;
386 if (cookiep) {
387 off = *cookiep++;
388 ++off;
389 ncookies--;
390 } else {
391 off += reclen;
393 len -= reclen;
394 continue;
397 linuxreclen = (is64bit)
398 ? LINUX_RECLEN(&linux_dirent64, bdp->d_namlen)
399 : LINUX_RECLEN(&linux_dirent, bdp->d_namlen);
401 if (reclen > len || resid < linuxreclen) {
402 outp++;
403 break;
406 bzero(&linux_dirent, sizeof(linux_dirent));
407 bzero(&linux_dirent64, sizeof(linux_dirent64));
408 if (justone) {
409 /* readdir(2) case. */
410 linux_dirent.d_ino = (l_long)INO64TO32(bdp->d_ino);
411 linux_dirent.d_off = (l_off_t)linuxreclen;
412 linux_dirent.d_reclen = (l_ushort)bdp->d_namlen;
413 strcpy(linux_dirent.d_name, bdp->d_name);
414 error = copyout(&linux_dirent, outp, linuxreclen);
415 } else {
416 if (is64bit) {
417 linux_dirent64.d_ino = bdp->d_ino;
418 linux_dirent64.d_off = (cookiep)
419 ? (l_off_t)*cookiep
420 : (l_off_t)(off + reclen);
421 linux_dirent64.d_reclen =
422 (l_ushort)linuxreclen;
423 linux_dirent64.d_type = bdp->d_type;
424 strcpy(linux_dirent64.d_name, bdp->d_name);
425 error = copyout(&linux_dirent64, outp,
426 linuxreclen);
427 } else {
428 linux_dirent.d_ino = INO64TO32(bdp->d_ino);
429 linux_dirent.d_off = (cookiep)
430 ? (l_off_t)*cookiep
431 : (l_off_t)(off + reclen);
432 linux_dirent.d_reclen = (l_ushort)linuxreclen;
433 strcpy(linux_dirent.d_name, bdp->d_name);
434 error = copyout(&linux_dirent, outp,
435 linuxreclen);
438 if (error)
439 goto out;
441 inp += reclen;
442 if (cookiep) {
443 off = *cookiep++;
444 ++off;
445 ncookies--;
446 } else {
447 off += reclen;
450 outp += linuxreclen;
451 resid -= linuxreclen;
452 len -= reclen;
453 if (justone)
454 break;
457 if (outp == (caddr_t)args->dirent && eofflag == 0)
458 goto again;
460 fp->f_offset = off;
461 if (justone)
462 nbytes = resid + linuxreclen;
464 eof:
465 args->sysmsg_iresult = (int)(nbytes - resid);
467 out:
468 if (cookies)
469 kfree(cookies, M_TEMP);
471 kfree(buf, M_TEMP);
472 done:
473 rel_mplock();
474 fdrop(fp);
475 return (error);
479 * MPSAFE
482 sys_linux_getdents(struct linux_getdents_args *args)
484 #ifdef DEBUG
485 if (ldebug(getdents))
486 kprintf(ARGS(getdents, "%d, *, %d"), args->fd, args->count);
487 #endif
488 return (getdents_common((struct linux_getdents64_args*)args, 0));
492 * MPSAFE
495 sys_linux_getdents64(struct linux_getdents64_args *args)
497 #ifdef DEBUG
498 if (ldebug(getdents64))
499 kprintf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count);
500 #endif
501 return (getdents_common(args, 1));
505 * These exist mainly for hooks for doing /compat/linux translation.
507 * MPALMOSTSAFE
510 sys_linux_access(struct linux_access_args *args)
512 struct nlookupdata nd;
513 char *path;
514 int error;
516 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
517 if (error)
518 return (error);
519 #ifdef DEBUG
520 if (ldebug(access))
521 kprintf(ARGS(access, "%s, %d"), path, args->flags);
522 #endif
523 get_mplock();
524 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
525 if (error == 0)
526 error = kern_access(&nd, args->flags, 0);
527 nlookup_done(&nd);
528 rel_mplock();
529 linux_free_path(&path);
530 return(error);
534 * MPALMOSTSAFE
537 sys_linux_unlink(struct linux_unlink_args *args)
539 struct nlookupdata nd;
540 char *path;
541 int error;
543 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
544 if (error)
545 return (error);
546 #ifdef DEBUG
547 if (ldebug(unlink))
548 kprintf(ARGS(unlink, "%s"), path);
549 #endif
550 get_mplock();
551 error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
552 if (error == 0)
553 error = kern_unlink(&nd);
554 nlookup_done(&nd);
555 rel_mplock();
556 linux_free_path(&path);
557 return(error);
561 * MPALMOSTSAFE
564 sys_linux_chdir(struct linux_chdir_args *args)
566 struct nlookupdata nd;
567 char *path;
568 int error;
570 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
571 if (error)
572 return (error);
573 #ifdef DEBUG
574 if (ldebug(chdir))
575 kprintf(ARGS(chdir, "%s"), path);
576 #endif
577 get_mplock();
578 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
579 if (error == 0) {
580 error = kern_chdir(&nd);
581 nlookup_done(&nd);
583 rel_mplock();
584 linux_free_path(&path);
585 return(error);
589 * MPALMOSTSAFE
592 sys_linux_chmod(struct linux_chmod_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(chmod))
603 kprintf(ARGS(chmod, "%s, %d"), path, args->mode);
604 #endif
605 get_mplock();
606 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
607 if (error == 0)
608 error = kern_chmod(&nd, args->mode);
609 nlookup_done(&nd);
610 rel_mplock();
611 linux_free_path(&path);
612 return(error);
616 * MPALMOSTSAFE
619 sys_linux_mkdir(struct linux_mkdir_args *args)
621 struct nlookupdata nd;
622 char *path;
623 int error;
625 error = linux_copyin_path(args->path, &path, LINUX_PATH_CREATE);
626 if (error)
627 return (error);
628 #ifdef DEBUG
629 if (ldebug(mkdir))
630 kprintf(ARGS(mkdir, "%s, %d"), path, args->mode);
631 #endif
632 get_mplock();
633 error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
634 if (error == 0)
635 error = kern_mkdir(&nd, args->mode);
636 nlookup_done(&nd);
637 rel_mplock();
639 linux_free_path(&path);
640 return(error);
644 * MPALMOSTSAFE
647 sys_linux_rmdir(struct linux_rmdir_args *args)
649 struct nlookupdata nd;
650 char *path;
651 int error;
653 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
654 if (error)
655 return (error);
656 #ifdef DEBUG
657 if (ldebug(rmdir))
658 kprintf(ARGS(rmdir, "%s"), path);
659 #endif
660 get_mplock();
661 error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
662 if (error == 0)
663 error = kern_rmdir(&nd);
664 nlookup_done(&nd);
665 rel_mplock();
666 linux_free_path(&path);
667 return(error);
671 * MPALMOSTSAFE
674 sys_linux_rename(struct linux_rename_args *args)
676 struct nlookupdata fromnd, tond;
677 char *from, *to;
678 int error;
680 error = linux_copyin_path(args->from, &from, LINUX_PATH_EXISTS);
681 if (error)
682 return (error);
683 error = linux_copyin_path(args->to, &to, LINUX_PATH_CREATE);
684 if (error) {
685 linux_free_path(&from);
686 return (error);
688 #ifdef DEBUG
689 if (ldebug(rename))
690 kprintf(ARGS(rename, "%s, %s"), from, to);
691 #endif
692 get_mplock();
693 error = nlookup_init(&fromnd, from, UIO_SYSSPACE, 0);
694 if (error == 0) {
695 error = nlookup_init(&tond, to, UIO_SYSSPACE, 0);
696 if (error == 0)
697 error = kern_rename(&fromnd, &tond);
698 nlookup_done(&tond);
700 nlookup_done(&fromnd);
701 rel_mplock();
702 linux_free_path(&from);
703 linux_free_path(&to);
704 return(error);
708 * MPALMOSTSAFE
711 sys_linux_symlink(struct linux_symlink_args *args)
713 struct thread *td = curthread;
714 struct nlookupdata nd;
715 char *path, *link;
716 int error;
717 int mode;
719 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
720 if (error)
721 return (error);
722 error = linux_copyin_path(args->to, &link, LINUX_PATH_CREATE);
723 if (error) {
724 linux_free_path(&path);
725 return (error);
727 #ifdef DEBUG
728 if (ldebug(symlink))
729 kprintf(ARGS(symlink, "%s, %s"), path, link);
730 #endif
731 get_mplock();
732 error = nlookup_init(&nd, link, UIO_SYSSPACE, 0);
733 if (error == 0) {
734 mode = ACCESSPERMS & ~td->td_proc->p_fd->fd_cmask;
735 error = kern_symlink(&nd, path, mode);
737 nlookup_done(&nd);
738 rel_mplock();
739 linux_free_path(&path);
740 linux_free_path(&link);
741 return(error);
745 * MPALMOSTSAFE
748 sys_linux_readlink(struct linux_readlink_args *args)
750 struct nlookupdata nd;
751 char *path;
752 int error;
754 error = linux_copyin_path(args->name, &path, LINUX_PATH_EXISTS);
755 if (error)
756 return (error);
757 #ifdef DEBUG
758 if (ldebug(readlink))
759 kprintf(ARGS(readlink, "%s, %p, %d"), path, (void *)args->buf,
760 args->count);
761 #endif
762 get_mplock();
763 error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
764 if (error == 0) {
765 error = kern_readlink(&nd, args->buf, args->count,
766 &args->sysmsg_iresult);
768 nlookup_done(&nd);
769 rel_mplock();
770 linux_free_path(&path);
771 return(error);
775 * MPALMOSTSAFE
778 sys_linux_truncate(struct linux_truncate_args *args)
780 struct nlookupdata nd;
781 char *path;
782 int error;
784 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
785 if (error)
786 return (error);
787 #ifdef DEBUG
788 if (ldebug(truncate))
789 kprintf(ARGS(truncate, "%s, %ld"), path,
790 (long)args->length);
791 #endif
792 get_mplock();
793 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
794 if (error == 0)
795 error = kern_truncate(&nd, args->length);
796 nlookup_done(&nd);
797 rel_mplock();
798 linux_free_path(&path);
799 return(error);
803 * MPALMOSTSAFE
806 sys_linux_truncate64(struct linux_truncate64_args *args)
808 struct nlookupdata nd;
809 char *path;
810 int error;
812 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
813 if (error)
814 return (error);
815 #ifdef DEBUG
816 if (ldebug(truncate64))
817 kprintf(ARGS(truncate64, "%s, %lld"), path,
818 (off_t)args->length);
819 #endif
820 get_mplock();
821 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
822 if (error == 0)
823 error = kern_truncate(&nd, args->length);
824 nlookup_done(&nd);
825 rel_mplock();
826 linux_free_path(&path);
827 return error;
831 * MPALMOSTSAFE
834 sys_linux_ftruncate(struct linux_ftruncate_args *args)
836 int error;
838 #ifdef DEBUG
839 if (ldebug(ftruncate))
840 kprintf(ARGS(ftruncate, "%d, %ld"), args->fd,
841 (long)args->length);
842 #endif
843 get_mplock();
844 error = kern_ftruncate(args->fd, args->length);
845 rel_mplock();
847 return error;
851 * MPALMOSTSAFE
854 sys_linux_ftruncate64(struct linux_ftruncate64_args *args)
856 int error;
858 #ifdef DEBUG
859 if (ldebug(ftruncate))
860 kprintf(ARGS(ftruncate64, "%d, %lld"), args->fd,
861 (off_t)args->length);
862 #endif
863 get_mplock();
864 error = kern_ftruncate(args->fd, args->length);
865 rel_mplock();
867 return error;
871 * MPALMOSTSAFE
874 sys_linux_link(struct linux_link_args *args)
876 struct nlookupdata nd, linknd;
877 char *path, *link;
878 int error;
880 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
881 if (error)
882 return (error);
883 error = linux_copyin_path(args->to, &link, LINUX_PATH_CREATE);
884 if (error) {
885 linux_free_path(&path);
886 return (error);
888 #ifdef DEBUG
889 if (ldebug(link))
890 kprintf(ARGS(link, "%s, %s"), path, link);
891 #endif
892 get_mplock();
893 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
894 if (error == 0) {
895 error = nlookup_init(&linknd, link, UIO_SYSSPACE, 0);
896 if (error == 0)
897 error = kern_link(&nd, &linknd);
898 nlookup_done(&linknd);
900 nlookup_done(&nd);
901 rel_mplock();
902 linux_free_path(&path);
903 linux_free_path(&link);
904 return(error);
908 * MPSAFE
911 sys_linux_fdatasync(struct linux_fdatasync_args *uap)
913 struct fsync_args bsd;
914 int error;
916 bsd.fd = uap->fd;
917 bsd.sysmsg_iresult = 0;
919 error = sys_fsync(&bsd);
920 uap->sysmsg_iresult = bsd.sysmsg_iresult;
921 return(error);
925 * MPSAFE
928 sys_linux_pread(struct linux_pread_args *uap)
930 struct thread *td = curthread;
931 struct uio auio;
932 struct iovec aiov;
933 int error;
935 aiov.iov_base = uap->buf;
936 aiov.iov_len = uap->nbyte;
937 auio.uio_iov = &aiov;
938 auio.uio_iovcnt = 1;
939 auio.uio_offset = uap->offset;
940 auio.uio_resid = uap->nbyte;
941 auio.uio_rw = UIO_READ;
942 auio.uio_segflg = UIO_USERSPACE;
943 auio.uio_td = td;
945 if ((ssize_t)auio.uio_resid < 0) {
946 error = EINVAL;
947 } else {
948 error = kern_preadv(uap->fd, &auio, O_FOFFSET,
949 &uap->sysmsg_szresult);
951 return(error);
955 * MPSAFE
958 sys_linux_pwrite(struct linux_pwrite_args *uap)
960 struct thread *td = curthread;
961 struct uio auio;
962 struct iovec aiov;
963 int error;
965 aiov.iov_base = uap->buf;
966 aiov.iov_len = uap->nbyte;
967 auio.uio_iov = &aiov;
968 auio.uio_iovcnt = 1;
969 auio.uio_offset = uap->offset;
970 auio.uio_resid = uap->nbyte;
971 auio.uio_rw = UIO_WRITE;
972 auio.uio_segflg = UIO_USERSPACE;
973 auio.uio_td = td;
975 if ((ssize_t)auio.uio_resid < 0) {
976 error = EINVAL;
977 } else {
978 error = kern_pwritev(uap->fd, &auio, O_FOFFSET,
979 &uap->sysmsg_szresult);
981 return(error);
985 * MPSAFE
988 sys_linux_oldumount(struct linux_oldumount_args *args)
990 struct linux_umount_args args2;
991 int error;
993 args2.path = args->path;
994 args2.flags = 0;
995 args2.sysmsg_iresult = 0;
996 error = sys_linux_umount(&args2);
997 args->sysmsg_iresult = args2.sysmsg_iresult;
998 return(error);
1002 * MPSAFE
1005 sys_linux_umount(struct linux_umount_args *args)
1007 struct unmount_args bsd;
1008 int error;
1010 bsd.path = args->path;
1011 bsd.flags = args->flags; /* XXX correct? */
1012 bsd.sysmsg_iresult = 0;
1014 error = sys_unmount(&bsd);
1015 args->sysmsg_iresult = bsd.sysmsg_iresult;
1016 return(error);
1020 * fcntl family of syscalls
1022 struct l_flock {
1023 l_short l_type;
1024 l_short l_whence;
1025 l_off_t l_start;
1026 l_off_t l_len;
1027 l_pid_t l_pid;
1031 * MPSAFE
1033 static void
1034 linux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock)
1036 switch (linux_flock->l_type) {
1037 case LINUX_F_RDLCK:
1038 bsd_flock->l_type = F_RDLCK;
1039 break;
1040 case LINUX_F_WRLCK:
1041 bsd_flock->l_type = F_WRLCK;
1042 break;
1043 case LINUX_F_UNLCK:
1044 bsd_flock->l_type = F_UNLCK;
1045 break;
1046 default:
1047 bsd_flock->l_type = -1;
1048 break;
1050 bsd_flock->l_whence = linux_flock->l_whence;
1051 bsd_flock->l_start = (off_t)linux_flock->l_start;
1052 bsd_flock->l_len = (off_t)linux_flock->l_len;
1053 bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1057 * MPSAFE
1059 static void
1060 bsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock)
1062 switch (bsd_flock->l_type) {
1063 case F_RDLCK:
1064 linux_flock->l_type = LINUX_F_RDLCK;
1065 break;
1066 case F_WRLCK:
1067 linux_flock->l_type = LINUX_F_WRLCK;
1068 break;
1069 case F_UNLCK:
1070 linux_flock->l_type = LINUX_F_UNLCK;
1071 break;
1073 linux_flock->l_whence = bsd_flock->l_whence;
1074 linux_flock->l_start = (l_off_t)bsd_flock->l_start;
1075 linux_flock->l_len = (l_off_t)bsd_flock->l_len;
1076 linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
1079 #if defined(__i386__)
1080 struct l_flock64 {
1081 l_short l_type;
1082 l_short l_whence;
1083 l_loff_t l_start;
1084 l_loff_t l_len;
1085 l_pid_t l_pid;
1089 * MPSAFE
1091 static void
1092 linux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock)
1094 switch (linux_flock->l_type) {
1095 case LINUX_F_RDLCK:
1096 bsd_flock->l_type = F_RDLCK;
1097 break;
1098 case LINUX_F_WRLCK:
1099 bsd_flock->l_type = F_WRLCK;
1100 break;
1101 case LINUX_F_UNLCK:
1102 bsd_flock->l_type = F_UNLCK;
1103 break;
1104 default:
1105 bsd_flock->l_type = -1;
1106 break;
1108 bsd_flock->l_whence = linux_flock->l_whence;
1109 bsd_flock->l_start = (off_t)linux_flock->l_start;
1110 bsd_flock->l_len = (off_t)linux_flock->l_len;
1111 bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1115 * MPSAFE
1117 static void
1118 bsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock)
1120 switch (bsd_flock->l_type) {
1121 case F_RDLCK:
1122 linux_flock->l_type = LINUX_F_RDLCK;
1123 break;
1124 case F_WRLCK:
1125 linux_flock->l_type = LINUX_F_WRLCK;
1126 break;
1127 case F_UNLCK:
1128 linux_flock->l_type = LINUX_F_UNLCK;
1129 break;
1131 linux_flock->l_whence = bsd_flock->l_whence;
1132 linux_flock->l_start = (l_loff_t)bsd_flock->l_start;
1133 linux_flock->l_len = (l_loff_t)bsd_flock->l_len;
1134 linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
1136 #endif /* __i386__ */
1139 * MPSAFE
1141 static int
1142 linux_fcntl_common(struct linux_fcntl64_args *args)
1144 struct thread *td = curthread;
1145 struct l_flock linux_flock;
1146 struct file *fp;
1147 union fcntl_dat dat;
1148 int error, cmd;
1150 switch (args->cmd) {
1151 case LINUX_F_DUPFD:
1152 cmd = F_DUPFD;
1153 dat.fc_fd = args->arg;
1154 break;
1155 case LINUX_F_GETFD:
1156 cmd = F_GETFD;
1157 break;
1158 case LINUX_F_SETFD:
1159 cmd = F_SETFD;
1160 dat.fc_cloexec = args->arg;
1161 break;
1162 case LINUX_F_GETFL:
1163 cmd = F_GETFL;
1164 break;
1165 case LINUX_F_SETFL:
1166 cmd = F_SETFL;
1167 dat.fc_flags = 0;
1168 if (args->arg & LINUX_O_NDELAY)
1169 dat.fc_flags |= O_NONBLOCK;
1170 if (args->arg & LINUX_O_APPEND)
1171 dat.fc_flags |= O_APPEND;
1172 if (args->arg & LINUX_O_SYNC)
1173 dat.fc_flags |= O_FSYNC;
1174 if (args->arg & LINUX_FASYNC)
1175 dat.fc_flags |= O_ASYNC;
1176 break;
1177 case LINUX_F_GETLK:
1178 case LINUX_F_SETLK:
1179 case LINUX_F_SETLKW:
1180 cmd = F_GETLK;
1181 error = copyin((caddr_t)args->arg, &linux_flock,
1182 sizeof(linux_flock));
1183 if (error)
1184 return (error);
1185 linux_to_bsd_flock(&linux_flock, &dat.fc_flock);
1186 break;
1187 case LINUX_F_GETOWN:
1188 cmd = F_GETOWN;
1189 break;
1190 case LINUX_F_SETOWN:
1192 * XXX some Linux applications depend on F_SETOWN having no
1193 * significant effect for pipes (SIGIO is not delivered for
1194 * pipes under Linux-2.2.35 at least).
1196 fp = holdfp(td->td_proc->p_fd, args->fd, -1);
1197 if (fp == NULL)
1198 return (EBADF);
1199 if (fp->f_type == DTYPE_PIPE) {
1200 fdrop(fp);
1201 return (EINVAL);
1203 fdrop(fp);
1204 cmd = F_SETOWN;
1205 dat.fc_owner = args->arg;
1206 break;
1207 default:
1208 return (EINVAL);
1211 /* MPSAFE */
1212 error = kern_fcntl(args->fd, cmd, &dat, td->td_ucred);
1214 if (error == 0) {
1215 switch (args->cmd) {
1216 case LINUX_F_DUPFD:
1217 args->sysmsg_iresult = dat.fc_fd;
1218 break;
1219 case LINUX_F_GETFD:
1220 args->sysmsg_iresult = dat.fc_cloexec;
1221 break;
1222 case LINUX_F_SETFD:
1223 break;
1224 case LINUX_F_GETFL:
1225 args->sysmsg_iresult = 0;
1226 if (dat.fc_flags & O_RDONLY)
1227 args->sysmsg_iresult |= LINUX_O_RDONLY;
1228 if (dat.fc_flags & O_WRONLY)
1229 args->sysmsg_iresult |= LINUX_O_WRONLY;
1230 if (dat.fc_flags & O_RDWR)
1231 args->sysmsg_iresult |= LINUX_O_RDWR;
1232 if (dat.fc_flags & O_NDELAY)
1233 args->sysmsg_iresult |= LINUX_O_NONBLOCK;
1234 if (dat.fc_flags & O_APPEND)
1235 args->sysmsg_iresult |= LINUX_O_APPEND;
1236 if (dat.fc_flags & O_FSYNC)
1237 args->sysmsg_iresult |= LINUX_O_SYNC;
1238 if (dat.fc_flags & O_ASYNC)
1239 args->sysmsg_iresult |= LINUX_FASYNC;
1240 break;
1241 case LINUX_F_GETLK:
1242 bsd_to_linux_flock(&dat.fc_flock, &linux_flock);
1243 error = copyout(&linux_flock, (caddr_t)args->arg,
1244 sizeof(linux_flock));
1245 break;
1246 case LINUX_F_SETLK:
1247 case LINUX_F_SETLKW:
1248 break;
1249 case LINUX_F_GETOWN:
1250 args->sysmsg_iresult = dat.fc_owner;
1251 break;
1252 case LINUX_F_SETOWN:
1253 break;
1257 return(error);
1261 * MPSAFE
1264 sys_linux_fcntl(struct linux_fcntl_args *args)
1266 struct linux_fcntl64_args args64;
1267 int error;
1269 #ifdef DEBUG
1270 if (ldebug(fcntl))
1271 kprintf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd);
1272 #endif
1274 args64.fd = args->fd;
1275 args64.cmd = args->cmd;
1276 args64.arg = args->arg;
1277 args64.sysmsg_iresult = 0;
1278 error = linux_fcntl_common(&args64);
1279 args->sysmsg_iresult = args64.sysmsg_iresult;
1280 return(error);
1283 #if defined(__i386__)
1285 * MPSAFE
1288 sys_linux_fcntl64(struct linux_fcntl64_args *args)
1290 struct thread *td = curthread;
1291 struct l_flock64 linux_flock;
1292 union fcntl_dat dat;
1293 int error, cmd = 0;
1295 #ifdef DEBUG
1296 if (ldebug(fcntl64))
1297 kprintf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd);
1298 #endif
1299 if (args->cmd == LINUX_F_GETLK64 || args->cmd == LINUX_F_SETLK64 ||
1300 args->cmd == LINUX_F_SETLKW64) {
1301 switch (args->cmd) {
1302 case LINUX_F_GETLK64:
1303 cmd = F_GETLK;
1304 break;
1305 case LINUX_F_SETLK64:
1306 cmd = F_SETLK;
1307 break;
1308 case LINUX_F_SETLKW64:
1309 cmd = F_SETLKW;
1310 break;
1313 error = copyin((caddr_t)args->arg, &linux_flock,
1314 sizeof(linux_flock));
1315 if (error)
1316 return (error);
1317 linux_to_bsd_flock64(&linux_flock, &dat.fc_flock);
1319 /* MPSAFE */
1320 error = kern_fcntl(args->fd, cmd, &dat, td->td_ucred);
1322 if (error == 0 && args->cmd == LINUX_F_GETLK64) {
1323 bsd_to_linux_flock64(&dat.fc_flock, &linux_flock);
1324 error = copyout(&linux_flock, (caddr_t)args->arg,
1325 sizeof(linux_flock));
1327 } else {
1328 error = linux_fcntl_common(args);
1331 return (error);
1333 #endif /* __i386__ */
1336 * MPALMOSTSAFE
1339 sys_linux_chown(struct linux_chown_args *args)
1341 struct nlookupdata nd;
1342 char *path;
1343 int error;
1345 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
1346 if (error)
1347 return (error);
1348 #ifdef DEBUG
1349 if (ldebug(chown))
1350 kprintf(ARGS(chown, "%s, %d, %d"), path, args->uid, args->gid);
1351 #endif
1352 get_mplock();
1353 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
1354 if (error == 0)
1355 error = kern_chown(&nd, args->uid, args->gid);
1356 nlookup_done(&nd);
1357 rel_mplock();
1358 linux_free_path(&path);
1359 return(error);
1363 * MPALMOSTSAFE
1366 sys_linux_lchown(struct linux_lchown_args *args)
1368 struct nlookupdata nd;
1369 char *path;
1370 int error;
1372 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
1373 if (error)
1374 return (error);
1375 #ifdef DEBUG
1376 if (ldebug(lchown))
1377 kprintf(ARGS(lchown, "%s, %d, %d"), path, args->uid, args->gid);
1378 #endif
1379 get_mplock();
1380 error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
1381 if (error == 0)
1382 error = kern_chown(&nd, args->uid, args->gid);
1383 nlookup_done(&nd);
1384 rel_mplock();
1385 linux_free_path(&path);
1386 return(error);