Convert most manual accesses to filedesc->fd_files[] into the appropriate
[dragonfly.git] / sys / emulation / linux / linux_file.c
1 /*-
2  * Copyright (c) 1994-1995 Søren Schmidt
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer 
10  *    in this position and unchanged.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software withough specific prior written permission
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * $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.29 2006/05/19 07:33:43 dillon Exp $
30  */
31
32 #include "opt_compat.h"
33
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>
51
52 #include <vfs/ufs/quota.h>
53 #include <vfs/ufs/ufsmount.h>
54
55 #include <sys/file2.h>
56
57 #include <arch_linux/linux.h>
58 #include <arch_linux/linux_proto.h>
59 #include "linux_util.h"
60
61 int
62 linux_creat(struct linux_creat_args *args)
63 {
64         struct nlookupdata nd;
65         char *path;
66         int error;
67
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);
79         }
80         linux_free_path(&path);
81         return(error);
82 }
83
84 int
85 linux_open(struct linux_open_args *args)
86 {
87         struct thread *td = curthread;
88         struct proc *p = td->td_proc;
89         struct nlookupdata nd;
90         char *path;
91         int error, flags;
92
93         KKASSERT(p);
94
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);
101         }
102         if (error)
103                 return (error);
104
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);
139         }
140
141         if (error == 0 && !(flags & O_NOCTTY) && 
142                 SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
143                 struct file *fp;
144
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);
150                 }
151         }
152 #ifdef DEBUG
153         if (ldebug(open))
154                 printf(LMSG("open returns error %d"), error);
155 #endif
156         linux_free_path(&path);
157         return error;
158 }
159
160 int
161 linux_lseek(struct linux_lseek_args *args)
162 {
163         int error;
164
165 #ifdef DEBUG
166         if (ldebug(lseek))
167                 printf(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);
172
173         return error;
174 }
175
176 int
177 linux_llseek(struct linux_llseek_args *args)
178 {
179         int error;
180         off_t off, res;
181
182 #ifdef DEBUG
183         if (ldebug(llseek))
184                 printf(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);
188
189         error = kern_lseek(args->fd, off, args->whence, &res);
190
191         if (error == 0)
192                 error = copyout(&res, args->res, sizeof(res));
193         return (error);
194 }
195
196 int
197 linux_readdir(struct linux_readdir_args *args)
198 {
199         struct linux_getdents_args lda;
200         int error;
201
202         lda.fd = args->fd;
203         lda.dent = args->dent;
204         lda.count = 1;
205         lda.sysmsg_result = 0;
206         error = linux_getdents(&lda);
207         args->sysmsg_result = lda.sysmsg_result;
208         return(error);
209 }
210
211 /*
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...
218  */
219
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];
225 };
226
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];
233 };
234
235 #define LINUX_RECLEN(de,namlen) \
236     ALIGN((((char *)&(de)->d_name - (char *)de) + (namlen) + 1))
237
238 #define LINUX_DIRBLKSIZ         512
239
240 static int
241 getdents_common(struct linux_getdents64_args *args, int is64bit)
242 {
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         u_long *cookies = NULL, *cookiep;
260         int ncookies;
261
262         KKASSERT(p);
263
264         if ((error = getvnode(p->p_fd, args->fd, &fp)) != 0)
265                 return (error);
266
267         if ((fp->f_flag & FREAD) == 0)
268                 return (EBADF);
269
270         vp = (struct vnode *) fp->f_data;
271         if (vp->v_type != VDIR)
272                 return (EINVAL);
273
274         if ((error = VOP_GETATTR(vp, &va)))
275                 return (error);
276
277         nbytes = args->count;
278         if (nbytes == 1) {
279                 /* readdir(2) case. Always struct dirent. */
280                 if (is64bit)
281                         return (EINVAL);
282                 nbytes = sizeof(linux_dirent);
283                 justone = 1;
284         } else
285                 justone = 0;
286
287         off = fp->f_offset;
288
289         buflen = max(LINUX_DIRBLKSIZ, nbytes);
290         buflen = min(buflen, MAXBSIZE);
291         buf = malloc(buflen, M_TEMP, M_WAITOK);
292         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
293
294 again:
295         aiov.iov_base = buf;
296         aiov.iov_len = buflen;
297         auio.uio_iov = &aiov;
298         auio.uio_iovcnt = 1;
299         auio.uio_rw = UIO_READ;
300         auio.uio_segflg = UIO_SYSSPACE;
301         auio.uio_td = td;
302         auio.uio_resid = buflen;
303         auio.uio_offset = off;
304
305         if (cookies) {
306                 free(cookies, M_TEMP);
307                 cookies = NULL;
308         }
309
310         if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies,
311                  &cookies)))
312                 goto out;
313
314         inp = buf;
315         outp = (caddr_t)args->dirent;
316         resid = nbytes;
317         if ((len = buflen - auio.uio_resid) <= 0)
318                 goto eof;
319
320         cookiep = cookies;
321
322         if (cookies) {
323                 /*
324                  * When using cookies, the vfs has the option of reading from
325                  * a different offset than that supplied (UFS truncates the
326                  * offset to a block boundary to make sure that it never reads
327                  * partway through a directory entry, even if the directory
328                  * has been compacted).
329                  */
330                 while (len > 0 && ncookies > 0 && *cookiep <= off) {
331                         bdp = (struct dirent *) inp;
332                         len -= _DIRENT_DIRSIZ(bdp);
333                         inp += _DIRENT_DIRSIZ(bdp);
334                         cookiep++;
335                         ncookies--;
336                 }
337         }
338
339         while (len > 0) {
340                 if (cookiep && ncookies == 0)
341                         break;
342                 bdp = (struct dirent *) inp;
343                 reclen = _DIRENT_DIRSIZ(bdp);
344                 if (reclen & 3) {
345                         error = EFAULT;
346                         goto out;
347                 }
348
349                 if (bdp->d_ino == 0) {
350                         inp += reclen;
351                         if (cookiep) {
352                                 off = *cookiep++;
353                                 ncookies--;
354                         } else
355                                 off += reclen;
356
357                         len -= reclen;
358                         continue;
359                 }
360
361                 linuxreclen = (is64bit)
362                     ? LINUX_RECLEN(&linux_dirent64, bdp->d_namlen)
363                     : LINUX_RECLEN(&linux_dirent, bdp->d_namlen);
364
365                 if (reclen > len || resid < linuxreclen) {
366                         outp++;
367                         break;
368                 }
369
370                 if (justone) {
371                         /* readdir(2) case. */
372                         linux_dirent.d_ino = (l_long)bdp->d_ino;
373                         linux_dirent.d_off = (l_off_t)linuxreclen;
374                         linux_dirent.d_reclen = (l_ushort)bdp->d_namlen;
375                         strcpy(linux_dirent.d_name, bdp->d_name);
376                         error = copyout(&linux_dirent, outp, linuxreclen);
377                 } else {
378                         if (is64bit) {
379                                 linux_dirent64.d_ino = bdp->d_ino;
380                                 linux_dirent64.d_off = (cookiep)
381                                     ? (l_off_t)*cookiep
382                                     : (l_off_t)(off + reclen);
383                                 linux_dirent64.d_reclen =
384                                     (l_ushort)linuxreclen;
385                                 linux_dirent64.d_type = bdp->d_type;
386                                 strcpy(linux_dirent64.d_name, bdp->d_name);
387                                 error = copyout(&linux_dirent64, outp,
388                                     linuxreclen);
389                         } else {
390                                 linux_dirent.d_ino = bdp->d_ino;
391                                 linux_dirent.d_off = (cookiep)
392                                     ? (l_off_t)*cookiep
393                                     : (l_off_t)(off + reclen);
394                                 linux_dirent.d_reclen = (l_ushort)linuxreclen;
395                                 strcpy(linux_dirent.d_name, bdp->d_name);
396                                 error = copyout(&linux_dirent, outp,
397                                     linuxreclen);
398                         }
399                 }
400                 if (error)
401                         goto out;
402
403                 inp += reclen;
404                 if (cookiep) {
405                         off = *cookiep++;
406                         ncookies--;
407                 } else
408                         off += reclen;
409
410                 outp += linuxreclen;
411                 resid -= linuxreclen;
412                 len -= reclen;
413                 if (justone)
414                         break;
415         }
416
417         if (outp == (caddr_t)args->dirent)
418                 goto again;
419
420         fp->f_offset = off;
421         if (justone)
422                 nbytes = resid + linuxreclen;
423
424 eof:
425         args->sysmsg_result = nbytes - resid;
426
427 out:
428         if (cookies)
429                 free(cookies, M_TEMP);
430
431         VOP_UNLOCK(vp, 0);
432         free(buf, M_TEMP);
433         return (error);
434 }
435
436 int
437 linux_getdents(struct linux_getdents_args *args)
438 {
439 #ifdef DEBUG
440         if (ldebug(getdents))
441                 printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count);
442 #endif
443         return (getdents_common((struct linux_getdents64_args*)args, 0));
444 }
445
446 int
447 linux_getdents64(struct linux_getdents64_args *args)
448 {
449 #ifdef DEBUG
450         if (ldebug(getdents64))
451                 printf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count);
452 #endif
453         return (getdents_common(args, 1));
454 }
455
456 /*
457  * These exist mainly for hooks for doing /compat/linux translation.
458  */
459
460 int
461 linux_access(struct linux_access_args *args)
462 {
463         struct nlookupdata nd;
464         char *path;
465         int error;
466
467         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
468         if (error)
469                 return (error);
470 #ifdef DEBUG
471         if (ldebug(access))
472                 printf(ARGS(access, "%s, %d"), path, args->flags);
473 #endif
474         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
475         if (error == 0)
476                 error = kern_access(&nd, args->flags);
477         nlookup_done(&nd);
478         linux_free_path(&path);
479         return(error);
480 }
481
482 int
483 linux_unlink(struct linux_unlink_args *args)
484 {
485         struct nlookupdata nd;
486         char *path;
487         int error;
488
489         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
490         if (error)
491                 return (error);
492 #ifdef DEBUG
493         if (ldebug(unlink))
494                 printf(ARGS(unlink, "%s"), path);
495 #endif
496         error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
497         if (error == 0)
498                 error = kern_unlink(&nd);
499         nlookup_done(&nd);
500         linux_free_path(&path);
501         return(error);
502 }
503
504 int
505 linux_chdir(struct linux_chdir_args *args)
506 {
507         struct nlookupdata nd;
508         char *path;
509         int error;
510
511         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
512         if (error)
513                 return (error);
514 #ifdef DEBUG
515         if (ldebug(chdir))
516                 printf(ARGS(chdir, "%s"), path);
517 #endif
518         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
519         if (error == 0) {
520                 error = kern_chdir(&nd);
521                 nlookup_done(&nd);
522         }
523         linux_free_path(&path);
524         return(error);
525 }
526
527 int
528 linux_chmod(struct linux_chmod_args *args)
529 {
530         struct nlookupdata nd;
531         char *path;
532         int error;
533
534         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
535         if (error)
536                 return (error);
537 #ifdef DEBUG
538         if (ldebug(chmod))
539                 printf(ARGS(chmod, "%s, %d"), path, args->mode);
540 #endif
541         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
542         if (error == 0)
543                 error = kern_chmod(&nd, args->mode);
544         nlookup_done(&nd);
545         linux_free_path(&path);
546         return(error);
547 }
548
549 int
550 linux_mkdir(struct linux_mkdir_args *args)
551 {
552         struct nlookupdata nd;
553         char *path;
554         int error;
555
556         error = linux_copyin_path(args->path, &path, LINUX_PATH_CREATE);
557         if (error)
558                 return (error);
559 #ifdef DEBUG
560         if (ldebug(mkdir))
561                 printf(ARGS(mkdir, "%s, %d"), path, args->mode);
562 #endif
563         error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
564         if (error == 0)
565                 error = kern_mkdir(&nd, args->mode);
566         nlookup_done(&nd);
567
568         linux_free_path(&path);
569         return(error);
570 }
571
572 int
573 linux_rmdir(struct linux_rmdir_args *args)
574 {
575         struct nlookupdata nd;
576         char *path;
577         int error;
578
579         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
580         if (error)
581                 return (error);
582 #ifdef DEBUG
583         if (ldebug(rmdir))
584                 printf(ARGS(rmdir, "%s"), path);
585 #endif
586         error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
587         if (error == 0)
588                 error = kern_rmdir(&nd);
589         nlookup_done(&nd);
590         linux_free_path(&path);
591         return(error);
592 }
593
594 int
595 linux_rename(struct linux_rename_args *args)
596 {
597         struct nlookupdata fromnd, tond;
598         char *from, *to;
599         int error;
600
601         error = linux_copyin_path(args->from, &from, LINUX_PATH_EXISTS);
602         if (error)
603                 return (error);
604         error = linux_copyin_path(args->to, &to, LINUX_PATH_CREATE);
605         if (error) {
606                 linux_free_path(&from);
607                 return (error);
608         }
609 #ifdef DEBUG
610         if (ldebug(rename))
611                 printf(ARGS(rename, "%s, %s"), from, to);
612 #endif
613         error = nlookup_init(&fromnd, from, UIO_SYSSPACE, 0);
614         if (error == 0) {
615                 error = nlookup_init(&tond, to, UIO_SYSSPACE, 0);
616                 if (error == 0)
617                         error = kern_rename(&fromnd, &tond);
618                 nlookup_done(&tond);
619         }
620         nlookup_done(&fromnd);
621         linux_free_path(&from);
622         linux_free_path(&to);
623         return(error);
624 }
625
626 int
627 linux_symlink(struct linux_symlink_args *args)
628 {
629         struct thread *td = curthread;
630         struct nlookupdata nd;
631         char *path, *link;
632         int error;
633         int mode;
634
635         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
636         if (error)
637                 return (error);
638         error = linux_copyin_path(args->to, &link, LINUX_PATH_CREATE);
639         if (error) {
640                 linux_free_path(&path);
641                 return (error);
642         }
643 #ifdef DEBUG
644         if (ldebug(symlink))
645                 printf(ARGS(symlink, "%s, %s"), path, link);
646 #endif
647         error = nlookup_init(&nd, link, UIO_SYSSPACE, 0);
648         if (error == 0) {
649                 mode = ACCESSPERMS & ~td->td_proc->p_fd->fd_cmask;
650                 error = kern_symlink(&nd, path, mode);
651         }
652         nlookup_done(&nd);
653         linux_free_path(&path);
654         linux_free_path(&link);
655         return(error);
656 }
657
658 int
659 linux_readlink(struct linux_readlink_args *args)
660 {
661         struct nlookupdata nd;
662         char *path;
663         int error;
664
665         error = linux_copyin_path(args->name, &path, LINUX_PATH_EXISTS);
666         if (error)
667                 return (error);
668 #ifdef DEBUG
669         if (ldebug(readlink))
670                 printf(ARGS(readlink, "%s, %p, %d"), path, (void *)args->buf,
671                     args->count);
672 #endif
673         error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
674         if (error == 0) {
675                 error = kern_readlink(&nd, args->buf, args->count,
676                                         &args->sysmsg_result);
677         }
678         nlookup_done(&nd);
679         linux_free_path(&path);
680         return(error);
681 }
682
683 int
684 linux_truncate(struct linux_truncate_args *args)
685 {
686         struct nlookupdata nd;
687         char *path;
688         int error;
689
690         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
691         if (error)
692                 return (error);
693 #ifdef DEBUG
694         if (ldebug(truncate))
695                 printf(ARGS(truncate, "%s, %ld"), path,
696                     (long)args->length);
697 #endif
698         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
699         if (error == 0)
700                 error = kern_truncate(&nd, args->length);
701         nlookup_done(&nd);
702         linux_free_path(&path);
703         return(error);
704 }
705
706 int
707 linux_truncate64(struct linux_truncate64_args *args)
708 {
709         struct nlookupdata nd;
710         char *path;
711         int error;
712
713         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
714         if (error)
715                 return (error);
716 #ifdef DEBUG
717         if (ldebug(truncate64))
718                 printf(ARGS(truncate64, "%s, %lld"), path,
719                     (off_t)args->length);
720 #endif
721         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
722         if (error == 0)
723                 error = kern_truncate(&nd, args->length);
724         nlookup_done(&nd);
725         linux_free_path(&path);
726         return error;
727 }
728
729 int
730 linux_ftruncate(struct linux_ftruncate_args *args)
731 {
732         int error;
733
734 #ifdef DEBUG
735         if (ldebug(ftruncate))
736                 printf(ARGS(ftruncate, "%d, %ld"), args->fd,
737                     (long)args->length);
738 #endif
739         error = kern_ftruncate(args->fd, args->length);
740
741         return error;
742 }
743
744 int
745 linux_ftruncate64(struct linux_ftruncate64_args *args)
746 {
747         int error;
748
749 #ifdef DEBUG
750         if (ldebug(ftruncate))
751                 printf(ARGS(ftruncate64, "%d, %lld"), args->fd,
752                     (off_t)args->length);
753 #endif
754         error = kern_ftruncate(args->fd, args->length);
755
756         return error;
757 }
758
759 int
760 linux_link(struct linux_link_args *args)
761 {
762         struct nlookupdata nd, linknd;
763         char *path, *link;
764         int error;
765
766         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
767         if (error)
768                 return (error);
769         error = linux_copyin_path(args->to, &link, LINUX_PATH_CREATE);
770         if (error) {
771                 linux_free_path(&path);
772                 return (error);
773         }
774 #ifdef DEBUG
775         if (ldebug(link))
776                 printf(ARGS(link, "%s, %s"), path, link);
777 #endif
778         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
779         if (error == 0) {
780                 error = nlookup_init(&linknd, link, UIO_SYSSPACE, 0);
781                 if (error == 0)
782                         error = kern_link(&nd, &linknd);
783                 nlookup_done(&linknd);
784         }
785         nlookup_done(&nd);
786         linux_free_path(&path);
787         linux_free_path(&link);
788         return(error);
789 }
790
791 int
792 linux_fdatasync(struct linux_fdatasync_args *uap)
793 {
794         struct fsync_args bsd;
795         int error;
796
797         bsd.fd = uap->fd;
798         bsd.sysmsg_result = 0;
799
800         error = fsync(&bsd);
801         uap->sysmsg_result = bsd.sysmsg_result;
802         return(error);
803 }
804
805 int
806 linux_pread(struct linux_pread_args *uap)
807 {
808         struct thread *td = curthread;
809         struct uio auio;
810         struct iovec aiov;
811         int error;
812
813         aiov.iov_base = uap->buf;
814         aiov.iov_len = uap->nbyte;
815         auio.uio_iov = &aiov;
816         auio.uio_iovcnt = 1;
817         auio.uio_offset = uap->offset;
818         auio.uio_resid = uap->nbyte;
819         auio.uio_rw = UIO_READ;
820         auio.uio_segflg = UIO_USERSPACE;
821         auio.uio_td = td;
822
823         if (auio.uio_resid < 0)
824                 error = EINVAL;
825         else
826                 error = kern_preadv(uap->fd, &auio, FOF_OFFSET, &uap->sysmsg_result);
827         return(error);
828 }
829
830 int
831 linux_pwrite(struct linux_pwrite_args *uap)
832 {
833         struct thread *td = curthread;
834         struct uio auio;
835         struct iovec aiov;
836         int error;
837
838         aiov.iov_base = uap->buf;
839         aiov.iov_len = uap->nbyte;
840         auio.uio_iov = &aiov;
841         auio.uio_iovcnt = 1;
842         auio.uio_offset = uap->offset;
843         auio.uio_resid = uap->nbyte;
844         auio.uio_rw = UIO_WRITE;
845         auio.uio_segflg = UIO_USERSPACE;
846         auio.uio_td = td;
847
848         if (auio.uio_resid < 0)
849                 error = EINVAL;
850         else
851                 error = kern_pwritev(uap->fd, &auio, FOF_OFFSET, &uap->sysmsg_result);
852
853         return(error);
854 }
855
856 int
857 linux_oldumount(struct linux_oldumount_args *args)
858 {
859         struct linux_umount_args args2;
860         int error;
861
862         args2.path = args->path;
863         args2.flags = 0;
864         args2.sysmsg_result = 0;
865         error = linux_umount(&args2);
866         args->sysmsg_result = args2.sysmsg_result;
867         return(error);
868 }
869
870 int
871 linux_umount(struct linux_umount_args *args)
872 {
873         struct unmount_args bsd;
874         int error;
875
876         bsd.path = args->path;
877         bsd.flags = args->flags;        /* XXX correct? */
878         bsd.sysmsg_result = 0;
879
880         error = unmount(&bsd);
881         args->sysmsg_result = bsd.sysmsg_result;
882         return(error);
883 }
884
885 /*
886  * fcntl family of syscalls
887  */
888
889 struct l_flock {
890         l_short         l_type;
891         l_short         l_whence;
892         l_off_t         l_start;
893         l_off_t         l_len;
894         l_pid_t         l_pid;
895 };
896
897 static void
898 linux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock)
899 {
900         switch (linux_flock->l_type) {
901         case LINUX_F_RDLCK:
902                 bsd_flock->l_type = F_RDLCK;
903                 break;
904         case LINUX_F_WRLCK:
905                 bsd_flock->l_type = F_WRLCK;
906                 break;
907         case LINUX_F_UNLCK:
908                 bsd_flock->l_type = F_UNLCK;
909                 break;
910         default:
911                 bsd_flock->l_type = -1;
912                 break;
913         }
914         bsd_flock->l_whence = linux_flock->l_whence;
915         bsd_flock->l_start = (off_t)linux_flock->l_start;
916         bsd_flock->l_len = (off_t)linux_flock->l_len;
917         bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
918 }
919
920 static void
921 bsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock)
922 {
923         switch (bsd_flock->l_type) {
924         case F_RDLCK:
925                 linux_flock->l_type = LINUX_F_RDLCK;
926                 break;
927         case F_WRLCK:
928                 linux_flock->l_type = LINUX_F_WRLCK;
929                 break;
930         case F_UNLCK:
931                 linux_flock->l_type = LINUX_F_UNLCK;
932                 break;
933         }
934         linux_flock->l_whence = bsd_flock->l_whence;
935         linux_flock->l_start = (l_off_t)bsd_flock->l_start;
936         linux_flock->l_len = (l_off_t)bsd_flock->l_len;
937         linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
938 }
939
940 #if defined(__i386__)
941 struct l_flock64 {
942         l_short         l_type;
943         l_short         l_whence;
944         l_loff_t        l_start;
945         l_loff_t        l_len;
946         l_pid_t         l_pid;
947 };
948
949 static void
950 linux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock)
951 {
952         switch (linux_flock->l_type) {
953         case LINUX_F_RDLCK:
954                 bsd_flock->l_type = F_RDLCK;
955                 break;
956         case LINUX_F_WRLCK:
957                 bsd_flock->l_type = F_WRLCK;
958                 break;
959         case LINUX_F_UNLCK:
960                 bsd_flock->l_type = F_UNLCK;
961                 break;
962         default:
963                 bsd_flock->l_type = -1;
964                 break;
965         }
966         bsd_flock->l_whence = linux_flock->l_whence;
967         bsd_flock->l_start = (off_t)linux_flock->l_start;
968         bsd_flock->l_len = (off_t)linux_flock->l_len;
969         bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
970 }
971
972 static void
973 bsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock)
974 {
975         switch (bsd_flock->l_type) {
976         case F_RDLCK:
977                 linux_flock->l_type = LINUX_F_RDLCK;
978                 break;
979         case F_WRLCK:
980                 linux_flock->l_type = LINUX_F_WRLCK;
981                 break;
982         case F_UNLCK:
983                 linux_flock->l_type = LINUX_F_UNLCK;
984                 break;
985         }
986         linux_flock->l_whence = bsd_flock->l_whence;
987         linux_flock->l_start = (l_loff_t)bsd_flock->l_start;
988         linux_flock->l_len = (l_loff_t)bsd_flock->l_len;
989         linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
990 }
991 #endif /* __i386__ */
992
993 static int
994 linux_fcntl_common(struct linux_fcntl64_args *args)
995 {
996         struct proc *p = curproc;
997         struct l_flock linux_flock;
998         struct file *fp;
999         union fcntl_dat dat;
1000         int error, cmd;
1001
1002         switch (args->cmd) {
1003         case LINUX_F_DUPFD:
1004                 cmd = F_DUPFD;
1005                 dat.fc_fd = args->arg;
1006                 break;
1007         case LINUX_F_GETFD:
1008                 cmd = F_GETFD;
1009                 break;
1010         case LINUX_F_SETFD:
1011                 cmd = F_SETFD;
1012                 dat.fc_cloexec = args->arg;
1013                 break;
1014         case LINUX_F_GETFL:
1015                 cmd = F_GETFL;
1016                 break;
1017         case LINUX_F_SETFL:
1018                 cmd = F_SETFL;
1019                 dat.fc_flags = 0;
1020                 if (args->arg & LINUX_O_NDELAY)
1021                         dat.fc_flags |= O_NONBLOCK;
1022                 if (args->arg & LINUX_O_APPEND)
1023                         dat.fc_flags |= O_APPEND;
1024                 if (args->arg & LINUX_O_SYNC)
1025                         dat.fc_flags |= O_FSYNC;
1026                 if (args->arg & LINUX_FASYNC)
1027                         dat.fc_flags |= O_ASYNC;
1028                 break;
1029         case LINUX_F_GETLK:
1030         case LINUX_F_SETLK:
1031         case LINUX_F_SETLKW:
1032                 cmd = F_GETLK;
1033                 error = copyin((caddr_t)args->arg, &linux_flock,
1034                     sizeof(linux_flock));
1035                 if (error)
1036                         return (error);
1037                 linux_to_bsd_flock(&linux_flock, &dat.fc_flock);
1038                 break;
1039         case LINUX_F_GETOWN:
1040                 cmd = F_GETOWN;
1041                 break;
1042         case LINUX_F_SETOWN:
1043                 /*
1044                  * XXX some Linux applications depend on F_SETOWN having no
1045                  * significant effect for pipes (SIGIO is not delivered for
1046                  * pipes under Linux-2.2.35 at least).
1047                  */
1048                 fp = holdfp(p->p_fd, args->fd, -1);
1049                 if (fp == NULL)
1050                         return (EBADF);
1051                 if (fp->f_type == DTYPE_PIPE) {
1052                         fdrop(fp);
1053                         return (EINVAL);
1054                 }
1055                 fdrop(fp);
1056                 cmd = F_SETOWN;
1057                 dat.fc_owner = args->arg;
1058                 break;
1059         default:
1060                 return (EINVAL);
1061         }
1062
1063         error = kern_fcntl(args->fd, cmd, &dat, p->p_ucred);
1064
1065         if (error == 0) {
1066                 switch (args->cmd) {
1067                 case LINUX_F_DUPFD:
1068                         args->sysmsg_result = dat.fc_fd;
1069                         break;
1070                 case LINUX_F_GETFD:
1071                         args->sysmsg_result = dat.fc_cloexec;
1072                         break;
1073                 case LINUX_F_SETFD:
1074                         break;
1075                 case LINUX_F_GETFL:
1076                         args->sysmsg_result = 0;
1077                         if (dat.fc_flags & O_RDONLY)
1078                                 args->sysmsg_result |= LINUX_O_RDONLY;
1079                         if (dat.fc_flags & O_WRONLY)
1080                                 args->sysmsg_result |= LINUX_O_WRONLY;
1081                         if (dat.fc_flags & O_RDWR)
1082                                 args->sysmsg_result |= LINUX_O_RDWR;
1083                         if (dat.fc_flags & O_NDELAY)
1084                                 args->sysmsg_result |= LINUX_O_NONBLOCK;
1085                         if (dat.fc_flags & O_APPEND)
1086                                 args->sysmsg_result |= LINUX_O_APPEND;
1087                         if (dat.fc_flags & O_FSYNC)
1088                                 args->sysmsg_result |= LINUX_O_SYNC;
1089                         if (dat.fc_flags & O_ASYNC)
1090                                 args->sysmsg_result |= LINUX_FASYNC;
1091                         break;
1092                 case LINUX_F_GETLK:
1093                         bsd_to_linux_flock(&dat.fc_flock, &linux_flock);
1094                         error = copyout(&linux_flock, (caddr_t)args->arg,
1095                             sizeof(linux_flock));
1096                         break;
1097                 case LINUX_F_SETLK:
1098                 case LINUX_F_SETLKW:
1099                         break;
1100                 case LINUX_F_GETOWN:
1101                         args->sysmsg_result = dat.fc_owner;
1102                         break;
1103                 case LINUX_F_SETOWN:
1104                         break;
1105                 }
1106         }
1107
1108         return(error);
1109 }
1110
1111 int
1112 linux_fcntl(struct linux_fcntl_args *args)
1113 {
1114         struct linux_fcntl64_args args64;
1115         int error;
1116
1117 #ifdef DEBUG
1118         if (ldebug(fcntl))
1119                 printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd);
1120 #endif
1121
1122         args64.fd = args->fd;
1123         args64.cmd = args->cmd;
1124         args64.arg = args->arg;
1125         args64.sysmsg_result = 0;
1126         error = linux_fcntl_common(&args64);
1127         args->sysmsg_result = args64.sysmsg_result;
1128         return(error);
1129 }
1130
1131 #if defined(__i386__)
1132 int
1133 linux_fcntl64(struct linux_fcntl64_args *args)
1134 {
1135         struct l_flock64 linux_flock;
1136         union fcntl_dat dat;
1137         int error, cmd = 0;
1138
1139 #ifdef DEBUG
1140         if (ldebug(fcntl64))
1141                 printf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd);
1142 #endif
1143         if (args->cmd == LINUX_F_GETLK64 || args->cmd == LINUX_F_SETLK64 ||
1144             args->cmd == LINUX_F_SETLKW64) {
1145                 switch (args->cmd) {
1146                 case LINUX_F_GETLK64:
1147                         cmd = F_GETLK;
1148                         break;
1149                 case LINUX_F_SETLK64:
1150                         cmd = F_SETLK;
1151                         break;
1152                 case LINUX_F_SETLKW64:
1153                         cmd = F_SETLKW;
1154                         break;
1155                 }
1156
1157                 error = copyin((caddr_t)args->arg, &linux_flock,
1158                     sizeof(linux_flock));
1159                 if (error)
1160                         return (error);
1161                 linux_to_bsd_flock64(&linux_flock, &dat.fc_flock);
1162
1163                 error = kern_fcntl(args->fd, cmd, &dat, curproc->p_ucred);
1164
1165                 if (error == 0 && args->cmd == LINUX_F_GETLK64) {
1166                         bsd_to_linux_flock64(&dat.fc_flock, &linux_flock);
1167                         error = copyout(&linux_flock, (caddr_t)args->arg,
1168                             sizeof(linux_flock));
1169                 }
1170         } else {
1171                 error = linux_fcntl_common(args);
1172         }
1173
1174         return (error);
1175 }
1176 #endif /* __i386__ */
1177
1178 int
1179 linux_chown(struct linux_chown_args *args)
1180 {
1181         struct nlookupdata nd;
1182         char *path;
1183         int error;
1184
1185         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
1186         if (error)
1187                 return (error);
1188 #ifdef DEBUG
1189         if (ldebug(chown))
1190                 printf(ARGS(chown, "%s, %d, %d"), path, args->uid, args->gid);
1191 #endif
1192         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
1193         if (error == 0)
1194                 error = kern_chown(&nd, args->uid, args->gid);
1195         nlookup_done(&nd);
1196         linux_free_path(&path);
1197         return(error);
1198 }
1199
1200 int
1201 linux_lchown(struct linux_lchown_args *args)
1202 {
1203         struct nlookupdata nd;
1204         char *path;
1205         int error;
1206
1207         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
1208         if (error)
1209                 return (error);
1210 #ifdef DEBUG
1211         if (ldebug(lchown))
1212                 printf(ARGS(lchown, "%s, %d, %d"), path, args->uid, args->gid);
1213 #endif
1214         error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
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);
1220 }
1221