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