Pull the fix from procfs_vnops.c:1.27 also to linprocfs
[dragonfly.git] / sys / emulation / linux / linux_file.c
blob685c0039b7a48eb85ae3d9937caa7d8ee18c5dd7
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.24 2005/08/27 20:23:05 joerg 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 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 printf(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_result);
80 linux_free_path(&path);
81 return(error);
84 int
85 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 printf(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_result);
141 if (error == 0 && !(flags & O_NOCTTY) &&
142 SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
143 struct filedesc *fdp = p->p_fd;
144 struct file *fp = fdp->fd_files[args->sysmsg_result].fp;
146 if (fp->f_type == DTYPE_VNODE)
147 fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0, td);
149 #ifdef DEBUG
150 if (ldebug(open))
151 printf(LMSG("open returns error %d"), error);
152 #endif
153 linux_free_path(&path);
154 return error;
158 linux_lseek(struct linux_lseek_args *args)
160 int error;
162 #ifdef DEBUG
163 if (ldebug(lseek))
164 printf(ARGS(lseek, "%d, %ld, %d"),
165 args->fdes, (long)args->off, args->whence);
166 #endif
167 error = kern_lseek(args->fdes, args->off, args->whence,
168 &args->sysmsg_offset);
170 return error;
174 linux_llseek(struct linux_llseek_args *args)
176 int error;
177 off_t off, res;
179 #ifdef DEBUG
180 if (ldebug(llseek))
181 printf(ARGS(llseek, "%d, %d:%d, %d"),
182 args->fd, args->ohigh, args->olow, args->whence);
183 #endif
184 off = (args->olow) | (((off_t) args->ohigh) << 32);
186 error = kern_lseek(args->fd, off, args->whence, &res);
188 if (error == 0)
189 error = copyout(&res, args->res, sizeof(res));
190 return (error);
194 linux_readdir(struct linux_readdir_args *args)
196 struct linux_getdents_args lda;
197 int error;
199 lda.fd = args->fd;
200 lda.dent = args->dent;
201 lda.count = 1;
202 lda.sysmsg_result = 0;
203 error = linux_getdents(&lda);
204 args->sysmsg_result = lda.sysmsg_result;
205 return(error);
209 * Note that linux_getdents(2) and linux_getdents64(2) have the same
210 * arguments. They only differ in the definition of struct dirent they
211 * operate on. We use this to common the code, with the exception of
212 * accessing struct dirent. Note that linux_readdir(2) is implemented
213 * by means of linux_getdents(2). In this case we never operate on
214 * struct dirent64 and thus don't need to handle it...
217 struct l_dirent {
218 l_long d_ino;
219 l_off_t d_off;
220 l_ushort d_reclen;
221 char d_name[LINUX_NAME_MAX + 1];
224 struct l_dirent64 {
225 uint64_t d_ino;
226 int64_t d_off;
227 l_ushort d_reclen;
228 u_char d_type;
229 char d_name[LINUX_NAME_MAX + 1];
232 #define LINUX_RECLEN(de,namlen) \
233 ALIGN((((char *)&(de)->d_name - (char *)de) + (namlen) + 1))
235 #define LINUX_DIRBLKSIZ 512
237 static int
238 getdents_common(struct linux_getdents64_args *args, int is64bit)
240 struct thread *td = curthread;
241 struct proc *p = td->td_proc;
242 struct dirent *bdp;
243 struct vnode *vp;
244 caddr_t inp, buf; /* BSD-format */
245 int len, reclen; /* BSD-format */
246 caddr_t outp; /* Linux-format */
247 int resid, linuxreclen=0; /* Linux-format */
248 struct file *fp;
249 struct uio auio;
250 struct iovec aiov;
251 struct vattr va;
252 off_t off;
253 struct l_dirent linux_dirent;
254 struct l_dirent64 linux_dirent64;
255 int buflen, error, eofflag, nbytes, justone;
256 u_long *cookies = NULL, *cookiep;
257 int ncookies;
259 KKASSERT(p);
261 if ((error = getvnode(p->p_fd, args->fd, &fp)) != 0)
262 return (error);
264 if ((fp->f_flag & FREAD) == 0)
265 return (EBADF);
267 vp = (struct vnode *) fp->f_data;
268 if (vp->v_type != VDIR)
269 return (EINVAL);
271 if ((error = VOP_GETATTR(vp, &va, td)))
272 return (error);
274 nbytes = args->count;
275 if (nbytes == 1) {
276 /* readdir(2) case. Always struct dirent. */
277 if (is64bit)
278 return (EINVAL);
279 nbytes = sizeof(linux_dirent);
280 justone = 1;
281 } else
282 justone = 0;
284 off = fp->f_offset;
286 buflen = max(LINUX_DIRBLKSIZ, nbytes);
287 buflen = min(buflen, MAXBSIZE);
288 buf = malloc(buflen, M_TEMP, M_WAITOK);
289 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
291 again:
292 aiov.iov_base = buf;
293 aiov.iov_len = buflen;
294 auio.uio_iov = &aiov;
295 auio.uio_iovcnt = 1;
296 auio.uio_rw = UIO_READ;
297 auio.uio_segflg = UIO_SYSSPACE;
298 auio.uio_td = td;
299 auio.uio_resid = buflen;
300 auio.uio_offset = off;
302 if (cookies) {
303 free(cookies, M_TEMP);
304 cookies = NULL;
307 if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies,
308 &cookies)))
309 goto out;
311 inp = buf;
312 outp = (caddr_t)args->dirent;
313 resid = nbytes;
314 if ((len = buflen - auio.uio_resid) <= 0)
315 goto eof;
317 cookiep = cookies;
319 if (cookies) {
321 * When using cookies, the vfs has the option of reading from
322 * a different offset than that supplied (UFS truncates the
323 * offset to a block boundary to make sure that it never reads
324 * partway through a directory entry, even if the directory
325 * has been compacted).
327 while (len > 0 && ncookies > 0 && *cookiep <= off) {
328 bdp = (struct dirent *) inp;
329 len -= _DIRENT_DIRSIZ(bdp);
330 inp += _DIRENT_DIRSIZ(bdp);
331 cookiep++;
332 ncookies--;
336 while (len > 0) {
337 if (cookiep && ncookies == 0)
338 break;
339 bdp = (struct dirent *) inp;
340 reclen = _DIRENT_DIRSIZ(bdp);
341 if (reclen & 3) {
342 error = EFAULT;
343 goto out;
346 if (bdp->d_ino == 0) {
347 inp += reclen;
348 if (cookiep) {
349 off = *cookiep++;
350 ncookies--;
351 } else
352 off += reclen;
354 len -= reclen;
355 continue;
358 linuxreclen = (is64bit)
359 ? LINUX_RECLEN(&linux_dirent64, bdp->d_namlen)
360 : LINUX_RECLEN(&linux_dirent, bdp->d_namlen);
362 if (reclen > len || resid < linuxreclen) {
363 outp++;
364 break;
367 if (justone) {
368 /* readdir(2) case. */
369 linux_dirent.d_ino = (l_long)bdp->d_ino;
370 linux_dirent.d_off = (l_off_t)linuxreclen;
371 linux_dirent.d_reclen = (l_ushort)bdp->d_namlen;
372 strcpy(linux_dirent.d_name, bdp->d_name);
373 error = copyout(&linux_dirent, outp, linuxreclen);
374 } else {
375 if (is64bit) {
376 linux_dirent64.d_ino = bdp->d_ino;
377 linux_dirent64.d_off = (cookiep)
378 ? (l_off_t)*cookiep
379 : (l_off_t)(off + reclen);
380 linux_dirent64.d_reclen =
381 (l_ushort)linuxreclen;
382 linux_dirent64.d_type = bdp->d_type;
383 strcpy(linux_dirent64.d_name, bdp->d_name);
384 error = copyout(&linux_dirent64, outp,
385 linuxreclen);
386 } else {
387 linux_dirent.d_ino = bdp->d_ino;
388 linux_dirent.d_off = (cookiep)
389 ? (l_off_t)*cookiep
390 : (l_off_t)(off + reclen);
391 linux_dirent.d_reclen = (l_ushort)linuxreclen;
392 strcpy(linux_dirent.d_name, bdp->d_name);
393 error = copyout(&linux_dirent, outp,
394 linuxreclen);
397 if (error)
398 goto out;
400 inp += reclen;
401 if (cookiep) {
402 off = *cookiep++;
403 ncookies--;
404 } else
405 off += reclen;
407 outp += linuxreclen;
408 resid -= linuxreclen;
409 len -= reclen;
410 if (justone)
411 break;
414 if (outp == (caddr_t)args->dirent)
415 goto again;
417 fp->f_offset = off;
418 if (justone)
419 nbytes = resid + linuxreclen;
421 eof:
422 args->sysmsg_result = nbytes - resid;
424 out:
425 if (cookies)
426 free(cookies, M_TEMP);
428 VOP_UNLOCK(vp, 0, td);
429 free(buf, M_TEMP);
430 return (error);
434 linux_getdents(struct linux_getdents_args *args)
436 #ifdef DEBUG
437 if (ldebug(getdents))
438 printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count);
439 #endif
440 return (getdents_common((struct linux_getdents64_args*)args, 0));
444 linux_getdents64(struct linux_getdents64_args *args)
446 #ifdef DEBUG
447 if (ldebug(getdents64))
448 printf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count);
449 #endif
450 return (getdents_common(args, 1));
454 * These exist mainly for hooks for doing /compat/linux translation.
458 linux_access(struct linux_access_args *args)
460 struct nlookupdata nd;
461 char *path;
462 int error;
464 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
465 if (error)
466 return (error);
467 #ifdef DEBUG
468 if (ldebug(access))
469 printf(ARGS(access, "%s, %d"), path, args->flags);
470 #endif
471 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
472 if (error == 0)
473 error = kern_access(&nd, args->flags);
474 nlookup_done(&nd);
475 linux_free_path(&path);
476 return(error);
480 linux_unlink(struct linux_unlink_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(unlink))
491 printf(ARGS(unlink, "%s"), path);
492 #endif
493 error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
494 if (error == 0)
495 error = kern_unlink(&nd);
496 nlookup_done(&nd);
497 linux_free_path(&path);
498 return(error);
502 linux_chdir(struct linux_chdir_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(chdir))
513 printf(ARGS(chdir, "%s"), path);
514 #endif
515 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
516 if (error == 0) {
517 error = kern_chdir(&nd);
518 nlookup_done(&nd);
520 linux_free_path(&path);
521 return(error);
525 linux_chmod(struct linux_chmod_args *args)
527 struct nlookupdata nd;
528 char *path;
529 int error;
531 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
532 if (error)
533 return (error);
534 #ifdef DEBUG
535 if (ldebug(chmod))
536 printf(ARGS(chmod, "%s, %d"), path, args->mode);
537 #endif
538 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
539 if (error == 0)
540 error = kern_chmod(&nd, args->mode);
541 nlookup_done(&nd);
542 linux_free_path(&path);
543 return(error);
547 linux_mkdir(struct linux_mkdir_args *args)
549 struct nlookupdata nd;
550 char *path;
551 int error;
553 error = linux_copyin_path(args->path, &path, LINUX_PATH_CREATE);
554 if (error)
555 return (error);
556 #ifdef DEBUG
557 if (ldebug(mkdir))
558 printf(ARGS(mkdir, "%s, %d"), path, args->mode);
559 #endif
560 error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
561 if (error == 0)
562 error = kern_mkdir(&nd, args->mode);
563 nlookup_done(&nd);
565 linux_free_path(&path);
566 return(error);
570 linux_rmdir(struct linux_rmdir_args *args)
572 struct nlookupdata nd;
573 char *path;
574 int error;
576 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
577 if (error)
578 return (error);
579 #ifdef DEBUG
580 if (ldebug(rmdir))
581 printf(ARGS(rmdir, "%s"), path);
582 #endif
583 error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
584 if (error == 0)
585 error = kern_rmdir(&nd);
586 nlookup_done(&nd);
587 linux_free_path(&path);
588 return(error);
592 linux_rename(struct linux_rename_args *args)
594 struct nlookupdata fromnd, tond;
595 char *from, *to;
596 int error;
598 error = linux_copyin_path(args->from, &from, LINUX_PATH_EXISTS);
599 if (error)
600 return (error);
601 error = linux_copyin_path(args->to, &to, LINUX_PATH_CREATE);
602 if (error) {
603 linux_free_path(&from);
604 return (error);
606 #ifdef DEBUG
607 if (ldebug(rename))
608 printf(ARGS(rename, "%s, %s"), from, to);
609 #endif
610 error = nlookup_init(&fromnd, from, UIO_SYSSPACE, 0);
611 if (error == 0) {
612 error = nlookup_init(&tond, to, UIO_SYSSPACE, 0);
613 if (error == 0)
614 error = kern_rename(&fromnd, &tond);
615 nlookup_done(&tond);
617 nlookup_done(&fromnd);
618 linux_free_path(&from);
619 linux_free_path(&to);
620 return(error);
624 linux_symlink(struct linux_symlink_args *args)
626 struct thread *td = curthread;
627 struct nlookupdata nd;
628 char *path, *link;
629 int error;
630 int mode;
632 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
633 if (error)
634 return (error);
635 error = linux_copyin_path(args->to, &link, LINUX_PATH_CREATE);
636 if (error) {
637 linux_free_path(&path);
638 return (error);
640 #ifdef DEBUG
641 if (ldebug(symlink))
642 printf(ARGS(symlink, "%s, %s"), path, link);
643 #endif
644 error = nlookup_init(&nd, link, UIO_SYSSPACE, 0);
645 if (error == 0) {
646 mode = ACCESSPERMS & ~td->td_proc->p_fd->fd_cmask;
647 error = kern_symlink(&nd, path, mode);
649 nlookup_done(&nd);
650 linux_free_path(&path);
651 linux_free_path(&link);
652 return(error);
656 linux_readlink(struct linux_readlink_args *args)
658 struct nlookupdata nd;
659 char *path;
660 int error;
662 error = linux_copyin_path(args->name, &path, LINUX_PATH_EXISTS);
663 if (error)
664 return (error);
665 #ifdef DEBUG
666 if (ldebug(readlink))
667 printf(ARGS(readlink, "%s, %p, %d"), path, (void *)args->buf,
668 args->count);
669 #endif
670 error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
671 if (error == 0) {
672 error = kern_readlink(&nd, args->buf, args->count,
673 &args->sysmsg_result);
675 nlookup_done(&nd);
676 linux_free_path(&path);
677 return(error);
681 linux_truncate(struct linux_truncate_args *args)
683 struct nlookupdata nd;
684 char *path;
685 int error;
687 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
688 if (error)
689 return (error);
690 #ifdef DEBUG
691 if (ldebug(truncate))
692 printf(ARGS(truncate, "%s, %ld"), path,
693 (long)args->length);
694 #endif
695 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
696 if (error == 0)
697 error = kern_truncate(&nd, args->length);
698 nlookup_done(&nd);
699 linux_free_path(&path);
700 return(error);
704 linux_truncate64(struct linux_truncate64_args *args)
706 struct nlookupdata nd;
707 char *path;
708 int error;
710 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
711 if (error)
712 return (error);
713 #ifdef DEBUG
714 if (ldebug(truncate64))
715 printf(ARGS(truncate64, "%s, %lld"), path,
716 (off_t)args->length);
717 #endif
718 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
719 if (error == 0)
720 error = kern_truncate(&nd, args->length);
721 nlookup_done(&nd);
722 linux_free_path(&path);
723 return error;
727 linux_ftruncate(struct linux_ftruncate_args *args)
729 int error;
731 #ifdef DEBUG
732 if (ldebug(ftruncate))
733 printf(ARGS(ftruncate, "%d, %ld"), args->fd,
734 (long)args->length);
735 #endif
736 error = kern_ftruncate(args->fd, args->length);
738 return error;
742 linux_ftruncate64(struct linux_ftruncate64_args *args)
744 int error;
746 #ifdef DEBUG
747 if (ldebug(ftruncate))
748 printf(ARGS(ftruncate64, "%d, %lld"), args->fd,
749 (off_t)args->length);
750 #endif
751 error = kern_ftruncate(args->fd, args->length);
753 return error;
757 linux_link(struct linux_link_args *args)
759 struct nlookupdata nd, linknd;
760 char *path, *link;
761 int error;
763 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
764 if (error)
765 return (error);
766 error = linux_copyin_path(args->to, &link, LINUX_PATH_CREATE);
767 if (error) {
768 linux_free_path(&path);
769 return (error);
771 #ifdef DEBUG
772 if (ldebug(link))
773 printf(ARGS(link, "%s, %s"), path, link);
774 #endif
775 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
776 if (error == 0) {
777 error = nlookup_init(&linknd, link, UIO_SYSSPACE, 0);
778 if (error == 0)
779 error = kern_link(&nd, &linknd);
780 nlookup_done(&linknd);
782 nlookup_done(&nd);
783 linux_free_path(&path);
784 linux_free_path(&link);
785 return(error);
789 linux_fdatasync(struct linux_fdatasync_args *uap)
791 struct fsync_args bsd;
792 int error;
794 bsd.fd = uap->fd;
795 bsd.sysmsg_result = 0;
797 error = fsync(&bsd);
798 uap->sysmsg_result = bsd.sysmsg_result;
799 return(error);
803 linux_pread(struct linux_pread_args *uap)
805 struct thread *td = curthread;
806 struct uio auio;
807 struct iovec aiov;
808 int error;
810 aiov.iov_base = uap->buf;
811 aiov.iov_len = uap->nbyte;
812 auio.uio_iov = &aiov;
813 auio.uio_iovcnt = 1;
814 auio.uio_offset = uap->offset;
815 auio.uio_resid = uap->nbyte;
816 auio.uio_rw = UIO_READ;
817 auio.uio_segflg = UIO_USERSPACE;
818 auio.uio_td = td;
820 error = kern_readv(uap->fd, &auio, FOF_OFFSET, &uap->sysmsg_result);
822 return(error);
826 linux_pwrite(struct linux_pwrite_args *uap)
828 struct thread *td = curthread;
829 struct uio auio;
830 struct iovec aiov;
831 int error;
833 aiov.iov_base = uap->buf;
834 aiov.iov_len = uap->nbyte;
835 auio.uio_iov = &aiov;
836 auio.uio_iovcnt = 1;
837 auio.uio_offset = uap->offset;
838 auio.uio_resid = uap->nbyte;
839 auio.uio_rw = UIO_WRITE;
840 auio.uio_segflg = UIO_USERSPACE;
841 auio.uio_td = td;
843 error = kern_writev(uap->fd, &auio, FOF_OFFSET, &uap->sysmsg_result);
845 return(error);
849 linux_oldumount(struct linux_oldumount_args *args)
851 struct linux_umount_args args2;
852 int error;
854 args2.path = args->path;
855 args2.flags = 0;
856 args2.sysmsg_result = 0;
857 error = linux_umount(&args2);
858 args->sysmsg_result = args2.sysmsg_result;
859 return(error);
863 linux_umount(struct linux_umount_args *args)
865 struct unmount_args bsd;
866 int error;
868 bsd.path = args->path;
869 bsd.flags = args->flags; /* XXX correct? */
870 bsd.sysmsg_result = 0;
872 error = unmount(&bsd);
873 args->sysmsg_result = bsd.sysmsg_result;
874 return(error);
878 * fcntl family of syscalls
881 struct l_flock {
882 l_short l_type;
883 l_short l_whence;
884 l_off_t l_start;
885 l_off_t l_len;
886 l_pid_t l_pid;
889 static void
890 linux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock)
892 switch (linux_flock->l_type) {
893 case LINUX_F_RDLCK:
894 bsd_flock->l_type = F_RDLCK;
895 break;
896 case LINUX_F_WRLCK:
897 bsd_flock->l_type = F_WRLCK;
898 break;
899 case LINUX_F_UNLCK:
900 bsd_flock->l_type = F_UNLCK;
901 break;
902 default:
903 bsd_flock->l_type = -1;
904 break;
906 bsd_flock->l_whence = linux_flock->l_whence;
907 bsd_flock->l_start = (off_t)linux_flock->l_start;
908 bsd_flock->l_len = (off_t)linux_flock->l_len;
909 bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
912 static void
913 bsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock)
915 switch (bsd_flock->l_type) {
916 case F_RDLCK:
917 linux_flock->l_type = LINUX_F_RDLCK;
918 break;
919 case F_WRLCK:
920 linux_flock->l_type = LINUX_F_WRLCK;
921 break;
922 case F_UNLCK:
923 linux_flock->l_type = LINUX_F_UNLCK;
924 break;
926 linux_flock->l_whence = bsd_flock->l_whence;
927 linux_flock->l_start = (l_off_t)bsd_flock->l_start;
928 linux_flock->l_len = (l_off_t)bsd_flock->l_len;
929 linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
932 #if defined(__i386__)
933 struct l_flock64 {
934 l_short l_type;
935 l_short l_whence;
936 l_loff_t l_start;
937 l_loff_t l_len;
938 l_pid_t l_pid;
941 static void
942 linux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock)
944 switch (linux_flock->l_type) {
945 case LINUX_F_RDLCK:
946 bsd_flock->l_type = F_RDLCK;
947 break;
948 case LINUX_F_WRLCK:
949 bsd_flock->l_type = F_WRLCK;
950 break;
951 case LINUX_F_UNLCK:
952 bsd_flock->l_type = F_UNLCK;
953 break;
954 default:
955 bsd_flock->l_type = -1;
956 break;
958 bsd_flock->l_whence = linux_flock->l_whence;
959 bsd_flock->l_start = (off_t)linux_flock->l_start;
960 bsd_flock->l_len = (off_t)linux_flock->l_len;
961 bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
964 static void
965 bsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock)
967 switch (bsd_flock->l_type) {
968 case F_RDLCK:
969 linux_flock->l_type = LINUX_F_RDLCK;
970 break;
971 case F_WRLCK:
972 linux_flock->l_type = LINUX_F_WRLCK;
973 break;
974 case F_UNLCK:
975 linux_flock->l_type = LINUX_F_UNLCK;
976 break;
978 linux_flock->l_whence = bsd_flock->l_whence;
979 linux_flock->l_start = (l_loff_t)bsd_flock->l_start;
980 linux_flock->l_len = (l_loff_t)bsd_flock->l_len;
981 linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
983 #endif /* __i386__ */
985 static int
986 linux_fcntl_common(struct linux_fcntl64_args *args)
988 struct proc *p = curproc;
989 struct l_flock linux_flock;
990 struct filedesc *fdp;
991 struct file *fp;
992 union fcntl_dat dat;
993 int error, cmd;
995 switch (args->cmd) {
996 case LINUX_F_DUPFD:
997 cmd = F_DUPFD;
998 dat.fc_fd = args->arg;
999 break;
1000 case LINUX_F_GETFD:
1001 cmd = F_GETFD;
1002 break;
1003 case LINUX_F_SETFD:
1004 cmd = F_SETFD;
1005 dat.fc_cloexec = args->arg;
1006 break;
1007 case LINUX_F_GETFL:
1008 cmd = F_GETFL;
1009 break;
1010 case LINUX_F_SETFL:
1011 cmd = F_SETFL;
1012 dat.fc_flags = 0;
1013 if (args->arg & LINUX_O_NDELAY)
1014 dat.fc_flags |= O_NONBLOCK;
1015 if (args->arg & LINUX_O_APPEND)
1016 dat.fc_flags |= O_APPEND;
1017 if (args->arg & LINUX_O_SYNC)
1018 dat.fc_flags |= O_FSYNC;
1019 if (args->arg & LINUX_FASYNC)
1020 dat.fc_flags |= O_ASYNC;
1021 break;
1022 case LINUX_F_GETLK:
1023 case LINUX_F_SETLK:
1024 case LINUX_F_SETLKW:
1025 cmd = F_GETLK;
1026 error = copyin((caddr_t)args->arg, &linux_flock,
1027 sizeof(linux_flock));
1028 if (error)
1029 return (error);
1030 linux_to_bsd_flock(&linux_flock, &dat.fc_flock);
1031 break;
1032 case LINUX_F_GETOWN:
1033 cmd = F_GETOWN;
1034 break;
1035 case LINUX_F_SETOWN:
1037 * XXX some Linux applications depend on F_SETOWN having no
1038 * significant effect for pipes (SIGIO is not delivered for
1039 * pipes under Linux-2.2.35 at least).
1041 fdp = p->p_fd;
1042 if ((u_int)args->fd >= fdp->fd_nfiles ||
1043 (fp = fdp->fd_files[args->fd].fp) == NULL)
1044 return (EBADF);
1045 if (fp->f_type == DTYPE_PIPE)
1046 return (EINVAL);
1047 cmd = F_SETOWN;
1048 dat.fc_owner = args->arg;
1049 break;
1050 default:
1051 return (EINVAL);
1054 error = kern_fcntl(args->fd, cmd, &dat);
1056 if (error == 0) {
1057 switch (args->cmd) {
1058 case LINUX_F_DUPFD:
1059 args->sysmsg_result = dat.fc_fd;
1060 break;
1061 case LINUX_F_GETFD:
1062 args->sysmsg_result = dat.fc_cloexec;
1063 break;
1064 case LINUX_F_SETFD:
1065 break;
1066 case LINUX_F_GETFL:
1067 args->sysmsg_result = 0;
1068 if (dat.fc_flags & O_RDONLY)
1069 args->sysmsg_result |= LINUX_O_RDONLY;
1070 if (dat.fc_flags & O_WRONLY)
1071 args->sysmsg_result |= LINUX_O_WRONLY;
1072 if (dat.fc_flags & O_RDWR)
1073 args->sysmsg_result |= LINUX_O_RDWR;
1074 if (dat.fc_flags & O_NDELAY)
1075 args->sysmsg_result |= LINUX_O_NONBLOCK;
1076 if (dat.fc_flags & O_APPEND)
1077 args->sysmsg_result |= LINUX_O_APPEND;
1078 if (dat.fc_flags & O_FSYNC)
1079 args->sysmsg_result |= LINUX_O_SYNC;
1080 if (dat.fc_flags & O_ASYNC)
1081 args->sysmsg_result |= LINUX_FASYNC;
1082 break;
1083 case LINUX_F_GETLK:
1084 bsd_to_linux_flock(&dat.fc_flock, &linux_flock);
1085 error = copyout(&linux_flock, (caddr_t)args->arg,
1086 sizeof(linux_flock));
1087 break;
1088 case LINUX_F_SETLK:
1089 case LINUX_F_SETLKW:
1090 break;
1091 case LINUX_F_GETOWN:
1092 args->sysmsg_result = dat.fc_owner;
1093 break;
1094 case LINUX_F_SETOWN:
1095 break;
1099 return(error);
1103 linux_fcntl(struct linux_fcntl_args *args)
1105 struct linux_fcntl64_args args64;
1106 int error;
1108 #ifdef DEBUG
1109 if (ldebug(fcntl))
1110 printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd);
1111 #endif
1113 args64.fd = args->fd;
1114 args64.cmd = args->cmd;
1115 args64.arg = args->arg;
1116 args64.sysmsg_result = 0;
1117 error = linux_fcntl_common(&args64);
1118 args->sysmsg_result = args64.sysmsg_result;
1119 return(error);
1122 #if defined(__i386__)
1124 linux_fcntl64(struct linux_fcntl64_args *args)
1126 struct l_flock64 linux_flock;
1127 union fcntl_dat dat;
1128 int error, cmd = 0;
1130 #ifdef DEBUG
1131 if (ldebug(fcntl64))
1132 printf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd);
1133 #endif
1134 if (args->cmd == LINUX_F_GETLK64 || args->cmd == LINUX_F_SETLK64 ||
1135 args->cmd == LINUX_F_SETLKW64) {
1136 switch (args->cmd) {
1137 case LINUX_F_GETLK64:
1138 cmd = F_GETLK;
1139 break;
1140 case LINUX_F_SETLK64:
1141 cmd = F_SETLK;
1142 break;
1143 case LINUX_F_SETLKW64:
1144 cmd = F_SETLKW;
1145 break;
1148 error = copyin((caddr_t)args->arg, &linux_flock,
1149 sizeof(linux_flock));
1150 if (error)
1151 return (error);
1152 linux_to_bsd_flock64(&linux_flock, &dat.fc_flock);
1154 error = kern_fcntl(args->fd, cmd, &dat);
1156 if (error == 0 && args->cmd == LINUX_F_GETLK64) {
1157 bsd_to_linux_flock64(&dat.fc_flock, &linux_flock);
1158 error = copyout(&linux_flock, (caddr_t)args->arg,
1159 sizeof(linux_flock));
1161 } else {
1162 error = linux_fcntl_common(args);
1165 return (error);
1167 #endif /* __i386__ */
1170 linux_chown(struct linux_chown_args *args)
1172 struct nlookupdata nd;
1173 char *path;
1174 int error;
1176 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
1177 if (error)
1178 return (error);
1179 #ifdef DEBUG
1180 if (ldebug(chown))
1181 printf(ARGS(chown, "%s, %d, %d"), path, args->uid, args->gid);
1182 #endif
1183 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
1184 if (error == 0)
1185 error = kern_chown(&nd, args->uid, args->gid);
1186 nlookup_done(&nd);
1187 linux_free_path(&path);
1188 return(error);
1192 linux_lchown(struct linux_lchown_args *args)
1194 struct nlookupdata nd;
1195 char *path;
1196 int error;
1198 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
1199 if (error)
1200 return (error);
1201 #ifdef DEBUG
1202 if (ldebug(lchown))
1203 printf(ARGS(lchown, "%s, %d, %d"), path, args->uid, args->gid);
1204 #endif
1205 error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
1206 if (error == 0)
1207 error = kern_chown(&nd, args->uid, args->gid);
1208 nlookup_done(&nd);
1209 linux_free_path(&path);
1210 return(error);