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