]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/compat/linux/linux_file.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / compat / 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 without 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
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include "opt_compat.h"
33 #include "opt_mac.h"
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/conf.h>
38 #include <sys/dirent.h>
39 #include <sys/fcntl.h>
40 #include <sys/file.h>
41 #include <sys/filedesc.h>
42 #include <sys/lock.h>
43 #include <sys/malloc.h>
44 #include <sys/mount.h>
45 #include <sys/mutex.h>
46 #include <sys/namei.h>
47 #include <sys/proc.h>
48 #include <sys/stat.h>
49 #include <sys/sx.h>
50 #include <sys/syscallsubr.h>
51 #include <sys/sysproto.h>
52 #include <sys/tty.h>
53 #include <sys/unistd.h>
54 #include <sys/vnode.h>
55
56 #include <security/mac/mac_framework.h>
57
58 #include <ufs/ufs/extattr.h>
59 #include <ufs/ufs/quota.h>
60 #include <ufs/ufs/ufsmount.h>
61
62 #ifdef COMPAT_LINUX32
63 #include <machine/../linux32/linux.h>
64 #include <machine/../linux32/linux32_proto.h>
65 #else
66 #include <machine/../linux/linux.h>
67 #include <machine/../linux/linux_proto.h>
68 #endif
69 #include <compat/linux/linux_util.h>
70
71 int
72 linux_creat(struct thread *td, struct linux_creat_args *args)
73 {
74     char *path;
75     int error;
76
77     LCONVPATHEXIST(td, args->path, &path);
78
79 #ifdef DEBUG
80         if (ldebug(creat))
81                 printf(ARGS(creat, "%s, %d"), path, args->mode);
82 #endif
83     error = kern_open(td, path, UIO_SYSSPACE, O_WRONLY | O_CREAT | O_TRUNC,
84         args->mode);
85     LFREEPATH(path);
86     return (error);
87 }
88
89
90 static int
91 linux_common_open(struct thread *td, char *path, int l_flags, int mode, int openat)
92 {
93     struct proc *p = td->td_proc;
94     struct file *fp;
95     int fd;
96     int bsd_flags, error;
97
98     bsd_flags = 0;
99     switch (l_flags & LINUX_O_ACCMODE) {
100     case LINUX_O_WRONLY:
101         bsd_flags |= O_WRONLY;
102         break;
103     case LINUX_O_RDWR:
104         bsd_flags |= O_RDWR;
105         break;
106     default:
107         bsd_flags |= O_RDONLY;
108     }
109     if (l_flags & LINUX_O_NDELAY)
110         bsd_flags |= O_NONBLOCK;
111     if (l_flags & LINUX_O_APPEND)
112         bsd_flags |= O_APPEND;
113     if (l_flags & LINUX_O_SYNC)
114         bsd_flags |= O_FSYNC;
115     if (l_flags & LINUX_O_NONBLOCK)
116         bsd_flags |= O_NONBLOCK;
117     if (l_flags & LINUX_FASYNC)
118         bsd_flags |= O_ASYNC;
119     if (l_flags & LINUX_O_CREAT)
120         bsd_flags |= O_CREAT;
121     if (l_flags & LINUX_O_TRUNC)
122         bsd_flags |= O_TRUNC;
123     if (l_flags & LINUX_O_EXCL)
124         bsd_flags |= O_EXCL;
125     if (l_flags & LINUX_O_NOCTTY)
126         bsd_flags |= O_NOCTTY;
127     if (l_flags & LINUX_O_DIRECT)
128         bsd_flags |= O_DIRECT;
129     if (l_flags & LINUX_O_NOFOLLOW)
130         bsd_flags |= O_NOFOLLOW;
131     /* XXX LINUX_O_NOATIME: unable to be easily implemented. */
132
133     error = kern_open(td, path, UIO_SYSSPACE, bsd_flags, mode);
134     if (!error) {
135             fd = td->td_retval[0];
136             /*
137              * XXX In between kern_open() and fget(), another process
138              * having the same filedesc could use that fd without
139              * checking below.
140              */
141             error = fget(td, fd, &fp);
142             if (!error) {
143                     sx_slock(&proctree_lock);
144                     PROC_LOCK(p);
145                     if (!(bsd_flags & O_NOCTTY) &&
146                         SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
147                             PROC_UNLOCK(p);
148                             sx_unlock(&proctree_lock);
149                             if (fp->f_type == DTYPE_VNODE)
150                                     (void) fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0,
151                                              td->td_ucred, td);
152                     } else {
153                             PROC_UNLOCK(p);
154                             sx_sunlock(&proctree_lock);
155                     }
156                     if (l_flags & LINUX_O_DIRECTORY) {
157                             if (fp->f_type != DTYPE_VNODE ||
158                                 fp->f_vnode->v_type != VDIR) {
159                                     error = ENOTDIR;
160                             }
161                     }
162                     fdrop(fp, td);
163                     /*
164                      * XXX as above, fdrop()/kern_close() pair is racy.
165                      */
166                     if (error)
167                             kern_close(td, fd);
168             }
169     }
170
171 #ifdef DEBUG
172     if (ldebug(open))
173             printf(LMSG("open returns error %d"), error);
174 #endif
175     if (!openat)
176         LFREEPATH(path);
177     return error;
178 }
179
180 /*
181  * common code for linux *at set of syscalls
182  *
183  * works like this:
184  * if filename is absolute 
185  *    ignore dirfd
186  * else
187  *    if dirfd == AT_FDCWD 
188  *       return CWD/filename
189  *    else
190  *       return DIRFD/filename
191  */
192 static int
193 linux_at(struct thread *td, int dirfd, char *filename, char **newpath, char **freebuf)
194 {
195         struct file *fp;
196         int error = 0, vfslocked;
197         struct vnode *dvp;
198         struct filedesc *fdp = td->td_proc->p_fd;
199         char *fullpath = "unknown";
200         char *freepath = NULL;
201
202         /* don't do anything if the pathname is absolute */
203         if (*filename == '/') {
204                 *newpath= filename;
205                 return (0);
206         }
207
208         /* check for AT_FDWCD */
209         if (dirfd == LINUX_AT_FDCWD) {
210                 FILEDESC_SLOCK(fdp);
211                 dvp = fdp->fd_cdir;
212                 vref(dvp);
213                 FILEDESC_SUNLOCK(fdp);
214         } else {
215                 error = fget(td, dirfd, &fp);
216                 if (error)
217                         return (error);
218                 dvp = fp->f_vnode;
219                 /* only a dir can be dfd */
220                 if (dvp->v_type != VDIR) {
221                         fdrop(fp, td);
222                         return (ENOTDIR);
223                 }
224                 vref(dvp);
225                 fdrop(fp, td);
226         }
227
228         /*
229          * XXXRW: This is bogus, as vn_fullpath() returns only an advisory
230          * file path, and may fail in several common situations, including
231          * for file systmes that don't use the name cache, and if the entry
232          * for the file falls out of the name cache.  We should implement
233          * openat() in the FreeBSD native system call layer properly (using a
234          * requested starting directory), and have Linux and other ABIs wrap
235          * the native implementation.
236          */
237         error = vn_fullpath(td, dvp, &fullpath, &freepath);
238         if (!error) {
239                 *newpath = malloc(strlen(fullpath) + strlen(filename) + 2, M_TEMP, M_WAITOK | M_ZERO);
240                 *freebuf = freepath;
241                 sprintf(*newpath, "%s/%s", fullpath, filename);
242         } else {
243                 *newpath = NULL;
244         }
245         vfslocked = VFS_LOCK_GIANT(dvp->v_mount);
246         vrele(dvp);
247         VFS_UNLOCK_GIANT(vfslocked);
248         return (error);
249 }
250
251 int
252 linux_openat(struct thread *td, struct linux_openat_args *args)
253 {
254         char *newpath, *oldpath, *freebuf, *path;
255         int error;
256
257         oldpath = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
258         error = copyinstr(args->filename, oldpath, MAXPATHLEN, NULL);
259         if (error) {
260                 free(oldpath, M_TEMP);
261                 return (error);
262         }
263 #ifdef DEBUG
264         if (ldebug(openat))
265                 printf(ARGS(openat, "%i, %s, 0x%x, 0x%x"), args->dfd,
266                     oldpath, args->flags, args->mode);
267 #endif
268         newpath = freebuf = NULL;
269         error = linux_at(td, args->dfd, oldpath, &newpath, &freebuf);
270         if (error == 0) {
271 #ifdef DEBUG
272                 if (ldebug(openat))
273                         printf(LMSG("newpath: %s"), newpath);
274 #endif
275                 if (args->flags & LINUX_O_CREAT)
276                         LCONVPATH_SEG(td, newpath, &path, 1, UIO_SYSSPACE);
277                 else
278                         LCONVPATH_SEG(td, newpath, &path, 0, UIO_SYSSPACE);
279         }
280         if (freebuf)
281                 free(freebuf, M_TEMP);
282         if (*oldpath != '/')
283                 free(newpath, M_TEMP);
284         if (error == 0) {
285                 error = linux_common_open(td, path, args->flags,
286                     args->mode, 1);
287                 LFREEPATH(path);
288         }
289         free(oldpath, M_TEMP);
290         return (error);
291 }
292
293 int
294 linux_open(struct thread *td, struct linux_open_args *args)
295 {
296     char *path;
297
298     if (args->flags & LINUX_O_CREAT)
299         LCONVPATHCREAT(td, args->path, &path);
300     else
301         LCONVPATHEXIST(td, args->path, &path);
302
303 #ifdef DEBUG
304         if (ldebug(open))
305                 printf(ARGS(open, "%s, 0x%x, 0x%x"),
306                     path, args->flags, args->mode);
307 #endif
308
309     return linux_common_open(td, path, args->flags, args->mode, 0);
310 }
311
312 int
313 linux_lseek(struct thread *td, struct linux_lseek_args *args)
314 {
315
316     struct lseek_args /* {
317         int fd;
318         int pad;
319         off_t offset;
320         int whence;
321     } */ tmp_args;
322     int error;
323
324 #ifdef DEBUG
325         if (ldebug(lseek))
326                 printf(ARGS(lseek, "%d, %ld, %d"),
327                     args->fdes, (long)args->off, args->whence);
328 #endif
329     tmp_args.fd = args->fdes;
330     tmp_args.offset = (off_t)args->off;
331     tmp_args.whence = args->whence;
332     error = lseek(td, &tmp_args);
333     return error;
334 }
335
336 int
337 linux_llseek(struct thread *td, struct linux_llseek_args *args)
338 {
339         struct lseek_args bsd_args;
340         int error;
341         off_t off;
342
343 #ifdef DEBUG
344         if (ldebug(llseek))
345                 printf(ARGS(llseek, "%d, %d:%d, %d"),
346                     args->fd, args->ohigh, args->olow, args->whence);
347 #endif
348         off = (args->olow) | (((off_t) args->ohigh) << 32);
349
350         bsd_args.fd = args->fd;
351         bsd_args.offset = off;
352         bsd_args.whence = args->whence;
353
354         if ((error = lseek(td, &bsd_args)))
355                 return error;
356
357         if ((error = copyout(td->td_retval, args->res, sizeof (off_t))))
358                 return error;
359
360         td->td_retval[0] = 0;
361         return 0;
362 }
363
364 int
365 linux_readdir(struct thread *td, struct linux_readdir_args *args)
366 {
367         struct linux_getdents_args lda;
368
369         lda.fd = args->fd;
370         lda.dent = args->dent;
371         lda.count = 1;
372         return linux_getdents(td, &lda);
373 }
374
375 /*
376  * Note that linux_getdents(2) and linux_getdents64(2) have the same
377  * arguments. They only differ in the definition of struct dirent they
378  * operate on. We use this to common the code, with the exception of
379  * accessing struct dirent. Note that linux_readdir(2) is implemented
380  * by means of linux_getdents(2). In this case we never operate on
381  * struct dirent64 and thus don't need to handle it...
382  */
383
384 struct l_dirent {
385         l_long          d_ino;
386         l_off_t         d_off;
387         l_ushort        d_reclen;
388         char            d_name[LINUX_NAME_MAX + 1];
389 };
390
391 struct l_dirent64 {
392         uint64_t        d_ino;
393         int64_t         d_off;
394         l_ushort        d_reclen;
395         u_char          d_type;
396         char            d_name[LINUX_NAME_MAX + 1];
397 };
398
399 /*
400  * Linux uses the last byte in the dirent buffer to store d_type,
401  * at least glibc-2.7 requires it. That is why l_dirent is padded with 2 bytes.
402  */
403 #define LINUX_RECLEN(namlen)                                            \
404     roundup((offsetof(struct l_dirent, d_name) + (namlen) + 2),         \
405     sizeof(l_ulong))
406
407 #define LINUX_RECLEN64(namlen)                                          \
408     roundup((offsetof(struct l_dirent64, d_name) + (namlen) + 1),       \
409     sizeof(uint64_t))
410
411 #define LINUX_MAXRECLEN         max(LINUX_RECLEN(LINUX_NAME_MAX),       \
412                                     LINUX_RECLEN64(LINUX_NAME_MAX))
413 #define LINUX_DIRBLKSIZ         512
414
415 static int
416 getdents_common(struct thread *td, struct linux_getdents64_args *args,
417     int is64bit)
418 {
419         struct dirent *bdp;
420         struct vnode *vp;
421         caddr_t inp, buf;               /* BSD-format */
422         int len, reclen;                /* BSD-format */
423         caddr_t outp;                   /* Linux-format */
424         int resid, linuxreclen=0;       /* Linux-format */
425         caddr_t lbuf;                   /* Linux-format */
426         struct file *fp;
427         struct uio auio;
428         struct iovec aiov;
429         off_t off;
430         struct l_dirent *linux_dirent;
431         struct l_dirent64 *linux_dirent64;
432         int buflen, error, eofflag, nbytes, justone;
433         u_long *cookies = NULL, *cookiep;
434         int ncookies, vfslocked;
435
436         nbytes = args->count;
437         if (nbytes == 1) {
438                 /* readdir(2) case. Always struct dirent. */
439                 if (is64bit)
440                         return (EINVAL);
441                 nbytes = sizeof(*linux_dirent);
442                 justone = 1;
443         } else
444                 justone = 0;
445
446         if ((error = getvnode(td->td_proc->p_fd, args->fd, &fp)) != 0)
447                 return (error);
448
449         if ((fp->f_flag & FREAD) == 0) {
450                 fdrop(fp, td);
451                 return (EBADF);
452         }
453
454         vp = fp->f_vnode;
455         vfslocked = VFS_LOCK_GIANT(vp->v_mount);
456         if (vp->v_type != VDIR) {
457                 VFS_UNLOCK_GIANT(vfslocked);
458                 fdrop(fp, td);
459                 return (EINVAL);
460         }
461
462         off = fp->f_offset;
463
464         buflen = max(LINUX_DIRBLKSIZ, nbytes);
465         buflen = min(buflen, MAXBSIZE);
466         buf = malloc(buflen, M_TEMP, M_WAITOK);
467         lbuf = malloc(LINUX_MAXRECLEN, M_TEMP, M_WAITOK | M_ZERO);
468         vn_lock(vp, LK_SHARED | LK_RETRY, td);
469
470 again:
471         aiov.iov_base = buf;
472         aiov.iov_len = buflen;
473         auio.uio_iov = &aiov;
474         auio.uio_iovcnt = 1;
475         auio.uio_rw = UIO_READ;
476         auio.uio_segflg = UIO_SYSSPACE;
477         auio.uio_td = td;
478         auio.uio_resid = buflen;
479         auio.uio_offset = off;
480
481         if (cookies) {
482                 free(cookies, M_TEMP);
483                 cookies = NULL;
484         }
485
486 #ifdef MAC
487         /*
488          * Do directory search MAC check using non-cached credentials.
489          */
490         if ((error = mac_check_vnode_readdir(td->td_ucred, vp)))
491                 goto out;
492 #endif /* MAC */
493         if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies,
494                  &cookies)))
495                 goto out;
496
497         inp = buf;
498         outp = (caddr_t)args->dirent;
499         resid = nbytes;
500         if ((len = buflen - auio.uio_resid) <= 0)
501                 goto eof;
502
503         cookiep = cookies;
504
505         if (cookies) {
506                 /*
507                  * When using cookies, the vfs has the option of reading from
508                  * a different offset than that supplied (UFS truncates the
509                  * offset to a block boundary to make sure that it never reads
510                  * partway through a directory entry, even if the directory
511                  * has been compacted).
512                  */
513                 while (len > 0 && ncookies > 0 && *cookiep <= off) {
514                         bdp = (struct dirent *) inp;
515                         len -= bdp->d_reclen;
516                         inp += bdp->d_reclen;
517                         cookiep++;
518                         ncookies--;
519                 }
520         }
521
522         while (len > 0) {
523                 if (cookiep && ncookies == 0)
524                         break;
525                 bdp = (struct dirent *) inp;
526                 reclen = bdp->d_reclen;
527                 if (reclen & 3) {
528                         error = EFAULT;
529                         goto out;
530                 }
531
532                 if (bdp->d_fileno == 0) {
533                         inp += reclen;
534                         if (cookiep) {
535                                 off = *cookiep++;
536                                 ncookies--;
537                         } else
538                                 off += reclen;
539
540                         len -= reclen;
541                         continue;
542                 }
543
544                 linuxreclen = (is64bit)
545                     ? LINUX_RECLEN64(bdp->d_namlen)
546                     : LINUX_RECLEN(bdp->d_namlen);
547
548                 if (reclen > len || resid < linuxreclen) {
549                         outp++;
550                         break;
551                 }
552
553                 if (justone) {
554                         /* readdir(2) case. */
555                         linux_dirent = (struct l_dirent*)lbuf;
556                         linux_dirent->d_ino = bdp->d_fileno;
557                         linux_dirent->d_off = (l_off_t)linuxreclen;
558                         linux_dirent->d_reclen = (l_ushort)bdp->d_namlen;
559                         strlcpy(linux_dirent->d_name, bdp->d_name,
560                             linuxreclen - offsetof(struct l_dirent, d_name));
561                         error = copyout(linux_dirent, outp, linuxreclen);
562                 }
563                 if (is64bit) {
564                         linux_dirent64 = (struct l_dirent64*)lbuf;
565                         linux_dirent64->d_ino = bdp->d_fileno;
566                         linux_dirent64->d_off = (cookiep)
567                             ? (l_off_t)*cookiep
568                             : (l_off_t)(off + reclen);
569                         linux_dirent64->d_reclen = (l_ushort)linuxreclen;
570                         linux_dirent64->d_type = bdp->d_type;
571                         strlcpy(linux_dirent64->d_name, bdp->d_name,
572                             linuxreclen - offsetof(struct l_dirent64, d_name));
573                         error = copyout(linux_dirent64, outp, linuxreclen);
574                 } else if (!justone) {
575                         linux_dirent = (struct l_dirent*)lbuf;
576                         linux_dirent->d_ino = bdp->d_fileno;
577                         linux_dirent->d_off = (cookiep)
578                             ? (l_off_t)*cookiep
579                             : (l_off_t)(off + reclen);
580                         linux_dirent->d_reclen = (l_ushort)linuxreclen;
581                         /*
582                          * Copy d_type to last byte of l_dirent buffer
583                          */
584                         lbuf[linuxreclen-1] = bdp->d_type;
585                         strlcpy(linux_dirent->d_name, bdp->d_name,
586                             linuxreclen - offsetof(struct l_dirent, d_name)-1);
587                         error = copyout(linux_dirent, outp, linuxreclen);
588                 }
589
590                 if (error)
591                         goto out;
592
593                 inp += reclen;
594                 if (cookiep) {
595                         off = *cookiep++;
596                         ncookies--;
597                 } else
598                         off += reclen;
599
600                 outp += linuxreclen;
601                 resid -= linuxreclen;
602                 len -= reclen;
603                 if (justone)
604                         break;
605         }
606
607         if (outp == (caddr_t)args->dirent)
608                 goto again;
609
610         fp->f_offset = off;
611         if (justone)
612                 nbytes = resid + linuxreclen;
613
614 eof:
615         td->td_retval[0] = nbytes - resid;
616
617 out:
618         if (cookies)
619                 free(cookies, M_TEMP);
620
621         VOP_UNLOCK(vp, 0, td);
622         VFS_UNLOCK_GIANT(vfslocked);
623         fdrop(fp, td);
624         free(buf, M_TEMP);
625         free(lbuf, M_TEMP);
626         return (error);
627 }
628
629 int
630 linux_getdents(struct thread *td, struct linux_getdents_args *args)
631 {
632
633 #ifdef DEBUG
634         if (ldebug(getdents))
635                 printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count);
636 #endif
637
638         return (getdents_common(td, (struct linux_getdents64_args*)args, 0));
639 }
640
641 int
642 linux_getdents64(struct thread *td, struct linux_getdents64_args *args)
643 {
644
645 #ifdef DEBUG
646         if (ldebug(getdents64))
647                 printf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count);
648 #endif
649
650         return (getdents_common(td, args, 1));
651 }
652
653 /*
654  * These exist mainly for hooks for doing /compat/linux translation.
655  */
656
657 int
658 linux_access(struct thread *td, struct linux_access_args *args)
659 {
660         char *path;
661         int error;
662
663         /* linux convention */
664         if (args->flags & ~(F_OK | X_OK | W_OK | R_OK))
665                 return (EINVAL);
666
667         LCONVPATHEXIST(td, args->path, &path);
668
669 #ifdef DEBUG
670         if (ldebug(access))
671                 printf(ARGS(access, "%s, %d"), path, args->flags);
672 #endif
673         error = kern_access(td, path, UIO_SYSSPACE, args->flags);
674         LFREEPATH(path);
675
676         return (error);
677 }
678
679 int
680 linux_unlink(struct thread *td, struct linux_unlink_args *args)
681 {
682         char *path;
683         int error;
684         struct stat st;
685
686         LCONVPATHEXIST(td, args->path, &path);
687
688 #ifdef DEBUG
689         if (ldebug(unlink))
690                 printf(ARGS(unlink, "%s"), path);
691 #endif
692
693         error = kern_unlink(td, path, UIO_SYSSPACE);
694         if (error == EPERM)
695                 /* Introduce POSIX noncompliant behaviour of Linux */
696                 if (kern_stat(td, path, UIO_SYSSPACE, &st) == 0)
697                         if (S_ISDIR(st.st_mode))
698                                 error = EISDIR;
699         LFREEPATH(path);
700         return (error);
701 }
702
703 int
704 linux_chdir(struct thread *td, struct linux_chdir_args *args)
705 {
706         char *path;
707         int error;
708
709         LCONVPATHEXIST(td, args->path, &path);
710
711 #ifdef DEBUG
712         if (ldebug(chdir))
713                 printf(ARGS(chdir, "%s"), path);
714 #endif
715         error = kern_chdir(td, path, UIO_SYSSPACE);
716         LFREEPATH(path);
717         return (error);
718 }
719
720 int
721 linux_chmod(struct thread *td, struct linux_chmod_args *args)
722 {
723         char *path;
724         int error;
725
726         LCONVPATHEXIST(td, args->path, &path);
727
728 #ifdef DEBUG
729         if (ldebug(chmod))
730                 printf(ARGS(chmod, "%s, %d"), path, args->mode);
731 #endif
732         error = kern_chmod(td, path, UIO_SYSSPACE, args->mode);
733         LFREEPATH(path);
734         return (error);
735 }
736
737 int
738 linux_mkdir(struct thread *td, struct linux_mkdir_args *args)
739 {
740         char *path;
741         int error;
742
743         LCONVPATHCREAT(td, args->path, &path);
744
745 #ifdef DEBUG
746         if (ldebug(mkdir))
747                 printf(ARGS(mkdir, "%s, %d"), path, args->mode);
748 #endif
749         error = kern_mkdir(td, path, UIO_SYSSPACE, args->mode);
750         LFREEPATH(path);
751         return (error);
752 }
753
754 int
755 linux_rmdir(struct thread *td, struct linux_rmdir_args *args)
756 {
757         char *path;
758         int error;
759
760         LCONVPATHEXIST(td, args->path, &path);
761
762 #ifdef DEBUG
763         if (ldebug(rmdir))
764                 printf(ARGS(rmdir, "%s"), path);
765 #endif
766         error = kern_rmdir(td, path, UIO_SYSSPACE);
767         LFREEPATH(path);
768         return (error);
769 }
770
771 int
772 linux_rename(struct thread *td, struct linux_rename_args *args)
773 {
774         char *from, *to;
775         int error;
776
777         LCONVPATHEXIST(td, args->from, &from);
778         /* Expand LCONVPATHCREATE so that `from' can be freed on errors */
779         error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1);
780         if (to == NULL) {
781                 LFREEPATH(from);
782                 return (error);
783         }
784
785 #ifdef DEBUG
786         if (ldebug(rename))
787                 printf(ARGS(rename, "%s, %s"), from, to);
788 #endif
789         error = kern_rename(td, from, to, UIO_SYSSPACE);
790         LFREEPATH(from);
791         LFREEPATH(to);
792         return (error);
793 }
794
795 int
796 linux_symlink(struct thread *td, struct linux_symlink_args *args)
797 {
798         char *path, *to;
799         int error;
800
801         LCONVPATHEXIST(td, args->path, &path);
802         /* Expand LCONVPATHCREATE so that `path' can be freed on errors */
803         error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1);
804         if (to == NULL) {
805                 LFREEPATH(path);
806                 return (error);
807         }
808
809 #ifdef DEBUG
810         if (ldebug(symlink))
811                 printf(ARGS(symlink, "%s, %s"), path, to);
812 #endif
813         error = kern_symlink(td, path, to, UIO_SYSSPACE);
814         LFREEPATH(path);
815         LFREEPATH(to);
816         return (error);
817 }
818
819 int
820 linux_readlink(struct thread *td, struct linux_readlink_args *args)
821 {
822         char *name;
823         int error;
824
825         LCONVPATHEXIST(td, args->name, &name);
826
827 #ifdef DEBUG
828         if (ldebug(readlink))
829                 printf(ARGS(readlink, "%s, %p, %d"), name, (void *)args->buf,
830                     args->count);
831 #endif
832         error = kern_readlink(td, name, UIO_SYSSPACE, args->buf, UIO_USERSPACE,
833             args->count);
834         LFREEPATH(name);
835         return (error);
836 }
837
838 int
839 linux_truncate(struct thread *td, struct linux_truncate_args *args)
840 {
841         char *path;
842         int error;
843
844         LCONVPATHEXIST(td, args->path, &path);
845
846 #ifdef DEBUG
847         if (ldebug(truncate))
848                 printf(ARGS(truncate, "%s, %ld"), path, (long)args->length);
849 #endif
850
851         error = kern_truncate(td, path, UIO_SYSSPACE, args->length);
852         LFREEPATH(path);
853         return (error);
854 }
855
856 int
857 linux_ftruncate(struct thread *td, struct linux_ftruncate_args *args)
858 {
859         struct ftruncate_args /* {
860                 int fd;
861                 int pad;
862                 off_t length;
863                 } */ nuap;
864            
865         nuap.fd = args->fd;
866         nuap.length = args->length;
867         return (ftruncate(td, &nuap));
868 }
869
870 int
871 linux_link(struct thread *td, struct linux_link_args *args)
872 {
873         char *path, *to;
874         int error;
875
876         LCONVPATHEXIST(td, args->path, &path);
877         /* Expand LCONVPATHCREATE so that `path' can be freed on errors */
878         error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1);
879         if (to == NULL) {
880                 LFREEPATH(path);
881                 return (error);
882         }
883
884 #ifdef DEBUG
885         if (ldebug(link))
886                 printf(ARGS(link, "%s, %s"), path, to);
887 #endif
888         error = kern_link(td, path, to, UIO_SYSSPACE);
889         LFREEPATH(path);
890         LFREEPATH(to);
891         return (error);
892 }
893
894 int
895 linux_fdatasync(td, uap)
896         struct thread *td;
897         struct linux_fdatasync_args *uap;
898 {
899         struct fsync_args bsd;
900
901         bsd.fd = uap->fd;
902         return fsync(td, &bsd);
903 }
904
905 int
906 linux_pread(td, uap)
907         struct thread *td;
908         struct linux_pread_args *uap;
909 {
910         struct pread_args bsd;
911         struct vnode *vp;
912         int error;
913
914         bsd.fd = uap->fd;
915         bsd.buf = uap->buf;
916         bsd.nbyte = uap->nbyte;
917         bsd.offset = uap->offset;
918
919         error = pread(td, &bsd);
920
921         if (error == 0) {
922                 /* This seems to violate POSIX but linux does it */
923                 if ((error = fgetvp(td, uap->fd, &vp)) != 0)
924                         return (error);
925                 if (vp->v_type == VDIR) {
926                         vrele(vp);
927                         return (EISDIR);
928                 }
929                 vrele(vp);
930         }
931
932         return (error);
933 }
934
935 int
936 linux_pwrite(td, uap)
937         struct thread *td;
938         struct linux_pwrite_args *uap;
939 {
940         struct pwrite_args bsd;
941
942         bsd.fd = uap->fd;
943         bsd.buf = uap->buf;
944         bsd.nbyte = uap->nbyte;
945         bsd.offset = uap->offset;
946         return pwrite(td, &bsd);
947 }
948
949 int
950 linux_mount(struct thread *td, struct linux_mount_args *args)
951 {
952         struct ufs_args ufs;
953         char fstypename[MFSNAMELEN];
954         char mntonname[MNAMELEN], mntfromname[MNAMELEN];
955         int error;
956         int fsflags;
957         void *fsdata;
958
959         error = copyinstr(args->filesystemtype, fstypename, MFSNAMELEN - 1,
960             NULL);
961         if (error)
962                 return (error);
963         error = copyinstr(args->specialfile, mntfromname, MNAMELEN - 1, NULL);
964         if (error)
965                 return (error);
966         error = copyinstr(args->dir, mntonname, MNAMELEN - 1, NULL);
967         if (error)
968                 return (error);
969
970 #ifdef DEBUG
971         if (ldebug(mount))
972                 printf(ARGS(mount, "%s, %s, %s"),
973                     fstypename, mntfromname, mntonname);
974 #endif
975
976         if (strcmp(fstypename, "ext2") == 0) {
977                 strcpy(fstypename, "ext2fs");
978                 fsdata = &ufs;
979                 ufs.fspec = mntfromname;
980 #define DEFAULT_ROOTID          -2
981                 ufs.export.ex_root = DEFAULT_ROOTID;
982                 ufs.export.ex_flags =
983                     args->rwflag & LINUX_MS_RDONLY ? MNT_EXRDONLY : 0;
984         } else if (strcmp(fstypename, "proc") == 0) {
985                 strcpy(fstypename, "linprocfs");
986                 fsdata = NULL;
987         } else {
988                 return (ENODEV);
989         }
990
991         fsflags = 0;
992
993         if ((args->rwflag & 0xffff0000) == 0xc0ed0000) {
994                 /*
995                  * Linux SYNC flag is not included; the closest equivalent
996                  * FreeBSD has is !ASYNC, which is our default.
997                  */
998                 if (args->rwflag & LINUX_MS_RDONLY)
999                         fsflags |= MNT_RDONLY;
1000                 if (args->rwflag & LINUX_MS_NOSUID)
1001                         fsflags |= MNT_NOSUID;
1002                 if (args->rwflag & LINUX_MS_NOEXEC)
1003                         fsflags |= MNT_NOEXEC;
1004                 if (args->rwflag & LINUX_MS_REMOUNT)
1005                         fsflags |= MNT_UPDATE;
1006         }
1007
1008         if (strcmp(fstypename, "linprocfs") == 0) {
1009                 error = kernel_vmount(fsflags,
1010                         "fstype", fstypename,
1011                         "fspath", mntonname,
1012                         NULL);
1013         } else
1014                 error = EOPNOTSUPP;
1015         return (error);
1016 }
1017
1018 int
1019 linux_oldumount(struct thread *td, struct linux_oldumount_args *args)
1020 {
1021         struct linux_umount_args args2;
1022
1023         args2.path = args->path;
1024         args2.flags = 0;
1025         return (linux_umount(td, &args2));
1026 }
1027
1028 int
1029 linux_umount(struct thread *td, struct linux_umount_args *args)
1030 {
1031         struct unmount_args bsd;
1032
1033         bsd.path = args->path;
1034         bsd.flags = args->flags;        /* XXX correct? */
1035         return (unmount(td, &bsd));
1036 }
1037
1038 /*
1039  * fcntl family of syscalls
1040  */
1041
1042 struct l_flock {
1043         l_short         l_type;
1044         l_short         l_whence;
1045         l_off_t         l_start;
1046         l_off_t         l_len;
1047         l_pid_t         l_pid;
1048 }
1049 #if defined(__amd64__) && defined(COMPAT_LINUX32)
1050 __packed
1051 #endif
1052 ;
1053
1054 static void
1055 linux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock)
1056 {
1057         switch (linux_flock->l_type) {
1058         case LINUX_F_RDLCK:
1059                 bsd_flock->l_type = F_RDLCK;
1060                 break;
1061         case LINUX_F_WRLCK:
1062                 bsd_flock->l_type = F_WRLCK;
1063                 break;
1064         case LINUX_F_UNLCK:
1065                 bsd_flock->l_type = F_UNLCK;
1066                 break;
1067         default:
1068                 bsd_flock->l_type = -1;
1069                 break;
1070         }
1071         bsd_flock->l_whence = linux_flock->l_whence;
1072         bsd_flock->l_start = (off_t)linux_flock->l_start;
1073         bsd_flock->l_len = (off_t)linux_flock->l_len;
1074         bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1075         bsd_flock->l_sysid = 0;
1076 }
1077
1078 static void
1079 bsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock)
1080 {
1081         switch (bsd_flock->l_type) {
1082         case F_RDLCK:
1083                 linux_flock->l_type = LINUX_F_RDLCK;
1084                 break;
1085         case F_WRLCK:
1086                 linux_flock->l_type = LINUX_F_WRLCK;
1087                 break;
1088         case F_UNLCK:
1089                 linux_flock->l_type = LINUX_F_UNLCK;
1090                 break;
1091         }
1092         linux_flock->l_whence = bsd_flock->l_whence;
1093         linux_flock->l_start = (l_off_t)bsd_flock->l_start;
1094         linux_flock->l_len = (l_off_t)bsd_flock->l_len;
1095         linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
1096 }
1097
1098 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
1099 struct l_flock64 {
1100         l_short         l_type;
1101         l_short         l_whence;
1102         l_loff_t        l_start;
1103         l_loff_t        l_len;
1104         l_pid_t         l_pid;
1105 }
1106 #if defined(__amd64__) && defined(COMPAT_LINUX32)
1107 __packed
1108 #endif
1109 ;
1110
1111 static void
1112 linux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock)
1113 {
1114         switch (linux_flock->l_type) {
1115         case LINUX_F_RDLCK:
1116                 bsd_flock->l_type = F_RDLCK;
1117                 break;
1118         case LINUX_F_WRLCK:
1119                 bsd_flock->l_type = F_WRLCK;
1120                 break;
1121         case LINUX_F_UNLCK:
1122                 bsd_flock->l_type = F_UNLCK;
1123                 break;
1124         default:
1125                 bsd_flock->l_type = -1;
1126                 break;
1127         }
1128         bsd_flock->l_whence = linux_flock->l_whence;
1129         bsd_flock->l_start = (off_t)linux_flock->l_start;
1130         bsd_flock->l_len = (off_t)linux_flock->l_len;
1131         bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1132         bsd_flock->l_sysid = 0;
1133 }
1134
1135 static void
1136 bsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock)
1137 {
1138         switch (bsd_flock->l_type) {
1139         case F_RDLCK:
1140                 linux_flock->l_type = LINUX_F_RDLCK;
1141                 break;
1142         case F_WRLCK:
1143                 linux_flock->l_type = LINUX_F_WRLCK;
1144                 break;
1145         case F_UNLCK:
1146                 linux_flock->l_type = LINUX_F_UNLCK;
1147                 break;
1148         }
1149         linux_flock->l_whence = bsd_flock->l_whence;
1150         linux_flock->l_start = (l_loff_t)bsd_flock->l_start;
1151         linux_flock->l_len = (l_loff_t)bsd_flock->l_len;
1152         linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
1153 }
1154 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
1155
1156 static int
1157 fcntl_common(struct thread *td, struct linux_fcntl64_args *args)
1158 {
1159         struct l_flock linux_flock;
1160         struct flock bsd_flock;
1161         struct file *fp;
1162         long arg;
1163         int error, result;
1164
1165         switch (args->cmd) {
1166         case LINUX_F_DUPFD:
1167                 return (kern_fcntl(td, args->fd, F_DUPFD, args->arg));
1168
1169         case LINUX_F_GETFD:
1170                 return (kern_fcntl(td, args->fd, F_GETFD, 0));
1171
1172         case LINUX_F_SETFD:
1173                 return (kern_fcntl(td, args->fd, F_SETFD, args->arg));
1174
1175         case LINUX_F_GETFL:
1176                 error = kern_fcntl(td, args->fd, F_GETFL, 0);
1177                 result = td->td_retval[0];
1178                 td->td_retval[0] = 0;
1179                 if (result & O_RDONLY)
1180                         td->td_retval[0] |= LINUX_O_RDONLY;
1181                 if (result & O_WRONLY)
1182                         td->td_retval[0] |= LINUX_O_WRONLY;
1183                 if (result & O_RDWR)
1184                         td->td_retval[0] |= LINUX_O_RDWR;
1185                 if (result & O_NDELAY)
1186                         td->td_retval[0] |= LINUX_O_NONBLOCK;
1187                 if (result & O_APPEND)
1188                         td->td_retval[0] |= LINUX_O_APPEND;
1189                 if (result & O_FSYNC)
1190                         td->td_retval[0] |= LINUX_O_SYNC;
1191                 if (result & O_ASYNC)
1192                         td->td_retval[0] |= LINUX_FASYNC;
1193 #ifdef LINUX_O_NOFOLLOW
1194                 if (result & O_NOFOLLOW)
1195                         td->td_retval[0] |= LINUX_O_NOFOLLOW;
1196 #endif
1197 #ifdef LINUX_O_DIRECT
1198                 if (result & O_DIRECT)
1199                         td->td_retval[0] |= LINUX_O_DIRECT;
1200 #endif
1201                 return (error);
1202
1203         case LINUX_F_SETFL:
1204                 arg = 0;
1205                 if (args->arg & LINUX_O_NDELAY)
1206                         arg |= O_NONBLOCK;
1207                 if (args->arg & LINUX_O_APPEND)
1208                         arg |= O_APPEND;
1209                 if (args->arg & LINUX_O_SYNC)
1210                         arg |= O_FSYNC;
1211                 if (args->arg & LINUX_FASYNC)
1212                         arg |= O_ASYNC;
1213 #ifdef LINUX_O_NOFOLLOW
1214                 if (args->arg & LINUX_O_NOFOLLOW)
1215                         arg |= O_NOFOLLOW;
1216 #endif
1217 #ifdef LINUX_O_DIRECT
1218                 if (args->arg & LINUX_O_DIRECT)
1219                         arg |= O_DIRECT;
1220 #endif
1221                 return (kern_fcntl(td, args->fd, F_SETFL, arg));
1222
1223         case LINUX_F_GETLK:
1224                 error = copyin((void *)args->arg, &linux_flock,
1225                     sizeof(linux_flock));
1226                 if (error)
1227                         return (error);
1228                 linux_to_bsd_flock(&linux_flock, &bsd_flock);
1229                 error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock);
1230                 if (error)
1231                         return (error);
1232                 bsd_to_linux_flock(&bsd_flock, &linux_flock);
1233                 return (copyout(&linux_flock, (void *)args->arg,
1234                     sizeof(linux_flock)));
1235
1236         case LINUX_F_SETLK:
1237                 error = copyin((void *)args->arg, &linux_flock,
1238                     sizeof(linux_flock));
1239                 if (error)
1240                         return (error);
1241                 linux_to_bsd_flock(&linux_flock, &bsd_flock);
1242                 return (kern_fcntl(td, args->fd, F_SETLK,
1243                     (intptr_t)&bsd_flock));
1244
1245         case LINUX_F_SETLKW:
1246                 error = copyin((void *)args->arg, &linux_flock,
1247                     sizeof(linux_flock));
1248                 if (error)
1249                         return (error);
1250                 linux_to_bsd_flock(&linux_flock, &bsd_flock);
1251                 return (kern_fcntl(td, args->fd, F_SETLKW,
1252                      (intptr_t)&bsd_flock));
1253
1254         case LINUX_F_GETOWN:
1255                 return (kern_fcntl(td, args->fd, F_GETOWN, 0));
1256
1257         case LINUX_F_SETOWN:
1258                 /*
1259                  * XXX some Linux applications depend on F_SETOWN having no
1260                  * significant effect for pipes (SIGIO is not delivered for
1261                  * pipes under Linux-2.2.35 at least).
1262                  */
1263                 error = fget(td, args->fd, &fp);
1264                 if (error)
1265                         return (error);
1266                 if (fp->f_type == DTYPE_PIPE) {
1267                         fdrop(fp, td);
1268                         return (EINVAL);
1269                 }
1270                 fdrop(fp, td);
1271
1272                 return (kern_fcntl(td, args->fd, F_SETOWN, args->arg));
1273         }
1274
1275         return (EINVAL);
1276 }
1277
1278 int
1279 linux_fcntl(struct thread *td, struct linux_fcntl_args *args)
1280 {
1281         struct linux_fcntl64_args args64;
1282
1283 #ifdef DEBUG
1284         if (ldebug(fcntl))
1285                 printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd);
1286 #endif
1287
1288         args64.fd = args->fd;
1289         args64.cmd = args->cmd;
1290         args64.arg = args->arg;
1291         return (fcntl_common(td, &args64));
1292 }
1293
1294 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
1295 int
1296 linux_fcntl64(struct thread *td, struct linux_fcntl64_args *args)
1297 {
1298         struct l_flock64 linux_flock;
1299         struct flock bsd_flock;
1300         int error;
1301
1302 #ifdef DEBUG
1303         if (ldebug(fcntl64))
1304                 printf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd);
1305 #endif
1306
1307         switch (args->cmd) {
1308         case LINUX_F_GETLK64:
1309                 error = copyin((void *)args->arg, &linux_flock,
1310                     sizeof(linux_flock));
1311                 if (error)
1312                         return (error);
1313                 linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1314                 error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock);
1315                 if (error)
1316                         return (error);
1317                 bsd_to_linux_flock64(&bsd_flock, &linux_flock);
1318                 return (copyout(&linux_flock, (void *)args->arg,
1319                             sizeof(linux_flock)));
1320
1321         case LINUX_F_SETLK64:
1322                 error = copyin((void *)args->arg, &linux_flock,
1323                     sizeof(linux_flock));
1324                 if (error)
1325                         return (error);
1326                 linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1327                 return (kern_fcntl(td, args->fd, F_SETLK,
1328                     (intptr_t)&bsd_flock));
1329
1330         case LINUX_F_SETLKW64:
1331                 error = copyin((void *)args->arg, &linux_flock,
1332                     sizeof(linux_flock));
1333                 if (error)
1334                         return (error);
1335                 linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1336                 return (kern_fcntl(td, args->fd, F_SETLKW,
1337                     (intptr_t)&bsd_flock));
1338         }
1339
1340         return (fcntl_common(td, args));
1341 }
1342 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
1343
1344 int
1345 linux_chown(struct thread *td, struct linux_chown_args *args)
1346 {
1347         char *path;
1348         int error;
1349
1350         LCONVPATHEXIST(td, args->path, &path);
1351
1352 #ifdef DEBUG
1353         if (ldebug(chown))
1354                 printf(ARGS(chown, "%s, %d, %d"), path, args->uid, args->gid);
1355 #endif
1356         error = kern_chown(td, path, UIO_SYSSPACE, args->uid, args->gid);
1357         LFREEPATH(path);
1358         return (error);
1359 }
1360
1361 int
1362 linux_lchown(struct thread *td, struct linux_lchown_args *args)
1363 {
1364         char *path;
1365         int error;
1366
1367         LCONVPATHEXIST(td, args->path, &path);
1368
1369 #ifdef DEBUG
1370         if (ldebug(lchown))
1371                 printf(ARGS(lchown, "%s, %d, %d"), path, args->uid, args->gid);
1372 #endif
1373         error = kern_lchown(td, path, UIO_SYSSPACE, args->uid, args->gid);
1374         LFREEPATH(path);
1375         return (error);
1376 }