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 #define LINUX_RECLEN(de,namlen) \
400 ALIGN((((char *)&(de)->d_name - (char *)de) + (namlen) + 1))
401
402 #define LINUX_DIRBLKSIZ 512
403
404 static int
405 getdents_common(struct thread *td, struct linux_getdents64_args *args,
406 int is64bit)
407 {
408 struct dirent *bdp;
409 struct vnode *vp;
410 caddr_t inp, buf; /* BSD-format */
411 int len, reclen; /* BSD-format */
412 caddr_t outp; /* Linux-format */
413 int resid, linuxreclen=0; /* Linux-format */
414 struct file *fp;
415 struct uio auio;
416 struct iovec aiov;
417 off_t off;
418 struct l_dirent linux_dirent;
419 struct l_dirent64 linux_dirent64;
420 int buflen, error, eofflag, nbytes, justone;
421 u_long *cookies = NULL, *cookiep;
422 int ncookies, vfslocked;
423
424 nbytes = args->count;
425 if (nbytes == 1) {
426 /* readdir(2) case. Always struct dirent. */
427 if (is64bit)
428 return (EINVAL);
429 nbytes = sizeof(linux_dirent);
430 justone = 1;
431 } else
432 justone = 0;
433
434 if ((error = getvnode(td->td_proc->p_fd, args->fd, &fp)) != 0)
435 return (error);
436
437 if ((fp->f_flag & FREAD) == 0) {
438 fdrop(fp, td);
439 return (EBADF);
440 }
441
442 vp = fp->f_vnode;
443 vfslocked = VFS_LOCK_GIANT(vp->v_mount);
444 if (vp->v_type != VDIR) {
445 VFS_UNLOCK_GIANT(vfslocked);
446 fdrop(fp, td);
447 return (EINVAL);
448 }
449
450 off = fp->f_offset;
451
452 buflen = max(LINUX_DIRBLKSIZ, nbytes);
453 buflen = min(buflen, MAXBSIZE);
454 buf = malloc(buflen, M_TEMP, M_WAITOK);
455 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
456
457 again:
458 aiov.iov_base = buf;
459 aiov.iov_len = buflen;
460 auio.uio_iov = &aiov;
461 auio.uio_iovcnt = 1;
462 auio.uio_rw = UIO_READ;
463 auio.uio_segflg = UIO_SYSSPACE;
464 auio.uio_td = td;
465 auio.uio_resid = buflen;
466 auio.uio_offset = off;
467
468 if (cookies) {
469 free(cookies, M_TEMP);
470 cookies = NULL;
471 }
472
473 #ifdef MAC
474 /*
475 * Do directory search MAC check using non-cached credentials.
476 */
477 if ((error = mac_check_vnode_readdir(td->td_ucred, vp)))
478 goto out;
479 #endif /* MAC */
480 if ((error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies,
481 &cookies)))
482 goto out;
483
484 inp = buf;
485 outp = (caddr_t)args->dirent;
486 resid = nbytes;
487 if ((len = buflen - auio.uio_resid) <= 0)
488 goto eof;
489
490 cookiep = cookies;
491
492 if (cookies) {
493 /*
494 * When using cookies, the vfs has the option of reading from
495 * a different offset than that supplied (UFS truncates the
496 * offset to a block boundary to make sure that it never reads
497 * partway through a directory entry, even if the directory
498 * has been compacted).
499 */
500 while (len > 0 && ncookies > 0 && *cookiep <= off) {
501 bdp = (struct dirent *) inp;
502 len -= bdp->d_reclen;
503 inp += bdp->d_reclen;
504 cookiep++;
505 ncookies--;
506 }
507 }
508
509 while (len > 0) {
510 if (cookiep && ncookies == 0)
511 break;
512 bdp = (struct dirent *) inp;
513 reclen = bdp->d_reclen;
514 if (reclen & 3) {
515 error = EFAULT;
516 goto out;
517 }
518
519 if (bdp->d_fileno == 0) {
520 inp += reclen;
521 if (cookiep) {
522 off = *cookiep++;
523 ncookies--;
524 } else
525 off += reclen;
526
527 len -= reclen;
528 continue;
529 }
530
531 linuxreclen = (is64bit)
532 ? LINUX_RECLEN(&linux_dirent64, bdp->d_namlen)
533 : LINUX_RECLEN(&linux_dirent, bdp->d_namlen);
534
535 if (reclen > len || resid < linuxreclen) {
536 outp++;
537 break;
538 }
539
540 if (justone) {
541 /* readdir(2) case. */
542 linux_dirent.d_ino = (l_long)bdp->d_fileno;
543 linux_dirent.d_off = (l_off_t)linuxreclen;
544 linux_dirent.d_reclen = (l_ushort)bdp->d_namlen;
545 strcpy(linux_dirent.d_name, bdp->d_name);
546 error = copyout(&linux_dirent, outp, linuxreclen);
547 } else {
548 if (is64bit) {
549 linux_dirent64.d_ino = bdp->d_fileno;
550 linux_dirent64.d_off = (cookiep)
551 ? (l_off_t)*cookiep
552 : (l_off_t)(off + reclen);
553 linux_dirent64.d_reclen =
554 (l_ushort)linuxreclen;
555 linux_dirent64.d_type = bdp->d_type;
556 strcpy(linux_dirent64.d_name, bdp->d_name);
557 error = copyout(&linux_dirent64, outp,
558 linuxreclen);
559 } else {
560 linux_dirent.d_ino = bdp->d_fileno;
561 linux_dirent.d_off = (cookiep)
562 ? (l_off_t)*cookiep
563 : (l_off_t)(off + reclen);
564 linux_dirent.d_reclen = (l_ushort)linuxreclen;
565 strcpy(linux_dirent.d_name, bdp->d_name);
566 error = copyout(&linux_dirent, outp,
567 linuxreclen);
568 }
569 }
570 if (error)
571 goto out;
572
573 inp += reclen;
574 if (cookiep) {
575 off = *cookiep++;
576 ncookies--;
577 } else
578 off += reclen;
579
580 outp += linuxreclen;
581 resid -= linuxreclen;
582 len -= reclen;
583 if (justone)
584 break;
585 }
586
587 if (outp == (caddr_t)args->dirent)
588 goto again;
589
590 fp->f_offset = off;
591 if (justone)
592 nbytes = resid + linuxreclen;
593
594 eof:
595 td->td_retval[0] = nbytes - resid;
596
597 out:
598 if (cookies)
599 free(cookies, M_TEMP);
600
601 VOP_UNLOCK(vp, 0, td);
602 VFS_UNLOCK_GIANT(vfslocked);
603 fdrop(fp, td);
604 free(buf, M_TEMP);
605 return (error);
606 }
607
608 int
609 linux_getdents(struct thread *td, struct linux_getdents_args *args)
610 {
611
612 #ifdef DEBUG
613 if (ldebug(getdents))
614 printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count);
615 #endif
616
617 return (getdents_common(td, (struct linux_getdents64_args*)args, 0));
618 }
619
620 int
621 linux_getdents64(struct thread *td, struct linux_getdents64_args *args)
622 {
623
624 #ifdef DEBUG
625 if (ldebug(getdents64))
626 printf(ARGS(getdents64, "%d, *, %d"), args->fd, args->count);
627 #endif
628
629 return (getdents_common(td, args, 1));
630 }
631
632 /*
633 * These exist mainly for hooks for doing /compat/linux translation.
634 */
635
636 int
637 linux_access(struct thread *td, struct linux_access_args *args)
638 {
639 char *path;
640 int error;
641
642 /* linux convention */
643 if (args->flags & ~(F_OK | X_OK | W_OK | R_OK))
644 return (EINVAL);
645
646 LCONVPATHEXIST(td, args->path, &path);
647
648 #ifdef DEBUG
649 if (ldebug(access))
650 printf(ARGS(access, "%s, %d"), path, args->flags);
651 #endif
652 error = kern_access(td, path, UIO_SYSSPACE, args->flags);
653 LFREEPATH(path);
654
655 return (error);
656 }
657
658 int
659 linux_unlink(struct thread *td, struct linux_unlink_args *args)
660 {
661 char *path;
662 int error;
663 struct stat st;
664
665 LCONVPATHEXIST(td, args->path, &path);
666
667 #ifdef DEBUG
668 if (ldebug(unlink))
669 printf(ARGS(unlink, "%s"), path);
670 #endif
671
672 error = kern_unlink(td, path, UIO_SYSSPACE);
673 if (error == EPERM)
674 /* Introduce POSIX noncompliant behaviour of Linux */
675 if (kern_stat(td, path, UIO_SYSSPACE, &st) == 0)
676 if (S_ISDIR(st.st_mode))
677 error = EISDIR;
678 LFREEPATH(path);
679 return (error);
680 }
681
682 int
683 linux_chdir(struct thread *td, struct linux_chdir_args *args)
684 {
685 char *path;
686 int error;
687
688 LCONVPATHEXIST(td, args->path, &path);
689
690 #ifdef DEBUG
691 if (ldebug(chdir))
692 printf(ARGS(chdir, "%s"), path);
693 #endif
694 error = kern_chdir(td, path, UIO_SYSSPACE);
695 LFREEPATH(path);
696 return (error);
697 }
698
699 int
700 linux_chmod(struct thread *td, struct linux_chmod_args *args)
701 {
702 char *path;
703 int error;
704
705 LCONVPATHEXIST(td, args->path, &path);
706
707 #ifdef DEBUG
708 if (ldebug(chmod))
709 printf(ARGS(chmod, "%s, %d"), path, args->mode);
710 #endif
711 error = kern_chmod(td, path, UIO_SYSSPACE, args->mode);
712 LFREEPATH(path);
713 return (error);
714 }
715
716 int
717 linux_mkdir(struct thread *td, struct linux_mkdir_args *args)
718 {
719 char *path;
720 int error;
721
722 LCONVPATHCREAT(td, args->path, &path);
723
724 #ifdef DEBUG
725 if (ldebug(mkdir))
726 printf(ARGS(mkdir, "%s, %d"), path, args->mode);
727 #endif
728 error = kern_mkdir(td, path, UIO_SYSSPACE, args->mode);
729 LFREEPATH(path);
730 return (error);
731 }
732
733 int
734 linux_rmdir(struct thread *td, struct linux_rmdir_args *args)
735 {
736 char *path;
737 int error;
738
739 LCONVPATHEXIST(td, args->path, &path);
740
741 #ifdef DEBUG
742 if (ldebug(rmdir))
743 printf(ARGS(rmdir, "%s"), path);
744 #endif
745 error = kern_rmdir(td, path, UIO_SYSSPACE);
746 LFREEPATH(path);
747 return (error);
748 }
749
750 int
751 linux_rename(struct thread *td, struct linux_rename_args *args)
752 {
753 char *from, *to;
754 int error;
755
756 LCONVPATHEXIST(td, args->from, &from);
757 /* Expand LCONVPATHCREATE so that `from' can be freed on errors */
758 error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1);
759 if (to == NULL) {
760 LFREEPATH(from);
761 return (error);
762 }
763
764 #ifdef DEBUG
765 if (ldebug(rename))
766 printf(ARGS(rename, "%s, %s"), from, to);
767 #endif
768 error = kern_rename(td, from, to, UIO_SYSSPACE);
769 LFREEPATH(from);
770 LFREEPATH(to);
771 return (error);
772 }
773
774 int
775 linux_symlink(struct thread *td, struct linux_symlink_args *args)
776 {
777 char *path, *to;
778 int error;
779
780 LCONVPATHEXIST(td, args->path, &path);
781 /* Expand LCONVPATHCREATE so that `path' can be freed on errors */
782 error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1);
783 if (to == NULL) {
784 LFREEPATH(path);
785 return (error);
786 }
787
788 #ifdef DEBUG
789 if (ldebug(symlink))
790 printf(ARGS(symlink, "%s, %s"), path, to);
791 #endif
792 error = kern_symlink(td, path, to, UIO_SYSSPACE);
793 LFREEPATH(path);
794 LFREEPATH(to);
795 return (error);
796 }
797
798 int
799 linux_readlink(struct thread *td, struct linux_readlink_args *args)
800 {
801 char *name;
802 int error;
803
804 LCONVPATHEXIST(td, args->name, &name);
805
806 #ifdef DEBUG
807 if (ldebug(readlink))
808 printf(ARGS(readlink, "%s, %p, %d"), name, (void *)args->buf,
809 args->count);
810 #endif
811 error = kern_readlink(td, name, UIO_SYSSPACE, args->buf, UIO_USERSPACE,
812 args->count);
813 LFREEPATH(name);
814 return (error);
815 }
816
817 int
818 linux_truncate(struct thread *td, struct linux_truncate_args *args)
819 {
820 char *path;
821 int error;
822
823 LCONVPATHEXIST(td, args->path, &path);
824
825 #ifdef DEBUG
826 if (ldebug(truncate))
827 printf(ARGS(truncate, "%s, %ld"), path, (long)args->length);
828 #endif
829
830 error = kern_truncate(td, path, UIO_SYSSPACE, args->length);
831 LFREEPATH(path);
832 return (error);
833 }
834
835 int
836 linux_ftruncate(struct thread *td, struct linux_ftruncate_args *args)
837 {
838 struct ftruncate_args /* {
839 int fd;
840 int pad;
841 off_t length;
842 } */ nuap;
843
844 nuap.fd = args->fd;
845 nuap.length = args->length;
846 return (ftruncate(td, &nuap));
847 }
848
849 int
850 linux_link(struct thread *td, struct linux_link_args *args)
851 {
852 char *path, *to;
853 int error;
854
855 LCONVPATHEXIST(td, args->path, &path);
856 /* Expand LCONVPATHCREATE so that `path' can be freed on errors */
857 error = linux_emul_convpath(td, args->to, UIO_USERSPACE, &to, 1);
858 if (to == NULL) {
859 LFREEPATH(path);
860 return (error);
861 }
862
863 #ifdef DEBUG
864 if (ldebug(link))
865 printf(ARGS(link, "%s, %s"), path, to);
866 #endif
867 error = kern_link(td, path, to, UIO_SYSSPACE);
868 LFREEPATH(path);
869 LFREEPATH(to);
870 return (error);
871 }
872
873 int
874 linux_fdatasync(td, uap)
875 struct thread *td;
876 struct linux_fdatasync_args *uap;
877 {
878 struct fsync_args bsd;
879
880 bsd.fd = uap->fd;
881 return fsync(td, &bsd);
882 }
883
884 int
885 linux_pread(td, uap)
886 struct thread *td;
887 struct linux_pread_args *uap;
888 {
889 struct pread_args bsd;
890 struct vnode *vp;
891 int error;
892
893 bsd.fd = uap->fd;
894 bsd.buf = uap->buf;
895 bsd.nbyte = uap->nbyte;
896 bsd.offset = uap->offset;
897
898 error = pread(td, &bsd);
899
900 if (error == 0) {
901 /* This seems to violate POSIX but linux does it */
902 if ((error = fgetvp(td, uap->fd, &vp)) != 0)
903 return (error);
904 if (vp->v_type == VDIR) {
905 vrele(vp);
906 return (EISDIR);
907 }
908 vrele(vp);
909 }
910
911 return (error);
912 }
913
914 int
915 linux_pwrite(td, uap)
916 struct thread *td;
917 struct linux_pwrite_args *uap;
918 {
919 struct pwrite_args bsd;
920
921 bsd.fd = uap->fd;
922 bsd.buf = uap->buf;
923 bsd.nbyte = uap->nbyte;
924 bsd.offset = uap->offset;
925 return pwrite(td, &bsd);
926 }
927
928 int
929 linux_mount(struct thread *td, struct linux_mount_args *args)
930 {
931 struct ufs_args ufs;
932 char fstypename[MFSNAMELEN];
933 char mntonname[MNAMELEN], mntfromname[MNAMELEN];
934 int error;
935 int fsflags;
936 void *fsdata;
937
938 error = copyinstr(args->filesystemtype, fstypename, MFSNAMELEN - 1,
939 NULL);
940 if (error)
941 return (error);
942 error = copyinstr(args->specialfile, mntfromname, MNAMELEN - 1, NULL);
943 if (error)
944 return (error);
945 error = copyinstr(args->dir, mntonname, MNAMELEN - 1, NULL);
946 if (error)
947 return (error);
948
949 #ifdef DEBUG
950 if (ldebug(mount))
951 printf(ARGS(mount, "%s, %s, %s"),
952 fstypename, mntfromname, mntonname);
953 #endif
954
955 if (strcmp(fstypename, "ext2") == 0) {
956 strcpy(fstypename, "ext2fs");
957 fsdata = &ufs;
958 ufs.fspec = mntfromname;
959 #define DEFAULT_ROOTID -2
960 ufs.export.ex_root = DEFAULT_ROOTID;
961 ufs.export.ex_flags =
962 args->rwflag & LINUX_MS_RDONLY ? MNT_EXRDONLY : 0;
963 } else if (strcmp(fstypename, "proc") == 0) {
964 strcpy(fstypename, "linprocfs");
965 fsdata = NULL;
966 } else {
967 return (ENODEV);
968 }
969
970 fsflags = 0;
971
972 if ((args->rwflag & 0xffff0000) == 0xc0ed0000) {
973 /*
974 * Linux SYNC flag is not included; the closest equivalent
975 * FreeBSD has is !ASYNC, which is our default.
976 */
977 if (args->rwflag & LINUX_MS_RDONLY)
978 fsflags |= MNT_RDONLY;
979 if (args->rwflag & LINUX_MS_NOSUID)
980 fsflags |= MNT_NOSUID;
981 if (args->rwflag & LINUX_MS_NOEXEC)
982 fsflags |= MNT_NOEXEC;
983 if (args->rwflag & LINUX_MS_REMOUNT)
984 fsflags |= MNT_UPDATE;
985 }
986
987 if (strcmp(fstypename, "linprocfs") == 0) {
988 error = kernel_vmount(fsflags,
989 "fstype", fstypename,
990 "fspath", mntonname,
991 NULL);
992 } else
993 error = EOPNOTSUPP;
994 return (error);
995 }
996
997 int
998 linux_oldumount(struct thread *td, struct linux_oldumount_args *args)
999 {
1000 struct linux_umount_args args2;
1001
1002 args2.path = args->path;
1003 args2.flags = 0;
1004 return (linux_umount(td, &args2));
1005 }
1006
1007 int
1008 linux_umount(struct thread *td, struct linux_umount_args *args)
1009 {
1010 struct unmount_args bsd;
1011
1012 bsd.path = args->path;
1013 bsd.flags = args->flags; /* XXX correct? */
1014 return (unmount(td, &bsd));
1015 }
1016
1017 /*
1018 * fcntl family of syscalls
1019 */
1020
1021 struct l_flock {
1022 l_short l_type;
1023 l_short l_whence;
1024 l_off_t l_start;
1025 l_off_t l_len;
1026 l_pid_t l_pid;
1027 }
1028 #if defined(__amd64__) && defined(COMPAT_LINUX32)
1029 __packed
1030 #endif
1031 ;
1032
1033 static void
1034 linux_to_bsd_flock(struct l_flock *linux_flock, struct flock *bsd_flock)
1035 {
1036 switch (linux_flock->l_type) {
1037 case LINUX_F_RDLCK:
1038 bsd_flock->l_type = F_RDLCK;
1039 break;
1040 case LINUX_F_WRLCK:
1041 bsd_flock->l_type = F_WRLCK;
1042 break;
1043 case LINUX_F_UNLCK:
1044 bsd_flock->l_type = F_UNLCK;
1045 break;
1046 default:
1047 bsd_flock->l_type = -1;
1048 break;
1049 }
1050 bsd_flock->l_whence = linux_flock->l_whence;
1051 bsd_flock->l_start = (off_t)linux_flock->l_start;
1052 bsd_flock->l_len = (off_t)linux_flock->l_len;
1053 bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1054 }
1055
1056 static void
1057 bsd_to_linux_flock(struct flock *bsd_flock, struct l_flock *linux_flock)
1058 {
1059 switch (bsd_flock->l_type) {
1060 case F_RDLCK:
1061 linux_flock->l_type = LINUX_F_RDLCK;
1062 break;
1063 case F_WRLCK:
1064 linux_flock->l_type = LINUX_F_WRLCK;
1065 break;
1066 case F_UNLCK:
1067 linux_flock->l_type = LINUX_F_UNLCK;
1068 break;
1069 }
1070 linux_flock->l_whence = bsd_flock->l_whence;
1071 linux_flock->l_start = (l_off_t)bsd_flock->l_start;
1072 linux_flock->l_len = (l_off_t)bsd_flock->l_len;
1073 linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
1074 }
1075
1076 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
1077 struct l_flock64 {
1078 l_short l_type;
1079 l_short l_whence;
1080 l_loff_t l_start;
1081 l_loff_t l_len;
1082 l_pid_t l_pid;
1083 }
1084 #if defined(__amd64__) && defined(COMPAT_LINUX32)
1085 __packed
1086 #endif
1087 ;
1088
1089 static void
1090 linux_to_bsd_flock64(struct l_flock64 *linux_flock, struct flock *bsd_flock)
1091 {
1092 switch (linux_flock->l_type) {
1093 case LINUX_F_RDLCK:
1094 bsd_flock->l_type = F_RDLCK;
1095 break;
1096 case LINUX_F_WRLCK:
1097 bsd_flock->l_type = F_WRLCK;
1098 break;
1099 case LINUX_F_UNLCK:
1100 bsd_flock->l_type = F_UNLCK;
1101 break;
1102 default:
1103 bsd_flock->l_type = -1;
1104 break;
1105 }
1106 bsd_flock->l_whence = linux_flock->l_whence;
1107 bsd_flock->l_start = (off_t)linux_flock->l_start;
1108 bsd_flock->l_len = (off_t)linux_flock->l_len;
1109 bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
1110 }
1111
1112 static void
1113 bsd_to_linux_flock64(struct flock *bsd_flock, struct l_flock64 *linux_flock)
1114 {
1115 switch (bsd_flock->l_type) {
1116 case F_RDLCK:
1117 linux_flock->l_type = LINUX_F_RDLCK;
1118 break;
1119 case F_WRLCK:
1120 linux_flock->l_type = LINUX_F_WRLCK;
1121 break;
1122 case F_UNLCK:
1123 linux_flock->l_type = LINUX_F_UNLCK;
1124 break;
1125 }
1126 linux_flock->l_whence = bsd_flock->l_whence;
1127 linux_flock->l_start = (l_loff_t)bsd_flock->l_start;
1128 linux_flock->l_len = (l_loff_t)bsd_flock->l_len;
1129 linux_flock->l_pid = (l_pid_t)bsd_flock->l_pid;
1130 }
1131 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
1132
1133 static int
1134 fcntl_common(struct thread *td, struct linux_fcntl64_args *args)
1135 {
1136 struct l_flock linux_flock;
1137 struct flock bsd_flock;
1138 struct file *fp;
1139 long arg;
1140 int error, result;
1141
1142 switch (args->cmd) {
1143 case LINUX_F_DUPFD:
1144 return (kern_fcntl(td, args->fd, F_DUPFD, args->arg));
1145
1146 case LINUX_F_GETFD:
1147 return (kern_fcntl(td, args->fd, F_GETFD, 0));
1148
1149 case LINUX_F_SETFD:
1150 return (kern_fcntl(td, args->fd, F_SETFD, args->arg));
1151
1152 case LINUX_F_GETFL:
1153 error = kern_fcntl(td, args->fd, F_GETFL, 0);
1154 result = td->td_retval[0];
1155 td->td_retval[0] = 0;
1156 if (result & O_RDONLY)
1157 td->td_retval[0] |= LINUX_O_RDONLY;
1158 if (result & O_WRONLY)
1159 td->td_retval[0] |= LINUX_O_WRONLY;
1160 if (result & O_RDWR)
1161 td->td_retval[0] |= LINUX_O_RDWR;
1162 if (result & O_NDELAY)
1163 td->td_retval[0] |= LINUX_O_NONBLOCK;
1164 if (result & O_APPEND)
1165 td->td_retval[0] |= LINUX_O_APPEND;
1166 if (result & O_FSYNC)
1167 td->td_retval[0] |= LINUX_O_SYNC;
1168 if (result & O_ASYNC)
1169 td->td_retval[0] |= LINUX_FASYNC;
1170 #ifdef LINUX_O_NOFOLLOW
1171 if (result & O_NOFOLLOW)
1172 td->td_retval[0] |= LINUX_O_NOFOLLOW;
1173 #endif
1174 #ifdef LINUX_O_DIRECT
1175 if (result & O_DIRECT)
1176 td->td_retval[0] |= LINUX_O_DIRECT;
1177 #endif
1178 return (error);
1179
1180 case LINUX_F_SETFL:
1181 arg = 0;
1182 if (args->arg & LINUX_O_NDELAY)
1183 arg |= O_NONBLOCK;
1184 if (args->arg & LINUX_O_APPEND)
1185 arg |= O_APPEND;
1186 if (args->arg & LINUX_O_SYNC)
1187 arg |= O_FSYNC;
1188 if (args->arg & LINUX_FASYNC)
1189 arg |= O_ASYNC;
1190 #ifdef LINUX_O_NOFOLLOW
1191 if (args->arg & LINUX_O_NOFOLLOW)
1192 arg |= O_NOFOLLOW;
1193 #endif
1194 #ifdef LINUX_O_DIRECT
1195 if (args->arg & LINUX_O_DIRECT)
1196 arg |= O_DIRECT;
1197 #endif
1198 return (kern_fcntl(td, args->fd, F_SETFL, arg));
1199
1200 case LINUX_F_GETLK:
1201 error = copyin((void *)args->arg, &linux_flock,
1202 sizeof(linux_flock));
1203 if (error)
1204 return (error);
1205 linux_to_bsd_flock(&linux_flock, &bsd_flock);
1206 error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock);
1207 if (error)
1208 return (error);
1209 bsd_to_linux_flock(&bsd_flock, &linux_flock);
1210 return (copyout(&linux_flock, (void *)args->arg,
1211 sizeof(linux_flock)));
1212
1213 case LINUX_F_SETLK:
1214 error = copyin((void *)args->arg, &linux_flock,
1215 sizeof(linux_flock));
1216 if (error)
1217 return (error);
1218 linux_to_bsd_flock(&linux_flock, &bsd_flock);
1219 return (kern_fcntl(td, args->fd, F_SETLK,
1220 (intptr_t)&bsd_flock));
1221
1222 case LINUX_F_SETLKW:
1223 error = copyin((void *)args->arg, &linux_flock,
1224 sizeof(linux_flock));
1225 if (error)
1226 return (error);
1227 linux_to_bsd_flock(&linux_flock, &bsd_flock);
1228 return (kern_fcntl(td, args->fd, F_SETLKW,
1229 (intptr_t)&bsd_flock));
1230
1231 case LINUX_F_GETOWN:
1232 return (kern_fcntl(td, args->fd, F_GETOWN, 0));
1233
1234 case LINUX_F_SETOWN:
1235 /*
1236 * XXX some Linux applications depend on F_SETOWN having no
1237 * significant effect for pipes (SIGIO is not delivered for
1238 * pipes under Linux-2.2.35 at least).
1239 */
1240 error = fget(td, args->fd, &fp);
1241 if (error)
1242 return (error);
1243 if (fp->f_type == DTYPE_PIPE) {
1244 fdrop(fp, td);
1245 return (EINVAL);
1246 }
1247 fdrop(fp, td);
1248
1249 return (kern_fcntl(td, args->fd, F_SETOWN, args->arg));
1250 }
1251
1252 return (EINVAL);
1253 }
1254
1255 int
1256 linux_fcntl(struct thread *td, struct linux_fcntl_args *args)
1257 {
1258 struct linux_fcntl64_args args64;
1259
1260 #ifdef DEBUG
1261 if (ldebug(fcntl))
1262 printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd);
1263 #endif
1264
1265 args64.fd = args->fd;
1266 args64.cmd = args->cmd;
1267 args64.arg = args->arg;
1268 return (fcntl_common(td, &args64));
1269 }
1270
1271 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
1272 int
1273 linux_fcntl64(struct thread *td, struct linux_fcntl64_args *args)
1274 {
1275 struct l_flock64 linux_flock;
1276 struct flock bsd_flock;
1277 int error;
1278
1279 #ifdef DEBUG
1280 if (ldebug(fcntl64))
1281 printf(ARGS(fcntl64, "%d, %08x, *"), args->fd, args->cmd);
1282 #endif
1283
1284 switch (args->cmd) {
1285 case LINUX_F_GETLK64:
1286 error = copyin((void *)args->arg, &linux_flock,
1287 sizeof(linux_flock));
1288 if (error)
1289 return (error);
1290 linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1291 error = kern_fcntl(td, args->fd, F_GETLK, (intptr_t)&bsd_flock);
1292 if (error)
1293 return (error);
1294 bsd_to_linux_flock64(&bsd_flock, &linux_flock);
1295 return (copyout(&linux_flock, (void *)args->arg,
1296 sizeof(linux_flock)));
1297
1298 case LINUX_F_SETLK64:
1299 error = copyin((void *)args->arg, &linux_flock,
1300 sizeof(linux_flock));
1301 if (error)
1302 return (error);
1303 linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1304 return (kern_fcntl(td, args->fd, F_SETLK,
1305 (intptr_t)&bsd_flock));
1306
1307 case LINUX_F_SETLKW64:
1308 error = copyin((void *)args->arg, &linux_flock,
1309 sizeof(linux_flock));
1310 if (error)
1311 return (error);
1312 linux_to_bsd_flock64(&linux_flock, &bsd_flock);
1313 return (kern_fcntl(td, args->fd, F_SETLKW,
1314 (intptr_t)&bsd_flock));
1315 }
1316
1317 return (fcntl_common(td, args));
1318 }
1319 #endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
1320
1321 int
1322 linux_chown(struct thread *td, struct linux_chown_args *args)
1323 {
1324 char *path;
1325 int error;
1326
1327 LCONVPATHEXIST(td, args->path, &path);
1328
1329 #ifdef DEBUG
1330 if (ldebug(chown))
1331 printf(ARGS(chown, "%s, %d, %d"), path, args->uid, args->gid);
1332 #endif
1333 error = kern_chown(td, path, UIO_SYSSPACE, args->uid, args->gid);
1334 LFREEPATH(path);
1335 return (error);
1336 }
1337
1338 int
1339 linux_lchown(struct thread *td, struct linux_lchown_args *args)
1340 {
1341 char *path;
1342 int error;
1343
1344 LCONVPATHEXIST(td, args->path, &path);
1345
1346 #ifdef DEBUG
1347 if (ldebug(lchown))
1348 printf(ARGS(lchown, "%s, %d, %d"), path, args->uid, args->gid);
1349 #endif
1350 error = kern_lchown(td, path, UIO_SYSSPACE, args->uid, args->gid);
1351 LFREEPATH(path);
1352 return (error);
1353 }
Cache object: 9794ffe425d8144d46c13d27047efcb3
|