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