Linux emulation adjustments.
[dragonfly.git] / sys / emulation / linux / linux_file.c
blob341aa7723158fefb1c8706e8f1662d9067782dbf
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_result);
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_result);
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_result, -1);
146 if (fp) {
147 if (fp->f_type == DTYPE_VNODE)
148 fo_ioctl(fp, TIOCSCTTY, NULL, p->p_ucred);
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_result = 0;
206 error = sys_linux_getdents(&lda);
207 args->sysmsg_result = lda.sysmsg_result;
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 len, reclen; /* BSD-format */
249 caddr_t outp; /* Linux-format */
250 int resid, linuxreclen=0; /* Linux-format */
251 struct file *fp;
252 struct uio auio;
253 struct iovec aiov;
254 struct vattr va;
255 off_t off;
256 struct l_dirent linux_dirent;
257 struct l_dirent64 linux_dirent64;
258 int buflen, error, eofflag, nbytes, justone;
259 off_t *cookies = NULL, *cookiep;
260 int ncookies;
262 KKASSERT(p);
264 if ((error = holdvnode(p->p_fd, args->fd, &fp)) != 0)
265 return (error);
267 if ((fp->f_flag & FREAD) == 0) {
268 error = EBADF;
269 goto done;
272 vp = (struct vnode *) fp->f_data;
273 if (vp->v_type != VDIR) {
274 error = EINVAL;
275 goto done;
278 if ((error = VOP_GETATTR(vp, &va)) != 0)
279 goto done;
281 nbytes = args->count;
282 if (nbytes == -1) {
283 /* readdir(2) case. Always struct dirent. */
284 if (is64bit) {
285 error = EINVAL;
286 goto done;
288 nbytes = sizeof(linux_dirent);
289 justone = 1;
290 } else {
291 justone = 0;
293 if (nbytes < 0)
294 nbytes = 0;
296 off = fp->f_offset;
298 buflen = max(LINUX_DIRBLKSIZ, nbytes);
299 buflen = min(buflen, MAXBSIZE);
300 buf = kmalloc(buflen, M_TEMP, M_WAITOK);
302 again:
303 aiov.iov_base = buf;
304 aiov.iov_len = buflen;
305 auio.uio_iov = &aiov;
306 auio.uio_iovcnt = 1;
307 auio.uio_rw = UIO_READ;
308 auio.uio_segflg = UIO_SYSSPACE;
309 auio.uio_td = td;
310 auio.uio_resid = buflen;
311 auio.uio_offset = off;
313 if (cookies) {
314 kfree(cookies, M_TEMP);
315 cookies = NULL;
318 eofflag = 0;
319 ncookies = 0;
320 if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies,
321 &cookies)))
322 goto out;
324 inp = buf;
325 outp = (caddr_t)args->dirent;
326 resid = nbytes;
327 if ((len = buflen - auio.uio_resid) <= 0)
328 goto eof;
330 cookiep = cookies;
332 if (cookies) {
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).
340 while (len > 0 && ncookies > 0 && *cookiep < off) {
341 bdp = (struct dirent *) inp;
342 len -= _DIRENT_DIRSIZ(bdp);
343 inp += _DIRENT_DIRSIZ(bdp);
344 cookiep++;
345 ncookies--;
349 while (len > 0) {
350 if (cookiep && ncookies == 0)
351 break;
352 bdp = (struct dirent *) inp;
353 reclen = _DIRENT_DIRSIZ(bdp);
354 if (reclen & 3) {
355 error = EFAULT;
356 goto out;
359 if (bdp->d_ino == 0) {
360 inp += reclen;
361 if (cookiep) {
362 off = *cookiep++;
363 ++off;
364 ncookies--;
365 } else {
366 off += reclen;
368 len -= reclen;
369 continue;
372 linuxreclen = (is64bit)
373 ? LINUX_RECLEN(&linux_dirent64, bdp->d_namlen)
374 : LINUX_RECLEN(&linux_dirent, bdp->d_namlen);
376 if (reclen > len || resid < linuxreclen) {
377 outp++;
378 break;
381 bzero(&linux_dirent, sizeof(linux_dirent));
382 bzero(&linux_dirent64, sizeof(linux_dirent64));
383 if (justone) {
384 /* readdir(2) case. */
385 linux_dirent.d_ino = (l_long)INO64TO32(bdp->d_ino);
386 linux_dirent.d_off = (l_off_t)linuxreclen;
387 linux_dirent.d_reclen = (l_ushort)bdp->d_namlen;
388 strcpy(linux_dirent.d_name, bdp->d_name);
389 error = copyout(&linux_dirent, outp, linuxreclen);
390 } else {
391 if (is64bit) {
392 linux_dirent64.d_ino = bdp->d_ino;
393 linux_dirent64.d_off = (cookiep)
394 ? (l_off_t)*cookiep
395 : (l_off_t)(off + reclen);
396 linux_dirent64.d_reclen =
397 (l_ushort)linuxreclen;
398 linux_dirent64.d_type = bdp->d_type;
399 strcpy(linux_dirent64.d_name, bdp->d_name);
400 error = copyout(&linux_dirent64, outp,
401 linuxreclen);
402 } else {
403 linux_dirent.d_ino = INO64TO32(bdp->d_ino);
404 linux_dirent.d_off = (cookiep)
405 ? (l_off_t)*cookiep
406 : (l_off_t)(off + reclen);
407 linux_dirent.d_reclen = (l_ushort)linuxreclen;
408 strcpy(linux_dirent.d_name, bdp->d_name);
409 error = copyout(&linux_dirent, outp,
410 linuxreclen);
413 if (error)
414 goto out;
416 inp += reclen;
417 if (cookiep) {
418 off = *cookiep++;
419 ++off;
420 ncookies--;
421 } else {
422 off += reclen;
425 outp += linuxreclen;
426 resid -= linuxreclen;
427 len -= reclen;
428 if (justone)
429 break;
432 if (outp == (caddr_t)args->dirent && eofflag == 0)
433 goto again;
435 fp->f_offset = off;
436 if (justone)
437 nbytes = resid + linuxreclen;
439 eof:
440 args->sysmsg_result = nbytes - resid;
442 out:
443 if (cookies)
444 kfree(cookies, M_TEMP);
446 kfree(buf, M_TEMP);
447 done:
448 fdrop(fp);
449 return (error);
453 sys_linux_getdents(struct linux_getdents_args *args)
455 #ifdef DEBUG
456 if (ldebug(getdents))
457 kprintf(ARGS(getdents, "%d, *, %d"), args->fd, args->count);
458 #endif
459 return (getdents_common((struct linux_getdents64_args*)args, 0));
463 sys_linux_getdents64(struct linux_getdents64_args *args)
465 #ifdef DEBUG
466 if (ldebug(getdents64))
467 kprintf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count);
468 #endif
469 return (getdents_common(args, 1));
473 * These exist mainly for hooks for doing /compat/linux translation.
477 sys_linux_access(struct linux_access_args *args)
479 struct nlookupdata nd;
480 char *path;
481 int error;
483 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
484 if (error)
485 return (error);
486 #ifdef DEBUG
487 if (ldebug(access))
488 kprintf(ARGS(access, "%s, %d"), path, args->flags);
489 #endif
490 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
491 if (error == 0)
492 error = kern_access(&nd, args->flags);
493 nlookup_done(&nd);
494 linux_free_path(&path);
495 return(error);
499 sys_linux_unlink(struct linux_unlink_args *args)
501 struct nlookupdata nd;
502 char *path;
503 int error;
505 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
506 if (error)
507 return (error);
508 #ifdef DEBUG
509 if (ldebug(unlink))
510 kprintf(ARGS(unlink, "%s"), path);
511 #endif
512 error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
513 if (error == 0)
514 error = kern_unlink(&nd);
515 nlookup_done(&nd);
516 linux_free_path(&path);
517 return(error);
521 sys_linux_chdir(struct linux_chdir_args *args)
523 struct nlookupdata nd;
524 char *path;
525 int error;
527 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
528 if (error)
529 return (error);
530 #ifdef DEBUG
531 if (ldebug(chdir))
532 kprintf(ARGS(chdir, "%s"), path);
533 #endif
534 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
535 if (error == 0) {
536 error = kern_chdir(&nd);
537 nlookup_done(&nd);
539 linux_free_path(&path);
540 return(error);
544 sys_linux_chmod(struct linux_chmod_args *args)
546 struct nlookupdata nd;
547 char *path;
548 int error;
550 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
551 if (error)
552 return (error);
553 #ifdef DEBUG
554 if (ldebug(chmod))
555 kprintf(ARGS(chmod, "%s, %d"), path, args->mode);
556 #endif
557 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
558 if (error == 0)
559 error = kern_chmod(&nd, args->mode);
560 nlookup_done(&nd);
561 linux_free_path(&path);
562 return(error);
566 sys_linux_mkdir(struct linux_mkdir_args *args)
568 struct nlookupdata nd;
569 char *path;
570 int error;
572 error = linux_copyin_path(args->path, &path, LINUX_PATH_CREATE);
573 if (error)
574 return (error);
575 #ifdef DEBUG
576 if (ldebug(mkdir))
577 kprintf(ARGS(mkdir, "%s, %d"), path, args->mode);
578 #endif
579 error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
580 if (error == 0)
581 error = kern_mkdir(&nd, args->mode);
582 nlookup_done(&nd);
584 linux_free_path(&path);
585 return(error);
589 sys_linux_rmdir(struct linux_rmdir_args *args)
591 struct nlookupdata nd;
592 char *path;
593 int error;
595 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
596 if (error)
597 return (error);
598 #ifdef DEBUG
599 if (ldebug(rmdir))
600 kprintf(ARGS(rmdir, "%s"), path);
601 #endif
602 error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
603 if (error == 0)
604 error = kern_rmdir(&nd);
605 nlookup_done(&nd);
606 linux_free_path(&path);
607 return(error);
611 sys_linux_rename(struct linux_rename_args *args)
613 struct nlookupdata fromnd, tond;
614 char *from, *to;
615 int error;
617 error = linux_copyin_path(args->from, &from, LINUX_PATH_EXISTS);
618 if (error)
619 return (error);
620 error = linux_copyin_path(args->to, &to, LINUX_PATH_CREATE);
621 if (error) {
622 linux_free_path(&from);
623 return (error);
625 #ifdef DEBUG
626 if (ldebug(rename))
627 kprintf(ARGS(rename, "%s, %s"), from, to);
628 #endif
629 error = nlookup_init(&fromnd, from, UIO_SYSSPACE, 0);
630 if (error == 0) {
631 error = nlookup_init(&tond, to, UIO_SYSSPACE, 0);
632 if (error == 0)
633 error = kern_rename(&fromnd, &tond);
634 nlookup_done(&tond);
636 nlookup_done(&fromnd);
637 linux_free_path(&from);
638 linux_free_path(&to);
639 return(error);
643 sys_linux_symlink(struct linux_symlink_args *args)
645 struct thread *td = curthread;
646 struct nlookupdata nd;
647 char *path, *link;
648 int error;
649 int mode;
651 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
652 if (error)
653 return (error);
654 error = linux_copyin_path(args->to, &link, LINUX_PATH_CREATE);
655 if (error) {
656 linux_free_path(&path);
657 return (error);
659 #ifdef DEBUG
660 if (ldebug(symlink))
661 kprintf(ARGS(symlink, "%s, %s"), path, link);
662 #endif
663 error = nlookup_init(&nd, link, UIO_SYSSPACE, 0);
664 if (error == 0) {
665 mode = ACCESSPERMS & ~td->td_proc->p_fd->fd_cmask;
666 error = kern_symlink(&nd, path, mode);
668 nlookup_done(&nd);
669 linux_free_path(&path);
670 linux_free_path(&link);
671 return(error);
675 sys_linux_readlink(struct linux_readlink_args *args)
677 struct nlookupdata nd;
678 char *path;
679 int error;
681 error = linux_copyin_path(args->name, &path, LINUX_PATH_EXISTS);
682 if (error)
683 return (error);
684 #ifdef DEBUG
685 if (ldebug(readlink))
686 kprintf(ARGS(readlink, "%s, %p, %d"), path, (void *)args->buf,
687 args->count);
688 #endif
689 error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
690 if (error == 0) {
691 error = kern_readlink(&nd, args->buf, args->count,
692 &args->sysmsg_result);
694 nlookup_done(&nd);
695 linux_free_path(&path);
696 return(error);
700 sys_linux_truncate(struct linux_truncate_args *args)
702 struct nlookupdata nd;
703 char *path;
704 int error;
706 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
707 if (error)
708 return (error);
709 #ifdef DEBUG
710 if (ldebug(truncate))
711 kprintf(ARGS(truncate, "%s, %ld"), path,
712 (long)args->length);
713 #endif
714 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
715 if (error == 0)
716 error = kern_truncate(&nd, args->length);
717 nlookup_done(&nd);
718 linux_free_path(&path);
719 return(error);
723 sys_linux_truncate64(struct linux_truncate64_args *args)
725 struct nlookupdata nd;
726 char *path;
727 int error;
729 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
730 if (error)
731 return (error);
732 #ifdef DEBUG
733 if (ldebug(truncate64))
734 kprintf(ARGS(truncate64, "%s, %lld"), path,
735 (off_t)args->length);
736 #endif
737 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
738 if (error == 0)
739 error = kern_truncate(&nd, args->length);
740 nlookup_done(&nd);
741 linux_free_path(&path);
742 return error;
746 sys_linux_ftruncate(struct linux_ftruncate_args *args)
748 int error;
750 #ifdef DEBUG
751 if (ldebug(ftruncate))
752 kprintf(ARGS(ftruncate, "%d, %ld"), args->fd,
753 (long)args->length);
754 #endif
755 error = kern_ftruncate(args->fd, args->length);
757 return error;
761 sys_linux_ftruncate64(struct linux_ftruncate64_args *args)
763 int error;
765 #ifdef DEBUG
766 if (ldebug(ftruncate))
767 kprintf(ARGS(ftruncate64, "%d, %lld"), args->fd,
768 (off_t)args->length);
769 #endif
770 error = kern_ftruncate(args->fd, args->length);
772 return error;
776 sys_linux_link(struct linux_link_args *args)
778 struct nlookupdata nd, linknd;
779 char *path, *link;
780 int error;
782 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
783 if (error)
784 return (error);
785 error = linux_copyin_path(args->to, &link, LINUX_PATH_CREATE);
786 if (error) {
787 linux_free_path(&path);
788 return (error);
790 #ifdef DEBUG
791 if (ldebug(link))
792 kprintf(ARGS(link, "%s, %s"), path, link);
793 #endif
794 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
795 if (error == 0) {
796 error = nlookup_init(&linknd, link, UIO_SYSSPACE, 0);
797 if (error == 0)
798 error = kern_link(&nd, &linknd);
799 nlookup_done(&linknd);
801 nlookup_done(&nd);
802 linux_free_path(&path);
803 linux_free_path(&link);
804 return(error);
808 sys_linux_fdatasync(struct linux_fdatasync_args *uap)
810 struct fsync_args bsd;
811 int error;
813 bsd.fd = uap->fd;
814 bsd.sysmsg_result = 0;
816 error = sys_fsync(&bsd);
817 uap->sysmsg_result = bsd.sysmsg_result;
818 return(error);
822 sys_linux_pread(struct linux_pread_args *uap)
824 struct thread *td = curthread;
825 struct uio auio;
826 struct iovec aiov;
827 int error;
829 aiov.iov_base = uap->buf;
830 aiov.iov_len = uap->nbyte;
831 auio.uio_iov = &aiov;
832 auio.uio_iovcnt = 1;
833 auio.uio_offset = uap->offset;
834 auio.uio_resid = uap->nbyte;
835 auio.uio_rw = UIO_READ;
836 auio.uio_segflg = UIO_USERSPACE;
837 auio.uio_td = td;
839 if (auio.uio_resid < 0)
840 error = EINVAL;
841 else
842 error = kern_preadv(uap->fd, &auio, O_FOFFSET, &uap->sysmsg_result);
843 return(error);
847 sys_linux_pwrite(struct linux_pwrite_args *uap)
849 struct thread *td = curthread;
850 struct uio auio;
851 struct iovec aiov;
852 int error;
854 aiov.iov_base = uap->buf;
855 aiov.iov_len = uap->nbyte;
856 auio.uio_iov = &aiov;
857 auio.uio_iovcnt = 1;
858 auio.uio_offset = uap->offset;
859 auio.uio_resid = uap->nbyte;
860 auio.uio_rw = UIO_WRITE;
861 auio.uio_segflg = UIO_USERSPACE;
862 auio.uio_td = td;
864 if (auio.uio_resid < 0)
865 error = EINVAL;
866 else
867 error = kern_pwritev(uap->fd, &auio, O_FOFFSET, &uap->sysmsg_result);
869 return(error);
873 sys_linux_oldumount(struct linux_oldumount_args *args)
875 struct linux_umount_args args2;
876 int error;
878 args2.path = args->path;
879 args2.flags = 0;
880 args2.sysmsg_result = 0;
881 error = sys_linux_umount(&args2);
882 args->sysmsg_result = args2.sysmsg_result;
883 return(error);
887 sys_linux_umount(struct linux_umount_args *args)
889 struct unmount_args bsd;
890 int error;
892 bsd.path = args->path;
893 bsd.flags = args->flags; /* XXX correct? */
894 bsd.sysmsg_result = 0;
896 error = sys_unmount(&bsd);
897 args->sysmsg_result = bsd.sysmsg_result;
898 return(error);
902 * fcntl family of syscalls
905 struct l_flock {
906 l_short l_type;
907 l_short l_whence;
908 l_off_t l_start;
909 l_off_t l_len;
910 l_pid_t l_pid;
913 static void
914 linux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock)
916 switch (linux_flock->l_type) {
917 case LINUX_F_RDLCK:
918 bsd_flock->l_type = F_RDLCK;
919 break;
920 case LINUX_F_WRLCK:
921 bsd_flock->l_type = F_WRLCK;
922 break;
923 case LINUX_F_UNLCK:
924 bsd_flock->l_type = F_UNLCK;
925 break;
926 default:
927 bsd_flock->l_type = -1;
928 break;
930 bsd_flock->l_whence = linux_flock->l_whence;
931 bsd_flock->l_start = (off_t)linux_flock->l_start;
932 bsd_flock->l_len = (off_t)linux_flock->l_len;
933 bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
936 static void
937 bsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock)
939 switch (bsd_flock->l_type) {
940 case F_RDLCK:
941 linux_flock->l_type = LINUX_F_RDLCK;
942 break;
943 case F_WRLCK:
944 linux_flock->l_type = LINUX_F_WRLCK;
945 break;
946 case F_UNLCK:
947 linux_flock->l_type = LINUX_F_UNLCK;
948 break;
950 linux_flock->l_whence = bsd_flock->l_whence;
951 linux_flock->l_start = (l_off_t)bsd_flock->l_start;
952 linux_flock->l_len = (l_off_t)bsd_flock->l_len;
953 linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
956 #if defined(__i386__)
957 struct l_flock64 {
958 l_short l_type;
959 l_short l_whence;
960 l_loff_t l_start;
961 l_loff_t l_len;
962 l_pid_t l_pid;
965 static void
966 linux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock)
968 switch (linux_flock->l_type) {
969 case LINUX_F_RDLCK:
970 bsd_flock->l_type = F_RDLCK;
971 break;
972 case LINUX_F_WRLCK:
973 bsd_flock->l_type = F_WRLCK;
974 break;
975 case LINUX_F_UNLCK:
976 bsd_flock->l_type = F_UNLCK;
977 break;
978 default:
979 bsd_flock->l_type = -1;
980 break;
982 bsd_flock->l_whence = linux_flock->l_whence;
983 bsd_flock->l_start = (off_t)linux_flock->l_start;
984 bsd_flock->l_len = (off_t)linux_flock->l_len;
985 bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
988 static void
989 bsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock)
991 switch (bsd_flock->l_type) {
992 case F_RDLCK:
993 linux_flock->l_type = LINUX_F_RDLCK;
994 break;
995 case F_WRLCK:
996 linux_flock->l_type = LINUX_F_WRLCK;
997 break;
998 case F_UNLCK:
999 linux_flock->l_type = LINUX_F_UNLCK;
1000 break;
1002 linux_flock->l_whence = bsd_flock->l_whence;
1003 linux_flock->l_start = (l_loff_t)bsd_flock->l_start;
1004 linux_flock->l_len = (l_loff_t)bsd_flock->l_len;
1005 linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
1007 #endif /* __i386__ */
1009 static int
1010 linux_fcntl_common(struct linux_fcntl64_args *args)
1012 struct proc *p = curproc;
1013 struct l_flock linux_flock;
1014 struct file *fp;
1015 union fcntl_dat dat;
1016 int error, cmd;
1018 switch (args->cmd) {
1019 case LINUX_F_DUPFD:
1020 cmd = F_DUPFD;
1021 dat.fc_fd = args->arg;
1022 break;
1023 case LINUX_F_GETFD:
1024 cmd = F_GETFD;
1025 break;
1026 case LINUX_F_SETFD:
1027 cmd = F_SETFD;
1028 dat.fc_cloexec = args->arg;
1029 break;
1030 case LINUX_F_GETFL:
1031 cmd = F_GETFL;
1032 break;
1033 case LINUX_F_SETFL:
1034 cmd = F_SETFL;
1035 dat.fc_flags = 0;
1036 if (args->arg & LINUX_O_NDELAY)
1037 dat.fc_flags |= O_NONBLOCK;
1038 if (args->arg & LINUX_O_APPEND)
1039 dat.fc_flags |= O_APPEND;
1040 if (args->arg & LINUX_O_SYNC)
1041 dat.fc_flags |= O_FSYNC;
1042 if (args->arg & LINUX_FASYNC)
1043 dat.fc_flags |= O_ASYNC;
1044 break;
1045 case LINUX_F_GETLK:
1046 case LINUX_F_SETLK:
1047 case LINUX_F_SETLKW:
1048 cmd = F_GETLK;
1049 error = copyin((caddr_t)args->arg, &linux_flock,
1050 sizeof(linux_flock));
1051 if (error)
1052 return (error);
1053 linux_to_bsd_flock(&linux_flock, &dat.fc_flock);
1054 break;
1055 case LINUX_F_GETOWN:
1056 cmd = F_GETOWN;
1057 break;
1058 case LINUX_F_SETOWN:
1060 * XXX some Linux applications depend on F_SETOWN having no
1061 * significant effect for pipes (SIGIO is not delivered for
1062 * pipes under Linux-2.2.35 at least).
1064 fp = holdfp(p->p_fd, args->fd, -1);
1065 if (fp == NULL)
1066 return (EBADF);
1067 if (fp->f_type == DTYPE_PIPE) {
1068 fdrop(fp);
1069 return (EINVAL);
1071 fdrop(fp);
1072 cmd = F_SETOWN;
1073 dat.fc_owner = args->arg;
1074 break;
1075 default:
1076 return (EINVAL);
1079 error = kern_fcntl(args->fd, cmd, &dat, p->p_ucred);
1081 if (error == 0) {
1082 switch (args->cmd) {
1083 case LINUX_F_DUPFD:
1084 args->sysmsg_result = dat.fc_fd;
1085 break;
1086 case LINUX_F_GETFD:
1087 args->sysmsg_result = dat.fc_cloexec;
1088 break;
1089 case LINUX_F_SETFD:
1090 break;
1091 case LINUX_F_GETFL:
1092 args->sysmsg_result = 0;
1093 if (dat.fc_flags & O_RDONLY)
1094 args->sysmsg_result |= LINUX_O_RDONLY;
1095 if (dat.fc_flags & O_WRONLY)
1096 args->sysmsg_result |= LINUX_O_WRONLY;
1097 if (dat.fc_flags & O_RDWR)
1098 args->sysmsg_result |= LINUX_O_RDWR;
1099 if (dat.fc_flags & O_NDELAY)
1100 args->sysmsg_result |= LINUX_O_NONBLOCK;
1101 if (dat.fc_flags & O_APPEND)
1102 args->sysmsg_result |= LINUX_O_APPEND;
1103 if (dat.fc_flags & O_FSYNC)
1104 args->sysmsg_result |= LINUX_O_SYNC;
1105 if (dat.fc_flags & O_ASYNC)
1106 args->sysmsg_result |= LINUX_FASYNC;
1107 break;
1108 case LINUX_F_GETLK:
1109 bsd_to_linux_flock(&dat.fc_flock, &linux_flock);
1110 error = copyout(&linux_flock, (caddr_t)args->arg,
1111 sizeof(linux_flock));
1112 break;
1113 case LINUX_F_SETLK:
1114 case LINUX_F_SETLKW:
1115 break;
1116 case LINUX_F_GETOWN:
1117 args->sysmsg_result = dat.fc_owner;
1118 break;
1119 case LINUX_F_SETOWN:
1120 break;
1124 return(error);
1128 sys_linux_fcntl(struct linux_fcntl_args *args)
1130 struct linux_fcntl64_args args64;
1131 int error;
1133 #ifdef DEBUG
1134 if (ldebug(fcntl))
1135 kprintf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd);
1136 #endif
1138 args64.fd = args->fd;
1139 args64.cmd = args->cmd;
1140 args64.arg = args->arg;
1141 args64.sysmsg_result = 0;
1142 error = linux_fcntl_common(&args64);
1143 args->sysmsg_result = args64.sysmsg_result;
1144 return(error);
1147 #if defined(__i386__)
1149 sys_linux_fcntl64(struct linux_fcntl64_args *args)
1151 struct l_flock64 linux_flock;
1152 union fcntl_dat dat;
1153 int error, cmd = 0;
1155 #ifdef DEBUG
1156 if (ldebug(fcntl64))
1157 kprintf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd);
1158 #endif
1159 if (args->cmd == LINUX_F_GETLK64 || args->cmd == LINUX_F_SETLK64 ||
1160 args->cmd == LINUX_F_SETLKW64) {
1161 switch (args->cmd) {
1162 case LINUX_F_GETLK64:
1163 cmd = F_GETLK;
1164 break;
1165 case LINUX_F_SETLK64:
1166 cmd = F_SETLK;
1167 break;
1168 case LINUX_F_SETLKW64:
1169 cmd = F_SETLKW;
1170 break;
1173 error = copyin((caddr_t)args->arg, &linux_flock,
1174 sizeof(linux_flock));
1175 if (error)
1176 return (error);
1177 linux_to_bsd_flock64(&linux_flock, &dat.fc_flock);
1179 error = kern_fcntl(args->fd, cmd, &dat, curproc->p_ucred);
1181 if (error == 0 && args->cmd == LINUX_F_GETLK64) {
1182 bsd_to_linux_flock64(&dat.fc_flock, &linux_flock);
1183 error = copyout(&linux_flock, (caddr_t)args->arg,
1184 sizeof(linux_flock));
1186 } else {
1187 error = linux_fcntl_common(args);
1190 return (error);
1192 #endif /* __i386__ */
1195 sys_linux_chown(struct linux_chown_args *args)
1197 struct nlookupdata nd;
1198 char *path;
1199 int error;
1201 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
1202 if (error)
1203 return (error);
1204 #ifdef DEBUG
1205 if (ldebug(chown))
1206 kprintf(ARGS(chown, "%s, %d, %d"), path, args->uid, args->gid);
1207 #endif
1208 error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
1209 if (error == 0)
1210 error = kern_chown(&nd, args->uid, args->gid);
1211 nlookup_done(&nd);
1212 linux_free_path(&path);
1213 return(error);
1217 sys_linux_lchown(struct linux_lchown_args *args)
1219 struct nlookupdata nd;
1220 char *path;
1221 int error;
1223 error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
1224 if (error)
1225 return (error);
1226 #ifdef DEBUG
1227 if (ldebug(lchown))
1228 kprintf(ARGS(lchown, "%s, %d, %d"), path, args->uid, args->gid);
1229 #endif
1230 error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
1231 if (error == 0)
1232 error = kern_chown(&nd, args->uid, args->gid);
1233 nlookup_done(&nd);
1234 linux_free_path(&path);
1235 return(error);