proc->thread stage 4: rework the VFS and DEVICE subsystems to take thread
[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.4 2003/06/25 03:55:44 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/filedesc.h>
41 #include <sys/lock.h>
42 #include <sys/malloc.h>
43 #include <sys/mount.h>
44 #include <sys/proc.h>
45 #include <sys/sysproto.h>
46 #include <sys/tty.h>
47 #include <sys/vnode.h>
48
49 #include <ufs/ufs/quota.h>
50 #include <ufs/ufs/ufsmount.h>
51
52 #include <sys/file2.h>
53
54 #include <machine/../linux/linux.h>
55 #include <machine/../linux/linux_proto.h>
56 #include <compat/linux/linux_util.h>
57
58 #ifndef __alpha__
59 int
60 linux_creat(struct linux_creat_args *args)
61 {
62     struct open_args /* {
63         char *path;
64         int flags;
65         int mode;
66     } */ bsd_open_args;
67     caddr_t sg;
68
69     sg = stackgap_init();
70     CHECKALTCREAT(&sg, args->path);
71
72 #ifdef DEBUG
73         if (ldebug(creat))
74                 printf(ARGS(creat, "%s, %d"), args->path, args->mode);
75 #endif
76     bsd_open_args.path = args->path;
77     bsd_open_args.mode = args->mode;
78     bsd_open_args.flags = O_WRONLY | O_CREAT | O_TRUNC;
79     return open(&bsd_open_args);
80 }
81 #endif /*!__alpha__*/
82
83 int
84 linux_open(struct linux_open_args *args)
85 {
86     struct open_args /* {
87         char *path;
88         int flags;
89         int mode;
90     } */ bsd_open_args;
91     int error;
92     caddr_t sg;
93     struct thread *td = curthread;
94     struct proc *p = td->td_proc;
95
96     KKASSERT(p);
97
98     sg = stackgap_init();
99     
100     if (args->flags & LINUX_O_CREAT)
101         CHECKALTCREAT(&sg, args->path);
102     else
103         CHECKALTEXIST(&sg, args->path);
104
105 #ifdef DEBUG
106         if (ldebug(open))
107                 printf(ARGS(open, "%s, 0x%x, 0x%x"),
108                     args->path, args->flags, args->mode);
109 #endif
110     bsd_open_args.flags = 0;
111     if (args->flags & LINUX_O_RDONLY)
112         bsd_open_args.flags |= O_RDONLY;
113     if (args->flags & LINUX_O_WRONLY) 
114         bsd_open_args.flags |= O_WRONLY;
115     if (args->flags & LINUX_O_RDWR)
116         bsd_open_args.flags |= O_RDWR;
117     if (args->flags & LINUX_O_NDELAY)
118         bsd_open_args.flags |= O_NONBLOCK;
119     if (args->flags & LINUX_O_APPEND)
120         bsd_open_args.flags |= O_APPEND;
121     if (args->flags & LINUX_O_SYNC)
122         bsd_open_args.flags |= O_FSYNC;
123     if (args->flags & LINUX_O_NONBLOCK)
124         bsd_open_args.flags |= O_NONBLOCK;
125     if (args->flags & LINUX_FASYNC)
126         bsd_open_args.flags |= O_ASYNC;
127     if (args->flags & LINUX_O_CREAT)
128         bsd_open_args.flags |= O_CREAT;
129     if (args->flags & LINUX_O_TRUNC)
130         bsd_open_args.flags |= O_TRUNC;
131     if (args->flags & LINUX_O_EXCL)
132         bsd_open_args.flags |= O_EXCL;
133     if (args->flags & LINUX_O_NOCTTY)
134         bsd_open_args.flags |= O_NOCTTY;
135     bsd_open_args.path = args->path;
136     bsd_open_args.mode = args->mode;
137
138     error = open(&bsd_open_args);
139     if (!error && !(bsd_open_args.flags & O_NOCTTY) && 
140         SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
141         struct filedesc *fdp = p->p_fd;
142         struct file *fp = fdp->fd_ofiles[p->p_retval[0]];
143
144         if (fp->f_type == DTYPE_VNODE)
145             fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0, td);
146     }
147 #ifdef DEBUG
148         if (ldebug(open))
149                 printf(LMSG("open returns error %d"), error);
150 #endif
151     return error;
152 }
153
154 int
155 linux_lseek(struct linux_lseek_args *args)
156 {
157
158     struct lseek_args /* {
159         int fd;
160         int pad;
161         off_t offset;
162         int whence;
163     } */ tmp_args;
164     int error;
165
166 #ifdef DEBUG
167         if (ldebug(lseek))
168                 printf(ARGS(lseek, "%d, %ld, %d"),
169                     args->fdes, (long)args->off, args->whence);
170 #endif
171     tmp_args.fd = args->fdes;
172     tmp_args.offset = (off_t)args->off;
173     tmp_args.whence = args->whence;
174     error = lseek(&tmp_args);
175     return error;
176 }
177
178 #ifndef __alpha__
179 int
180 linux_llseek(struct linux_llseek_args *args)
181 {
182         struct proc *p = curproc;
183         struct lseek_args bsd_args;
184         int error;
185         off_t off;
186
187 #ifdef DEBUG
188         if (ldebug(llseek))
189                 printf(ARGS(llseek, "%d, %d:%d, %d"),
190                     args->fd, args->ohigh, args->olow, args->whence);
191 #endif
192         off = (args->olow) | (((off_t) args->ohigh) << 32);
193
194         bsd_args.fd = args->fd;
195         bsd_args.offset = off;
196         bsd_args.whence = args->whence;
197
198         if ((error = lseek(&bsd_args)))
199                 return error;
200
201         if ((error = copyout(p->p_retval, (caddr_t)args->res, sizeof (off_t))))
202                 return error;
203
204         p->p_retval[0] = 0;
205         return 0;
206 }
207 #endif /*!__alpha__*/
208
209 #ifndef __alpha__
210 int
211 linux_readdir(struct linux_readdir_args *args)
212 {
213         struct linux_getdents_args lda;
214
215         lda.fd = args->fd;
216         lda.dent = args->dent;
217         lda.count = 1;
218         return linux_getdents(&lda);
219 }
220 #endif /*!__alpha__*/
221
222 /*
223  * Note that linux_getdents(2) and linux_getdents64(2) have the same
224  * arguments. They only differ in the definition of struct dirent they
225  * operate on. We use this to common the code, with the exception of
226  * accessing struct dirent. Note that linux_readdir(2) is implemented
227  * by means of linux_getdents(2). In this case we never operate on
228  * struct dirent64 and thus don't need to handle it...
229  */
230
231 struct l_dirent {
232         l_long          d_ino;
233         l_off_t         d_off;
234         l_ushort        d_reclen;
235         char            d_name[LINUX_NAME_MAX + 1];
236 };
237
238 struct l_dirent64 {
239         uint64_t        d_ino;
240         int64_t         d_off;
241         l_ushort        d_reclen;
242         u_char          d_type;
243         char            d_name[LINUX_NAME_MAX + 1];
244 };
245
246 #define LINUX_RECLEN(de,namlen) \
247     ALIGN((((char *)&(de)->d_name - (char *)de) + (namlen) + 1))
248
249 #define LINUX_DIRBLKSIZ         512
250
251 static int
252 getdents_common(struct linux_getdents64_args *args, int is64bit)
253 {
254         struct thread *td = curthread;
255         struct proc *p = td->td_proc;
256         struct dirent *bdp;
257         struct vnode *vp;
258         caddr_t inp, buf;               /* BSD-format */
259         int len, reclen;                /* BSD-format */
260         caddr_t outp;                   /* Linux-format */
261         int resid, linuxreclen=0;       /* Linux-format */
262         struct file *fp;
263         struct uio auio;
264         struct iovec aiov;
265         struct vattr va;
266         off_t off;
267         struct l_dirent linux_dirent;
268         struct l_dirent64 linux_dirent64;
269         int buflen, error, eofflag, nbytes, justone;
270         u_long *cookies = NULL, *cookiep;
271         int ncookies;
272
273         KKASSERT(p);
274
275         if ((error = getvnode(p->p_fd, args->fd, &fp)) != 0)
276                 return (error);
277
278         if ((fp->f_flag & FREAD) == 0)
279                 return (EBADF);
280
281         vp = (struct vnode *) fp->f_data;
282         if (vp->v_type != VDIR)
283                 return (EINVAL);
284
285         if ((error = VOP_GETATTR(vp, &va, p->p_ucred, td)))
286                 return (error);
287
288         nbytes = args->count;
289         if (nbytes == 1) {
290                 /* readdir(2) case. Always struct dirent. */
291                 if (is64bit)
292                         return (EINVAL);
293                 nbytes = sizeof(linux_dirent);
294                 justone = 1;
295         } else
296                 justone = 0;
297
298         off = fp->f_offset;
299
300         buflen = max(LINUX_DIRBLKSIZ, nbytes);
301         buflen = min(buflen, MAXBSIZE);
302         buf = malloc(buflen, M_TEMP, M_WAITOK);
303         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
304
305 again:
306         aiov.iov_base = buf;
307         aiov.iov_len = buflen;
308         auio.uio_iov = &aiov;
309         auio.uio_iovcnt = 1;
310         auio.uio_rw = UIO_READ;
311         auio.uio_segflg = UIO_SYSSPACE;
312         auio.uio_td = td;
313         auio.uio_resid = buflen;
314         auio.uio_offset = off;
315
316         if (cookies) {
317                 free(cookies, M_TEMP);
318                 cookies = NULL;
319         }
320
321         if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies,
322                  &cookies)))
323                 goto out;
324
325         inp = buf;
326         outp = (caddr_t)args->dirent;
327         resid = nbytes;
328         if ((len = buflen - auio.uio_resid) <= 0)
329                 goto eof;
330
331         cookiep = cookies;
332
333         if (cookies) {
334                 /*
335                  * When using cookies, the vfs has the option of reading from
336                  * a different offset than that supplied (UFS truncates the
337                  * offset to a block boundary to make sure that it never reads
338                  * partway through a directory entry, even if the directory
339                  * has been compacted).
340                  */
341                 while (len > 0 && ncookies > 0 && *cookiep <= off) {
342                         bdp = (struct dirent *) inp;
343                         len -= bdp->d_reclen;
344                         inp += bdp->d_reclen;
345                         cookiep++;
346                         ncookies--;
347                 }
348         }
349
350         while (len > 0) {
351                 if (cookiep && ncookies == 0)
352                         break;
353                 bdp = (struct dirent *) inp;
354                 reclen = bdp->d_reclen;
355                 if (reclen & 3) {
356                         error = EFAULT;
357                         goto out;
358                 }
359
360                 if (bdp->d_fileno == 0) {
361                         inp += reclen;
362                         if (cookiep) {
363                                 off = *cookiep++;
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                 if (justone) {
382                         /* readdir(2) case. */
383                         linux_dirent.d_ino = (l_long)bdp->d_fileno;
384                         linux_dirent.d_off = (l_off_t)linuxreclen;
385                         linux_dirent.d_reclen = (l_ushort)bdp->d_namlen;
386                         strcpy(linux_dirent.d_name, bdp->d_name);
387                         error = copyout(&linux_dirent, outp, linuxreclen);
388                 } else {
389                         if (is64bit) {
390                                 linux_dirent64.d_ino = bdp->d_fileno;
391                                 linux_dirent64.d_off = (cookiep)
392                                     ? (l_off_t)*cookiep
393                                     : (l_off_t)(off + reclen);
394                                 linux_dirent64.d_reclen =
395                                     (l_ushort)linuxreclen;
396                                 linux_dirent64.d_type = bdp->d_type;
397                                 strcpy(linux_dirent64.d_name, bdp->d_name);
398                                 error = copyout(&linux_dirent64, outp,
399                                     linuxreclen);
400                         } else {
401                                 linux_dirent.d_ino = bdp->d_fileno;
402                                 linux_dirent.d_off = (cookiep)
403                                     ? (l_off_t)*cookiep
404                                     : (l_off_t)(off + reclen);
405                                 linux_dirent.d_reclen = (l_ushort)linuxreclen;
406                                 strcpy(linux_dirent.d_name, bdp->d_name);
407                                 error = copyout(&linux_dirent, outp,
408                                     linuxreclen);
409                         }
410                 }
411                 if (error)
412                         goto out;
413
414                 inp += reclen;
415                 if (cookiep) {
416                         off = *cookiep++;
417                         ncookies--;
418                 } else
419                         off += reclen;
420
421                 outp += linuxreclen;
422                 resid -= linuxreclen;
423                 len -= reclen;
424                 if (justone)
425                         break;
426         }
427
428         if (outp == (caddr_t)args->dirent)
429                 goto again;
430
431         fp->f_offset = off;
432         if (justone)
433                 nbytes = resid + linuxreclen;
434
435 eof:
436         p->p_retval[0] = nbytes - resid;
437
438 out:
439         if (cookies)
440                 free(cookies, M_TEMP);
441
442         VOP_UNLOCK(vp, 0, td);
443         free(buf, M_TEMP);
444         return (error);
445 }
446
447 int
448 linux_getdents(struct linux_getdents_args *args)
449 {
450 #ifdef DEBUG
451         if (ldebug(getdents))
452                 printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count);
453 #endif
454         return (getdents_common((struct linux_getdents64_args*)args, 0));
455 }
456
457 int
458 linux_getdents64(struct linux_getdents64_args *args)
459 {
460 #ifdef DEBUG
461         if (ldebug(getdents64))
462                 printf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count);
463 #endif
464         return (getdents_common(args, 1));
465 }
466
467 /*
468  * These exist mainly for hooks for doing /compat/linux translation.
469  */
470
471 int
472 linux_access(struct linux_access_args *args)
473 {
474         struct access_args bsd;
475         caddr_t sg;
476
477         sg = stackgap_init();
478         CHECKALTEXIST(&sg, args->path);
479
480 #ifdef DEBUG
481         if (ldebug(access))
482                 printf(ARGS(access, "%s, %d"), args->path, args->flags);
483 #endif
484         bsd.path = args->path;
485         bsd.flags = args->flags;
486
487         return access(&bsd);
488 }
489
490 int
491 linux_unlink(struct linux_unlink_args *args)
492 {
493         struct unlink_args bsd;
494         caddr_t sg;
495
496         sg = stackgap_init();
497         CHECKALTEXIST(&sg, args->path);
498
499 #ifdef DEBUG
500         if (ldebug(unlink))
501                 printf(ARGS(unlink, "%s"), args->path);
502 #endif
503         bsd.path = args->path;
504
505         return unlink(&bsd);
506 }
507
508 int
509 linux_chdir(struct linux_chdir_args *args)
510 {
511         struct chdir_args bsd;
512         caddr_t sg;
513
514         sg = stackgap_init();
515         CHECKALTEXIST(&sg, args->path);
516
517 #ifdef DEBUG
518         if (ldebug(chdir))
519                 printf(ARGS(chdir, "%s"), args->path);
520 #endif
521         bsd.path = args->path;
522
523         return chdir(&bsd);
524 }
525
526 int
527 linux_chmod(struct linux_chmod_args *args)
528 {
529         struct chmod_args bsd;
530         caddr_t sg;
531
532         sg = stackgap_init();
533         CHECKALTEXIST(&sg, args->path);
534
535 #ifdef DEBUG
536         if (ldebug(chmod))
537                 printf(ARGS(chmod, "%s, %d"), args->path, args->mode);
538 #endif
539         bsd.path = args->path;
540         bsd.mode = args->mode;
541
542         return chmod(&bsd);
543 }
544
545 int
546 linux_mkdir(struct linux_mkdir_args *args)
547 {
548         struct mkdir_args bsd;
549         caddr_t sg;
550
551         sg = stackgap_init();
552         CHECKALTCREAT(&sg, args->path);
553
554 #ifdef DEBUG
555         if (ldebug(mkdir))
556                 printf(ARGS(mkdir, "%s, %d"), args->path, args->mode);
557 #endif
558         bsd.path = args->path;
559         bsd.mode = args->mode;
560
561         return mkdir(&bsd);
562 }
563
564 int
565 linux_rmdir(struct linux_rmdir_args *args)
566 {
567         struct rmdir_args bsd;
568         caddr_t sg;
569
570         sg = stackgap_init();
571         CHECKALTEXIST(&sg, args->path);
572
573 #ifdef DEBUG
574         if (ldebug(rmdir))
575                 printf(ARGS(rmdir, "%s"), args->path);
576 #endif
577         bsd.path = args->path;
578
579         return rmdir(&bsd);
580 }
581
582 int
583 linux_rename(struct linux_rename_args *args)
584 {
585         struct rename_args bsd;
586         caddr_t sg;
587
588         sg = stackgap_init();
589         CHECKALTEXIST(&sg, args->from);
590         CHECKALTCREAT(&sg, args->to);
591
592 #ifdef DEBUG
593         if (ldebug(rename))
594                 printf(ARGS(rename, "%s, %s"), args->from, args->to);
595 #endif
596         bsd.from = args->from;
597         bsd.to = args->to;
598
599         return rename(&bsd);
600 }
601
602 int
603 linux_symlink(struct linux_symlink_args *args)
604 {
605         struct symlink_args bsd;
606         caddr_t sg;
607
608         sg = stackgap_init();
609         CHECKALTEXIST(&sg, args->path);
610         CHECKALTCREAT(&sg, args->to);
611
612 #ifdef DEBUG
613         if (ldebug(symlink))
614                 printf(ARGS(symlink, "%s, %s"), args->path, args->to);
615 #endif
616         bsd.path = args->path;
617         bsd.link = args->to;
618
619         return symlink(&bsd);
620 }
621
622 int
623 linux_readlink(struct linux_readlink_args *args)
624 {
625         struct readlink_args bsd;
626         caddr_t sg;
627
628         sg = stackgap_init();
629         CHECKALTEXIST(&sg, args->name);
630
631 #ifdef DEBUG
632         if (ldebug(readlink))
633                 printf(ARGS(readlink, "%s, %p, %d"),
634                     args->name, (void *)args->buf, args->count);
635 #endif
636         bsd.path = args->name;
637         bsd.buf = args->buf;
638         bsd.count = args->count;
639
640         return readlink(&bsd);
641 }
642
643 int
644 linux_truncate(struct linux_truncate_args *args)
645 {
646         struct truncate_args bsd;
647         caddr_t sg;
648
649         sg = stackgap_init();
650         CHECKALTEXIST(&sg, args->path);
651
652 #ifdef DEBUG
653         if (ldebug(truncate))
654                 printf(ARGS(truncate, "%s, %ld"), args->path,
655                     (long)args->length);
656 #endif
657         bsd.path = args->path;
658         bsd.length = args->length;
659
660         return truncate(&bsd);
661 }
662
663 int
664 linux_link(struct linux_link_args *args)
665 {
666     struct link_args bsd;
667     caddr_t sg;
668
669     sg = stackgap_init();
670     CHECKALTEXIST(&sg, args->path);
671     CHECKALTCREAT(&sg, args->to);
672
673 #ifdef DEBUG
674         if (ldebug(link))
675                 printf(ARGS(link, "%s, %s"), args->path, args->to);
676 #endif
677
678     bsd.path = args->path;
679     bsd.link = args->to;
680
681     return link(&bsd);
682 }
683
684 #ifndef __alpha__
685 int
686 linux_fdatasync(struct linux_fdatasync_args *uap)
687 {
688         struct fsync_args bsd;
689
690         bsd.fd = uap->fd;
691         return fsync(&bsd);
692 }
693 #endif /*!__alpha__*/
694
695 int
696 linux_pread(struct linux_pread_args *uap)
697 {
698         struct pread_args bsd;
699
700         bsd.fd = uap->fd;
701         bsd.buf = uap->buf;
702         bsd.nbyte = uap->nbyte;
703         bsd.offset = uap->offset;
704         return pread(&bsd);
705 }
706
707 int
708 linux_pwrite(struct linux_pwrite_args *uap)
709 {
710         struct pwrite_args bsd;
711
712         bsd.fd = uap->fd;
713         bsd.buf = uap->buf;
714         bsd.nbyte = uap->nbyte;
715         bsd.offset = uap->offset;
716         return pwrite(&bsd);
717 }
718
719 int
720 linux_oldumount(struct linux_oldumount_args *args)
721 {
722         struct linux_umount_args args2;
723
724         args2.path = args->path;
725         args2.flags = 0;
726         return (linux_umount(&args2));
727 }
728
729 int
730 linux_umount(struct linux_umount_args *args)
731 {
732         struct unmount_args bsd;
733
734         bsd.path = args->path;
735         bsd.flags = args->flags;        /* XXX correct? */
736         return (unmount(&bsd));
737 }
738
739 /*
740  * fcntl family of syscalls
741  */
742
743 struct l_flock {
744         l_short         l_type;
745         l_short         l_whence;
746         l_off_t         l_start;
747         l_off_t         l_len;
748         l_pid_t         l_pid;
749 };
750
751 static void
752 linux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock)
753 {
754         switch (linux_flock->l_type) {
755         case LINUX_F_RDLCK:
756                 bsd_flock->l_type = F_RDLCK;
757                 break;
758         case LINUX_F_WRLCK:
759                 bsd_flock->l_type = F_WRLCK;
760                 break;
761         case LINUX_F_UNLCK:
762                 bsd_flock->l_type = F_UNLCK;
763                 break;
764         default:
765                 bsd_flock->l_type = -1;
766                 break;
767         }
768         bsd_flock->l_whence = linux_flock->l_whence;
769         bsd_flock->l_start = (off_t)linux_flock->l_start;
770         bsd_flock->l_len = (off_t)linux_flock->l_len;
771         bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
772 }
773
774 static void
775 bsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock)
776 {
777         switch (bsd_flock->l_type) {
778         case F_RDLCK:
779                 linux_flock->l_type = LINUX_F_RDLCK;
780                 break;
781         case F_WRLCK:
782                 linux_flock->l_type = LINUX_F_WRLCK;
783                 break;
784         case F_UNLCK:
785                 linux_flock->l_type = LINUX_F_UNLCK;
786                 break;
787         }
788         linux_flock->l_whence = bsd_flock->l_whence;
789         linux_flock->l_start = (l_off_t)bsd_flock->l_start;
790         linux_flock->l_len = (l_off_t)bsd_flock->l_len;
791         linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
792 }
793
794 #if defined(__i386__)
795 struct l_flock64 {
796         l_short         l_type;
797         l_short         l_whence;
798         l_loff_t        l_start;
799         l_loff_t        l_len;
800         l_pid_t         l_pid;
801 };
802
803 static void
804 linux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock)
805 {
806         switch (linux_flock->l_type) {
807         case LINUX_F_RDLCK:
808                 bsd_flock->l_type = F_RDLCK;
809                 break;
810         case LINUX_F_WRLCK:
811                 bsd_flock->l_type = F_WRLCK;
812                 break;
813         case LINUX_F_UNLCK:
814                 bsd_flock->l_type = F_UNLCK;
815                 break;
816         default:
817                 bsd_flock->l_type = -1;
818                 break;
819         }
820         bsd_flock->l_whence = linux_flock->l_whence;
821         bsd_flock->l_start = (off_t)linux_flock->l_start;
822         bsd_flock->l_len = (off_t)linux_flock->l_len;
823         bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
824 }
825
826 static void
827 bsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock)
828 {
829         switch (bsd_flock->l_type) {
830         case F_RDLCK:
831                 linux_flock->l_type = LINUX_F_RDLCK;
832                 break;
833         case F_WRLCK:
834                 linux_flock->l_type = LINUX_F_WRLCK;
835                 break;
836         case F_UNLCK:
837                 linux_flock->l_type = LINUX_F_UNLCK;
838                 break;
839         }
840         linux_flock->l_whence = bsd_flock->l_whence;
841         linux_flock->l_start = (l_loff_t)bsd_flock->l_start;
842         linux_flock->l_len = (l_loff_t)bsd_flock->l_len;
843         linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
844 }
845 #endif /* __i386__ */
846
847 #if defined(__alpha__)
848 #define linux_fcntl64_args      linux_fcntl_args
849 #endif
850
851 static int
852 fcntl_common(struct linux_fcntl64_args *args)
853 {
854         struct proc *p = curproc;
855         struct l_flock linux_flock;
856         struct flock *bsd_flock;
857         struct fcntl_args fcntl_args;
858         struct filedesc *fdp;
859         struct file *fp;
860         int error, result;
861         caddr_t sg;
862
863         sg = stackgap_init();
864         bsd_flock = (struct flock *)stackgap_alloc(&sg, sizeof(bsd_flock));
865
866         fcntl_args.fd = args->fd;
867
868         switch (args->cmd) {
869         case LINUX_F_DUPFD:
870                 fcntl_args.cmd = F_DUPFD;
871                 fcntl_args.arg = args->arg;
872                 return (fcntl(&fcntl_args));
873
874         case LINUX_F_GETFD:
875                 fcntl_args.cmd = F_GETFD;
876                 return (fcntl(&fcntl_args));
877
878         case LINUX_F_SETFD:
879                 fcntl_args.cmd = F_SETFD;
880                 fcntl_args.arg = args->arg;
881                 return (fcntl(&fcntl_args));
882
883         case LINUX_F_GETFL:
884                 fcntl_args.cmd = F_GETFL;
885                 error = fcntl(&fcntl_args);
886                 result = p->p_retval[0];
887                 p->p_retval[0] = 0;
888                 if (result & O_RDONLY)
889                         p->p_retval[0] |= LINUX_O_RDONLY;
890                 if (result & O_WRONLY)
891                         p->p_retval[0] |= LINUX_O_WRONLY;
892                 if (result & O_RDWR)
893                         p->p_retval[0] |= LINUX_O_RDWR;
894                 if (result & O_NDELAY)
895                         p->p_retval[0] |= LINUX_O_NONBLOCK;
896                 if (result & O_APPEND)
897                         p->p_retval[0] |= LINUX_O_APPEND;
898                 if (result & O_FSYNC)
899                         p->p_retval[0] |= LINUX_O_SYNC;
900                 if (result & O_ASYNC)
901                         p->p_retval[0] |= LINUX_FASYNC;
902                 return (error);
903
904         case LINUX_F_SETFL:
905                 fcntl_args.arg = 0;
906                 if (args->arg & LINUX_O_NDELAY)
907                         fcntl_args.arg |= O_NONBLOCK;
908                 if (args->arg & LINUX_O_APPEND)
909                         fcntl_args.arg |= O_APPEND;
910                 if (args->arg & LINUX_O_SYNC)
911                         fcntl_args.arg |= O_FSYNC;
912                 if (args->arg & LINUX_FASYNC)
913                         fcntl_args.arg |= O_ASYNC;
914                 fcntl_args.cmd = F_SETFL;
915                 return (fcntl(&fcntl_args));
916
917         case LINUX_F_GETLK:
918                 error = copyin((caddr_t)args->arg, &linux_flock,
919                     sizeof(linux_flock));
920                 if (error)
921                         return (error);
922                 linux_to_bsd_flock(&linux_flock, bsd_flock);
923                 fcntl_args.fd = args->fd;
924                 fcntl_args.cmd = F_GETLK;
925                 fcntl_args.arg = (long)bsd_flock;
926                 error = fcntl(&fcntl_args);
927                 if (error)
928                         return (error);
929                 bsd_to_linux_flock(bsd_flock, &linux_flock);
930                 return (copyout(&linux_flock, (caddr_t)args->arg,
931                     sizeof(linux_flock)));
932
933         case LINUX_F_SETLK:
934                 error = copyin((caddr_t)args->arg, &linux_flock,
935                     sizeof(linux_flock));
936                 if (error)
937                         return (error);
938                 linux_to_bsd_flock(&linux_flock, bsd_flock);
939                 fcntl_args.fd = args->fd;
940                 fcntl_args.cmd = F_SETLK;
941                 fcntl_args.arg = (long)bsd_flock;
942                 return (fcntl(&fcntl_args));
943
944         case LINUX_F_SETLKW:
945                 error = copyin((caddr_t)args->arg, &linux_flock,
946                     sizeof(linux_flock));
947                 if (error)
948                         return (error);
949                 linux_to_bsd_flock(&linux_flock, bsd_flock);
950                 fcntl_args.fd = args->fd;
951                 fcntl_args.cmd = F_SETLKW;
952                 fcntl_args.arg = (long)bsd_flock;
953                 return (fcntl(&fcntl_args));
954
955         case LINUX_F_GETOWN:
956                 fcntl_args.cmd = F_GETOWN;
957                 return (fcntl(&fcntl_args));
958
959         case LINUX_F_SETOWN:
960                 /*
961                  * XXX some Linux applications depend on F_SETOWN having no
962                  * significant effect for pipes (SIGIO is not delivered for
963                  * pipes under Linux-2.2.35 at least).
964                  */
965                 fdp = p->p_fd;
966                 if ((u_int)args->fd >= fdp->fd_nfiles ||
967                     (fp = fdp->fd_ofiles[args->fd]) == NULL)
968                         return (EBADF);
969                 if (fp->f_type == DTYPE_PIPE)
970                         return (EINVAL);
971
972                 fcntl_args.cmd = F_SETOWN;
973                 fcntl_args.arg = args->arg;
974                 return (fcntl(&fcntl_args));
975         }
976
977         return (EINVAL);
978 }
979
980 int
981 linux_fcntl(struct linux_fcntl_args *args)
982 {
983         struct linux_fcntl64_args args64;
984
985 #ifdef DEBUG
986         if (ldebug(fcntl))
987                 printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd);
988 #endif
989
990         args64.fd = args->fd;
991         args64.cmd = args->cmd;
992         args64.arg = args->arg;
993         return (fcntl_common(&args64));
994 }
995
996 #if defined(__i386__)
997 int
998 linux_fcntl64(struct linux_fcntl64_args *args)
999 {
1000         struct fcntl_args fcntl_args;
1001         struct l_flock64 linux_flock;
1002         struct flock *bsd_flock;
1003         int error;
1004         caddr_t sg;
1005
1006         sg = stackgap_init();
1007         bsd_flock = (struct flock *)stackgap_alloc(&sg, sizeof(bsd_flock));
1008
1009 #ifdef DEBUG
1010         if (ldebug(fcntl64))
1011                 printf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd);
1012 #endif
1013
1014         switch (args->cmd) {
1015         case LINUX_F_GETLK64:
1016                 error = copyin((caddr_t)args->arg, &linux_flock,
1017                     sizeof(linux_flock));
1018                 if (error)
1019                         return (error);
1020                 linux_to_bsd_flock64(&linux_flock, bsd_flock);
1021                 fcntl_args.fd = args->fd;
1022                 fcntl_args.cmd = F_GETLK;
1023                 fcntl_args.arg = (long)bsd_flock;
1024                 error = fcntl(&fcntl_args);
1025                 if (error)
1026                         return (error);
1027                 bsd_to_linux_flock64(bsd_flock, &linux_flock);
1028                 return (copyout(&linux_flock, (caddr_t)args->arg,
1029                     sizeof(linux_flock)));
1030
1031         case LINUX_F_SETLK64:
1032                 error = copyin((caddr_t)args->arg, &linux_flock,
1033                     sizeof(linux_flock));
1034                 if (error)
1035                         return (error);
1036                 linux_to_bsd_flock64(&linux_flock, bsd_flock);
1037                 fcntl_args.fd = args->fd;
1038                 fcntl_args.cmd = F_SETLK;
1039                 fcntl_args.arg = (long)bsd_flock;
1040                 return (fcntl(&fcntl_args));
1041
1042         case LINUX_F_SETLKW64:
1043                 error = copyin((caddr_t)args->arg, &linux_flock,
1044                     sizeof(linux_flock));
1045                 if (error)
1046                         return (error);
1047                 linux_to_bsd_flock64(&linux_flock, bsd_flock);
1048                 fcntl_args.fd = args->fd;
1049                 fcntl_args.cmd = F_SETLKW;
1050                 fcntl_args.arg = (long)bsd_flock;
1051                 return (fcntl(&fcntl_args));
1052         }
1053
1054         return (fcntl_common(args));
1055 }
1056 #endif /* __i386__ */
1057
1058 int
1059 linux_chown(struct linux_chown_args *args)
1060 {
1061         struct chown_args bsd;
1062         caddr_t sg;
1063
1064         sg = stackgap_init();
1065         CHECKALTEXIST(&sg, args->path);
1066
1067 #ifdef DEBUG
1068         if (ldebug(chown))
1069                 printf(ARGS(chown, "%s, %d, %d"), args->path, args->uid,
1070                     args->gid);
1071 #endif
1072
1073         bsd.path = args->path;
1074         bsd.uid = args->uid;
1075         bsd.gid = args->gid;
1076         return (chown(&bsd));
1077 }
1078
1079 int
1080 linux_lchown(struct linux_lchown_args *args)
1081 {
1082         struct lchown_args bsd;
1083         caddr_t sg;
1084
1085         sg = stackgap_init();
1086         CHECKALTEXIST(&sg, args->path);
1087
1088 #ifdef DEBUG
1089         if (ldebug(lchown))
1090                 printf(ARGS(lchown, "%s, %d, %d"), args->path, args->uid,
1091                     args->gid);
1092 #endif
1093
1094         bsd.path = args->path;
1095         bsd.uid = args->uid;
1096         bsd.gid = args->gid;
1097         return (lchown(&bsd));
1098 }