Merge branch 'vendor/OPENSSH'
[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.39 2008/09/28 05:08:16 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 sys_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                 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);
79         }
80         linux_free_path(&path);
81         return(error);
82 }
83
84 int
85 sys_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                 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);
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                 kprintf(LMSG("open returns error %d"), error);
155 #endif
156         linux_free_path(&path);
157         return error;
158 }
159
160 int
161 sys_linux_lseek(struct linux_lseek_args *args)
162 {
163         int error;
164
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);
172
173         return error;
174 }
175
176 int
177 sys_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                 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);
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 sys_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 = sys_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         off_t *cookies = NULL, *cookiep;
260         int ncookies;
261
262         KKASSERT(p);
263
264         if ((error = holdvnode(p->p_fd, args->fd, &fp)) != 0)
265                 return (error);
266
267         if ((fp->f_flag & FREAD) == 0) {
268                 error = EBADF;
269                 goto done;
270         }
271
272         vp = (struct vnode *) fp->f_data;
273         if (vp->v_type != VDIR) {
274                 error = EINVAL;
275                 goto done;
276         }
277
278         if ((error = VOP_GETATTR(vp, &va)) != 0)
279                 goto done;
280
281         nbytes = args->count;
282         if (nbytes == -1) {
283                 /* readdir(2) case. Always struct dirent. */
284                 if (is64bit) {
285                         error = EINVAL;
286                         goto done;
287                 }
288                 nbytes = sizeof(linux_dirent);
289                 justone = 1;
290         } else {
291                 justone = 0;
292         }
293         if (nbytes < 0)
294                 nbytes = 0;
295
296         off = fp->f_offset;
297
298         buflen = max(LINUX_DIRBLKSIZ, nbytes);
299         buflen = min(buflen, MAXBSIZE);
300         buf = kmalloc(buflen, M_TEMP, M_WAITOK);
301
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;
312
313         if (cookies) {
314                 kfree(cookies, M_TEMP);
315                 cookies = NULL;
316         }
317
318         eofflag = 0;
319         ncookies = 0;
320         if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies,
321                  &cookies)))
322                 goto out;
323
324         inp = buf;
325         outp = (caddr_t)args->dirent;
326         resid = nbytes;
327         if ((len = buflen - auio.uio_resid) <= 0)
328                 goto eof;
329
330         cookiep = cookies;
331
332         if (cookies) {
333                 /*
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).
339                  */
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--;
346                 }
347         }
348
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;
357                 }
358
359                 if (bdp->d_ino == 0) {
360                         inp += reclen;
361                         if (cookiep) {
362                                 off = *cookiep++;
363                                 ++off;
364                                 ncookies--;
365                         } else {
366                                 off += reclen;
367                         }
368                         len -= reclen;
369                         continue;
370                 }
371
372                 linuxreclen = (is64bit)
373                     ? LINUX_RECLEN(&linux_dirent64, bdp->d_namlen)
374                     : LINUX_RECLEN(&linux_dirent, bdp->d_namlen);
375
376                 if (reclen > len || resid < linuxreclen) {
377                         outp++;
378                         break;
379                 }
380
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);
411                         }
412                 }
413                 if (error)
414                         goto out;
415
416                 inp += reclen;
417                 if (cookiep) {
418                         off = *cookiep++;
419                         ++off;
420                         ncookies--;
421                 } else {
422                         off += reclen;
423                 }
424
425                 outp += linuxreclen;
426                 resid -= linuxreclen;
427                 len -= reclen;
428                 if (justone)
429                         break;
430         }
431
432         if (outp == (caddr_t)args->dirent && eofflag == 0)
433                 goto again;
434
435         fp->f_offset = off;
436         if (justone)
437                 nbytes = resid + linuxreclen;
438
439 eof:
440         args->sysmsg_result = nbytes - resid;
441
442 out:
443         if (cookies)
444                 kfree(cookies, M_TEMP);
445
446         kfree(buf, M_TEMP);
447 done:
448         fdrop(fp);
449         return (error);
450 }
451
452 int
453 sys_linux_getdents(struct linux_getdents_args *args)
454 {
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));
460 }
461
462 int
463 sys_linux_getdents64(struct linux_getdents64_args *args)
464 {
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));
470 }
471
472 /*
473  * These exist mainly for hooks for doing /compat/linux translation.
474  */
475
476 int
477 sys_linux_access(struct linux_access_args *args)
478 {
479         struct nlookupdata nd;
480         char *path;
481         int error;
482
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);
496 }
497
498 int
499 sys_linux_unlink(struct linux_unlink_args *args)
500 {
501         struct nlookupdata nd;
502         char *path;
503         int error;
504
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);
518 }
519
520 int
521 sys_linux_chdir(struct linux_chdir_args *args)
522 {
523         struct nlookupdata nd;
524         char *path;
525         int error;
526
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);
538         }
539         linux_free_path(&path);
540         return(error);
541 }
542
543 int
544 sys_linux_chmod(struct linux_chmod_args *args)
545 {
546         struct nlookupdata nd;
547         char *path;
548         int error;
549
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);
563 }
564
565 int
566 sys_linux_mkdir(struct linux_mkdir_args *args)
567 {
568         struct nlookupdata nd;
569         char *path;
570         int error;
571
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);
583
584         linux_free_path(&path);
585         return(error);
586 }
587
588 int
589 sys_linux_rmdir(struct linux_rmdir_args *args)
590 {
591         struct nlookupdata nd;
592         char *path;
593         int error;
594
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);
608 }
609
610 int
611 sys_linux_rename(struct linux_rename_args *args)
612 {
613         struct nlookupdata fromnd, tond;
614         char *from, *to;
615         int error;
616
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);
624         }
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);
635         }
636         nlookup_done(&fromnd);
637         linux_free_path(&from);
638         linux_free_path(&to);
639         return(error);
640 }
641
642 int
643 sys_linux_symlink(struct linux_symlink_args *args)
644 {
645         struct thread *td = curthread;
646         struct nlookupdata nd;
647         char *path, *link;
648         int error;
649         int mode;
650
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);
658         }
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);
667         }
668         nlookup_done(&nd);
669         linux_free_path(&path);
670         linux_free_path(&link);
671         return(error);
672 }
673
674 int
675 sys_linux_readlink(struct linux_readlink_args *args)
676 {
677         struct nlookupdata nd;
678         char *path;
679         int error;
680
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);
693         }
694         nlookup_done(&nd);
695         linux_free_path(&path);
696         return(error);
697 }
698
699 int
700 sys_linux_truncate(struct linux_truncate_args *args)
701 {
702         struct nlookupdata nd;
703         char *path;
704         int error;
705
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);
720 }
721
722 int
723 sys_linux_truncate64(struct linux_truncate64_args *args)
724 {
725         struct nlookupdata nd;
726         char *path;
727         int error;
728
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;
743 }
744
745 int
746 sys_linux_ftruncate(struct linux_ftruncate_args *args)
747 {
748         int error;
749
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);
756
757         return error;
758 }
759
760 int
761 sys_linux_ftruncate64(struct linux_ftruncate64_args *args)
762 {
763         int error;
764
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);
771
772         return error;
773 }
774
775 int
776 sys_linux_link(struct linux_link_args *args)
777 {
778         struct nlookupdata nd, linknd;
779         char *path, *link;
780         int error;
781
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);
789         }
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);
800         }
801         nlookup_done(&nd);
802         linux_free_path(&path);
803         linux_free_path(&link);
804         return(error);
805 }
806
807 int
808 sys_linux_fdatasync(struct linux_fdatasync_args *uap)
809 {
810         struct fsync_args bsd;
811         int error;
812
813         bsd.fd = uap->fd;
814         bsd.sysmsg_result = 0;
815
816         error = sys_fsync(&bsd);
817         uap->sysmsg_result = bsd.sysmsg_result;
818         return(error);
819 }
820
821 int
822 sys_linux_pread(struct linux_pread_args *uap)
823 {
824         struct thread *td = curthread;
825         struct uio auio;
826         struct iovec aiov;
827         int error;
828
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;
838
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);
844 }
845
846 int
847 sys_linux_pwrite(struct linux_pwrite_args *uap)
848 {
849         struct thread *td = curthread;
850         struct uio auio;
851         struct iovec aiov;
852         int error;
853
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;
863
864         if (auio.uio_resid < 0)
865                 error = EINVAL;
866         else
867                 error = kern_pwritev(uap->fd, &auio, O_FOFFSET, &uap->sysmsg_result);
868
869         return(error);
870 }
871
872 int
873 sys_linux_oldumount(struct linux_oldumount_args *args)
874 {
875         struct linux_umount_args args2;
876         int error;
877
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);
884 }
885
886 int
887 sys_linux_umount(struct linux_umount_args *args)
888 {
889         struct unmount_args bsd;
890         int error;
891
892         bsd.path = args->path;
893         bsd.flags = args->flags;        /* XXX correct? */
894         bsd.sysmsg_result = 0;
895
896         error = sys_unmount(&bsd);
897         args->sysmsg_result = bsd.sysmsg_result;
898         return(error);
899 }
900
901 /*
902  * fcntl family of syscalls
903  */
904
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;
911 };
912
913 static void
914 linux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock)
915 {
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;
929         }
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;
934 }
935
936 static void
937 bsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock)
938 {
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;
949         }
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;
954 }
955
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;
963 };
964
965 static void
966 linux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock)
967 {
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;
981         }
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;
986 }
987
988 static void
989 bsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock)
990 {
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;
1001         }
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;
1006 }
1007 #endif /* __i386__ */
1008
1009 static int
1010 linux_fcntl_common(struct linux_fcntl64_args *args)
1011 {
1012         struct proc *p = curproc;
1013         struct l_flock linux_flock;
1014         struct file *fp;
1015         union fcntl_dat dat;
1016         int error, cmd;
1017
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:
1059                 /*
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).
1063                  */
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);
1070                 }
1071                 fdrop(fp);
1072                 cmd = F_SETOWN;
1073                 dat.fc_owner = args->arg;
1074                 break;
1075         default:
1076                 return (EINVAL);
1077         }
1078
1079         error = kern_fcntl(args->fd, cmd, &dat, p->p_ucred);
1080
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;
1121                 }
1122         }
1123
1124         return(error);
1125 }
1126
1127 int
1128 sys_linux_fcntl(struct linux_fcntl_args *args)
1129 {
1130         struct linux_fcntl64_args args64;
1131         int error;
1132
1133 #ifdef DEBUG
1134         if (ldebug(fcntl))
1135                 kprintf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd);
1136 #endif
1137
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);
1145 }
1146
1147 #if defined(__i386__)
1148 int
1149 sys_linux_fcntl64(struct linux_fcntl64_args *args)
1150 {
1151         struct l_flock64 linux_flock;
1152         union fcntl_dat dat;
1153         int error, cmd = 0;
1154
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;
1171                 }
1172
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);
1178
1179                 error = kern_fcntl(args->fd, cmd, &dat, curproc->p_ucred);
1180
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));
1185                 }
1186         } else {
1187                 error = linux_fcntl_common(args);
1188         }
1189
1190         return (error);
1191 }
1192 #endif /* __i386__ */
1193
1194 int
1195 sys_linux_chown(struct linux_chown_args *args)
1196 {
1197         struct nlookupdata nd;
1198         char *path;
1199         int error;
1200
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);
1214 }
1215
1216 int
1217 sys_linux_lchown(struct linux_lchown_args *args)
1218 {
1219         struct nlookupdata nd;
1220         char *path;
1221         int error;
1222
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);
1236 }
1237