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