xref: /freebsd/sys/compat/linux/linux_file.c (revision 5521ff5a4d1929056e7ffc982fac3341ca54df7c)
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 withough 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  * $FreeBSD$
29  */
30 
31 #include "opt_compat.h"
32 
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/conf.h>
36 #include <sys/dirent.h>
37 #include <sys/fcntl.h>
38 #include <sys/file.h>
39 #include <sys/filedesc.h>
40 #include <sys/lock.h>
41 #include <sys/malloc.h>
42 #include <sys/mount.h>
43 #include <sys/mutex.h>
44 #include <sys/proc.h>
45 #include <sys/sysproto.h>
46 #include <sys/tty.h>
47 #include <sys/vnode.h>
48 
49 #include <ufs/ufs/extattr.h>
50 #include <ufs/ufs/quota.h>
51 #include <ufs/ufs/ufsmount.h>
52 
53 #include <machine/../linux/linux.h>
54 #include <machine/../linux/linux_proto.h>
55 #include <compat/linux/linux_util.h>
56 
57 #ifndef __alpha__
58 int
59 linux_creat(struct proc *p, struct linux_creat_args *args)
60 {
61     struct open_args /* {
62 	char *path;
63 	int flags;
64 	int mode;
65     } */ bsd_open_args;
66     caddr_t sg;
67 
68     sg = stackgap_init();
69     CHECKALTCREAT(p, &sg, args->path);
70 
71 #ifdef DEBUG
72 	if (ldebug(creat))
73 		printf(ARGS(creat, "%s, %d"), args->path, args->mode);
74 #endif
75     bsd_open_args.path = args->path;
76     bsd_open_args.mode = args->mode;
77     bsd_open_args.flags = O_WRONLY | O_CREAT | O_TRUNC;
78     return open(p, &bsd_open_args);
79 }
80 #endif /*!__alpha__*/
81 
82 int
83 linux_open(struct proc *p, struct linux_open_args *args)
84 {
85     struct open_args /* {
86 	char *path;
87 	int flags;
88 	int mode;
89     } */ bsd_open_args;
90     int error;
91     caddr_t sg;
92 
93     sg = stackgap_init();
94 
95     if (args->flags & LINUX_O_CREAT)
96 	CHECKALTCREAT(p, &sg, args->path);
97     else
98 	CHECKALTEXIST(p, &sg, args->path);
99 
100 #ifdef DEBUG
101 	if (ldebug(open))
102 		printf(ARGS(open, "%s, 0x%x, 0x%x"),
103 		    args->path, args->flags, args->mode);
104 #endif
105     bsd_open_args.flags = 0;
106     if (args->flags & LINUX_O_RDONLY)
107 	bsd_open_args.flags |= O_RDONLY;
108     if (args->flags & LINUX_O_WRONLY)
109 	bsd_open_args.flags |= O_WRONLY;
110     if (args->flags & LINUX_O_RDWR)
111 	bsd_open_args.flags |= O_RDWR;
112     if (args->flags & LINUX_O_NDELAY)
113 	bsd_open_args.flags |= O_NONBLOCK;
114     if (args->flags & LINUX_O_APPEND)
115 	bsd_open_args.flags |= O_APPEND;
116     if (args->flags & LINUX_O_SYNC)
117 	bsd_open_args.flags |= O_FSYNC;
118     if (args->flags & LINUX_O_NONBLOCK)
119 	bsd_open_args.flags |= O_NONBLOCK;
120     if (args->flags & LINUX_FASYNC)
121 	bsd_open_args.flags |= O_ASYNC;
122     if (args->flags & LINUX_O_CREAT)
123 	bsd_open_args.flags |= O_CREAT;
124     if (args->flags & LINUX_O_TRUNC)
125 	bsd_open_args.flags |= O_TRUNC;
126     if (args->flags & LINUX_O_EXCL)
127 	bsd_open_args.flags |= O_EXCL;
128     if (args->flags & LINUX_O_NOCTTY)
129 	bsd_open_args.flags |= O_NOCTTY;
130     bsd_open_args.path = args->path;
131     bsd_open_args.mode = args->mode;
132 
133     error = open(p, &bsd_open_args);
134     PROC_LOCK(p);
135     if (!error && !(bsd_open_args.flags & O_NOCTTY) &&
136 	SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
137 	struct filedesc *fdp = p->p_fd;
138 	struct file *fp = fdp->fd_ofiles[p->p_retval[0]];
139 
140 	PROC_UNLOCK(p);
141 	if (fp->f_type == DTYPE_VNODE)
142 	    fo_ioctl(fp, TIOCSCTTY, (caddr_t) 0, p);
143     } else
144 	PROC_UNLOCK(p);
145 #ifdef DEBUG
146 	if (ldebug(open))
147 		printf(LMSG("open returns error %d"), error);
148 #endif
149     return error;
150 }
151 
152 struct linux_flock {
153     short l_type;
154     short l_whence;
155     linux_off_t l_start;
156     linux_off_t l_len;
157     linux_pid_t l_pid;
158 };
159 
160 static void
161 linux_to_bsd_flock(struct linux_flock *linux_flock, struct flock *bsd_flock)
162 {
163     switch (linux_flock->l_type) {
164     case LINUX_F_RDLCK:
165 	bsd_flock->l_type = F_RDLCK;
166 	break;
167     case LINUX_F_WRLCK:
168 	bsd_flock->l_type = F_WRLCK;
169 	break;
170     case LINUX_F_UNLCK:
171 	bsd_flock->l_type = F_UNLCK;
172 	break;
173     default:
174         bsd_flock->l_type = -1;
175         break;
176     }
177     bsd_flock->l_whence = linux_flock->l_whence;
178     bsd_flock->l_start = (off_t)linux_flock->l_start;
179     bsd_flock->l_len = (off_t)linux_flock->l_len;
180     bsd_flock->l_pid = (pid_t)linux_flock->l_pid;
181 }
182 
183 static void
184 bsd_to_linux_flock(struct flock *bsd_flock, struct linux_flock *linux_flock)
185 {
186     switch (bsd_flock->l_type) {
187     case F_RDLCK:
188 	linux_flock->l_type = LINUX_F_RDLCK;
189 	break;
190     case F_WRLCK:
191 	linux_flock->l_type = LINUX_F_WRLCK;
192 	break;
193     case F_UNLCK:
194 	linux_flock->l_type = LINUX_F_UNLCK;
195 	break;
196     }
197     linux_flock->l_whence = bsd_flock->l_whence;
198     linux_flock->l_start = (linux_off_t)bsd_flock->l_start;
199     linux_flock->l_len = (linux_off_t)bsd_flock->l_len;
200     linux_flock->l_pid = (linux_pid_t)bsd_flock->l_pid;
201 }
202 
203 int
204 linux_fcntl(struct proc *p, struct linux_fcntl_args *args)
205 {
206     int error, result;
207     struct fcntl_args /* {
208 	int fd;
209 	int cmd;
210 	long arg;
211     } */ fcntl_args;
212     struct linux_flock linux_flock;
213     struct flock *bsd_flock;
214     struct filedesc *fdp;
215     struct file *fp;
216     caddr_t sg;
217 
218     sg = stackgap_init();
219     bsd_flock = (struct flock *)stackgap_alloc(&sg, sizeof(struct flock));
220 
221 #ifdef DEBUG
222 	if (ldebug(fcntl))
223 		printf(ARGS(fcntl, "%d, %08x, *"), args->fd, args->cmd);
224 #endif
225     fcntl_args.fd = args->fd;
226 
227     switch (args->cmd) {
228     case LINUX_F_DUPFD:
229 	fcntl_args.cmd = F_DUPFD;
230 	fcntl_args.arg = args->arg;
231 	return fcntl(p, &fcntl_args);
232 
233     case LINUX_F_GETFD:
234 	fcntl_args.cmd = F_GETFD;
235 	return fcntl(p, &fcntl_args);
236 
237     case LINUX_F_SETFD:
238 	fcntl_args.cmd = F_SETFD;
239 	fcntl_args.arg = args->arg;
240 	return fcntl(p, &fcntl_args);
241 
242     case LINUX_F_GETFL:
243 	fcntl_args.cmd = F_GETFL;
244 	error = fcntl(p, &fcntl_args);
245 	result = p->p_retval[0];
246 	p->p_retval[0] = 0;
247 	if (result & O_RDONLY) p->p_retval[0] |= LINUX_O_RDONLY;
248 	if (result & O_WRONLY) p->p_retval[0] |= LINUX_O_WRONLY;
249 	if (result & O_RDWR) p->p_retval[0] |= LINUX_O_RDWR;
250 	if (result & O_NDELAY) p->p_retval[0] |= LINUX_O_NONBLOCK;
251 	if (result & O_APPEND) p->p_retval[0] |= LINUX_O_APPEND;
252 	if (result & O_FSYNC) p->p_retval[0] |= LINUX_O_SYNC;
253 	if (result & O_ASYNC) p->p_retval[0] |= LINUX_FASYNC;
254 	return error;
255 
256     case LINUX_F_SETFL:
257 	fcntl_args.arg = 0;
258 	if (args->arg & LINUX_O_NDELAY) fcntl_args.arg |= O_NONBLOCK;
259 	if (args->arg & LINUX_O_APPEND) fcntl_args.arg |= O_APPEND;
260 	if (args->arg & LINUX_O_SYNC) fcntl_args.arg |= O_FSYNC;
261 	if (args->arg & LINUX_FASYNC) fcntl_args.arg |= O_ASYNC;
262 	fcntl_args.cmd = F_SETFL;
263 	return fcntl(p, &fcntl_args);
264 
265     case LINUX_F_GETLK:
266 	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
267 		   	    sizeof(struct linux_flock))))
268 	    return error;
269 	linux_to_bsd_flock(&linux_flock, bsd_flock);
270 	fcntl_args.cmd = F_GETLK;
271 	fcntl_args.arg = (long)bsd_flock;
272 	error = fcntl(p, &fcntl_args);
273 	if (error)
274 	    return error;
275 	bsd_to_linux_flock(bsd_flock, &linux_flock);
276 	return copyout((caddr_t)&linux_flock, (caddr_t)args->arg,
277 		       sizeof(struct linux_flock));
278 
279     case LINUX_F_SETLK:
280 	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
281 		   	    sizeof(struct linux_flock))))
282 	    return error;
283 	linux_to_bsd_flock(&linux_flock, bsd_flock);
284 	fcntl_args.cmd = F_SETLK;
285 	fcntl_args.arg = (long)bsd_flock;
286 	return fcntl(p, &fcntl_args);
287 
288     case LINUX_F_SETLKW:
289 	if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock,
290 		   	    sizeof(struct linux_flock))))
291 	    return error;
292 	linux_to_bsd_flock(&linux_flock, bsd_flock);
293 	fcntl_args.cmd = F_SETLKW;
294 	fcntl_args.arg = (long)bsd_flock;
295 	return fcntl(p, &fcntl_args);
296 
297     case LINUX_F_GETOWN:
298 	fcntl_args.cmd = F_GETOWN;
299 	return fcntl(p, &fcntl_args);
300 
301     case LINUX_F_SETOWN:
302 	/*
303 	 * XXX some Linux applications depend on F_SETOWN having no
304 	 * significant effect for pipes (SIGIO is not delivered for
305 	 * pipes under Linux-2.2.35 at least).
306 	 */
307 	fdp = p->p_fd;
308 	if ((u_int)args->fd >= fdp->fd_nfiles ||
309 	  (fp = fdp->fd_ofiles[args->fd]) == NULL)
310 	    return EBADF;
311 	if (fp->f_type == DTYPE_PIPE)
312 	    return EINVAL;
313 
314  	fcntl_args.cmd = F_SETOWN;
315 	fcntl_args.arg = args->arg;
316 	return fcntl(p, &fcntl_args);
317     }
318     return EINVAL;
319 }
320 
321 int
322 linux_lseek(struct proc *p, struct linux_lseek_args *args)
323 {
324 
325     struct lseek_args /* {
326 	int fd;
327 	int pad;
328 	off_t offset;
329 	int whence;
330     } */ tmp_args;
331     int error;
332 
333 #ifdef DEBUG
334 	if (ldebug(lseek))
335 		printf(ARGS(lseek, "%d, %ld, %d"),
336 		    args->fdes, args->off, args->whence);
337 #endif
338     tmp_args.fd = args->fdes;
339     tmp_args.offset = (off_t)args->off;
340     tmp_args.whence = args->whence;
341     error = lseek(p, &tmp_args);
342     return error;
343 }
344 
345 #ifndef __alpha__
346 int
347 linux_llseek(struct proc *p, struct linux_llseek_args *args)
348 {
349 	struct lseek_args bsd_args;
350 	int error;
351 	off_t off;
352 
353 #ifdef DEBUG
354 	if (ldebug(llseek))
355 		printf(ARGS(llseek, "%d, %d:%d, %d"),
356 		    args->fd, args->ohigh, args->olow, args->whence);
357 #endif
358 	off = (args->olow) | (((off_t) args->ohigh) << 32);
359 
360 	bsd_args.fd = args->fd;
361 	bsd_args.offset = off;
362 	bsd_args.whence = args->whence;
363 
364 	if ((error = lseek(p, &bsd_args)))
365 		return error;
366 
367 	if ((error = copyout(p->p_retval, (caddr_t)args->res, sizeof (off_t))))
368 		return error;
369 
370 	p->p_retval[0] = 0;
371 	return 0;
372 }
373 #endif /*!__alpha__*/
374 
375 
376 struct linux_dirent {
377     long dino;
378     linux_off_t doff;
379     unsigned short dreclen;
380     char dname[LINUX_NAME_MAX + 1];
381 };
382 
383 #define LINUX_RECLEN(de,namlen) \
384     ALIGN((((char *)&(de)->dname - (char *)de) + (namlen) + 1))
385 
386 #ifndef __alpha__
387 int
388 linux_readdir(struct proc *p, struct linux_readdir_args *args)
389 {
390 	struct linux_getdents_args lda;
391 
392 	lda.fd = args->fd;
393 	lda.dent = args->dent;
394 	lda.count = 1;
395 	return linux_getdents(p, &lda);
396 }
397 #endif /*!__alpha__*/
398 
399 int
400 linux_getdents(struct proc *p, struct linux_getdents_args *args)
401 {
402     register struct dirent *bdp;
403     struct vnode *vp;
404     caddr_t inp, buf;		/* BSD-format */
405     int len, reclen;		/* BSD-format */
406     caddr_t outp;		/* Linux-format */
407     int resid, linuxreclen=0;	/* Linux-format */
408     struct file *fp;
409     struct uio auio;
410     struct iovec aiov;
411     struct vattr va;
412     off_t off;
413     struct linux_dirent linux_dirent;
414     int buflen, error, eofflag, nbytes, justone;
415     u_long *cookies = NULL, *cookiep;
416     int ncookies;
417 
418 #ifdef DEBUG
419 	if (ldebug(getdents))
420 		printf(ARGS(getdents, "%d, *, %d"), args->fd, args->count);
421 #endif
422     if ((error = getvnode(p->p_fd, args->fd, &fp)) != 0) {
423 	return (error);
424     }
425 
426     if ((fp->f_flag & FREAD) == 0)
427 	return (EBADF);
428 
429     vp = (struct vnode *) fp->f_data;
430 
431     if (vp->v_type != VDIR)
432 	return (EINVAL);
433 
434     if ((error = VOP_GETATTR(vp, &va, p->p_ucred, p))) {
435 	return error;
436     }
437 
438     nbytes = args->count;
439     if (nbytes == 1) {
440 	nbytes = sizeof (struct linux_dirent);
441 	justone = 1;
442     }
443     else
444 	justone = 0;
445 
446     off = fp->f_offset;
447 #define	DIRBLKSIZ	512		/* XXX we used to use ufs's DIRBLKSIZ */
448     buflen = max(DIRBLKSIZ, nbytes);
449     buflen = min(buflen, MAXBSIZE);
450     buf = malloc(buflen, M_TEMP, M_WAITOK);
451     vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p);
452 again:
453     aiov.iov_base = buf;
454     aiov.iov_len = buflen;
455     auio.uio_iov = &aiov;
456     auio.uio_iovcnt = 1;
457     auio.uio_rw = UIO_READ;
458     auio.uio_segflg = UIO_SYSSPACE;
459     auio.uio_procp = p;
460     auio.uio_resid = buflen;
461     auio.uio_offset = off;
462 
463     if (cookies) {
464 	free(cookies, M_TEMP);
465 	cookies = NULL;
466     }
467 
468     error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, &ncookies, &cookies);
469     if (error) {
470 	goto out;
471     }
472 
473     inp = buf;
474     outp = (caddr_t) args->dent;
475     resid = nbytes;
476     if ((len = buflen - auio.uio_resid) <= 0) {
477 	goto eof;
478     }
479 
480     cookiep = cookies;
481 
482     if (cookies) {
483 	/*
484 	 * When using cookies, the vfs has the option of reading from
485 	 * a different offset than that supplied (UFS truncates the
486 	 * offset to a block boundary to make sure that it never reads
487 	 * partway through a directory entry, even if the directory
488 	 * has been compacted).
489 	 */
490 	while (len > 0 && ncookies > 0 && *cookiep <= off) {
491 	    bdp = (struct dirent *) inp;
492 	    len -= bdp->d_reclen;
493 	    inp += bdp->d_reclen;
494 	    cookiep++;
495 	    ncookies--;
496 	}
497     }
498 
499     while (len > 0) {
500 	if (cookiep && ncookies == 0)
501 	    break;
502 	bdp = (struct dirent *) inp;
503 	reclen = bdp->d_reclen;
504 	if (reclen & 3) {
505 	    printf("linux_readdir: reclen=%d\n", reclen);
506 	    error = EFAULT;
507 	    goto out;
508 	}
509 
510 	if (bdp->d_fileno == 0) {
511 	    inp += reclen;
512 	    if (cookiep) {
513 		off = *cookiep++;
514 		ncookies--;
515 	    } else
516 		off += reclen;
517 	    len -= reclen;
518 	    continue;
519 	}
520 	linuxreclen = LINUX_RECLEN(&linux_dirent, bdp->d_namlen);
521 	if (reclen > len || resid < linuxreclen) {
522 	    outp++;
523 	    break;
524 	}
525 	linux_dirent.dino = (long) bdp->d_fileno;
526 	if (justone) {
527 	    /*
528 	     * old linux-style readdir usage.
529 	     */
530 	    linux_dirent.doff = (linux_off_t) linuxreclen;
531 	    linux_dirent.dreclen = (u_short) bdp->d_namlen;
532 	} else {
533 	    if (cookiep)
534 		linux_dirent.doff = (linux_off_t)*cookiep;
535 	    else
536 		linux_dirent.doff = (linux_off_t)(off + reclen);
537 	    linux_dirent.dreclen = (u_short) linuxreclen;
538 	}
539 	strcpy(linux_dirent.dname, bdp->d_name);
540 	if ((error = copyout((caddr_t)&linux_dirent, outp, linuxreclen))) {
541 	    goto out;
542 	}
543 	inp += reclen;
544 	if (cookiep) {
545 	    off = *cookiep++;
546 	    ncookies--;
547 	} else
548 	    off += reclen;
549 	outp += linuxreclen;
550 	resid -= linuxreclen;
551 	len -= reclen;
552 	if (justone)
553 	    break;
554     }
555 
556     if (outp == (caddr_t) args->dent)
557 	goto again;
558     fp->f_offset = off;
559 
560     if (justone)
561 	nbytes = resid + linuxreclen;
562 
563 eof:
564     p->p_retval[0] = nbytes - resid;
565 out:
566     if (cookies)
567 	free(cookies, M_TEMP);
568     VOP_UNLOCK(vp, 0, p);
569     free(buf, M_TEMP);
570     return error;
571 }
572 
573 /*
574  * These exist mainly for hooks for doing /compat/linux translation.
575  */
576 
577 int
578 linux_access(struct proc *p, struct linux_access_args *args)
579 {
580 	struct access_args bsd;
581 	caddr_t sg;
582 
583 	sg = stackgap_init();
584 	CHECKALTEXIST(p, &sg, args->path);
585 
586 #ifdef DEBUG
587 	if (ldebug(access))
588 		printf(ARGS(access, "%s, %d"), args->path, args->flags);
589 #endif
590 	bsd.path = args->path;
591 	bsd.flags = args->flags;
592 
593 	return access(p, &bsd);
594 }
595 
596 int
597 linux_unlink(struct proc *p, struct linux_unlink_args *args)
598 {
599 	struct unlink_args bsd;
600 	caddr_t sg;
601 
602 	sg = stackgap_init();
603 	CHECKALTEXIST(p, &sg, args->path);
604 
605 #ifdef DEBUG
606 	if (ldebug(unlink))
607 		printf(ARGS(unlink, "%s"), args->path);
608 #endif
609 	bsd.path = args->path;
610 
611 	return unlink(p, &bsd);
612 }
613 
614 int
615 linux_chdir(struct proc *p, struct linux_chdir_args *args)
616 {
617 	struct chdir_args bsd;
618 	caddr_t sg;
619 
620 	sg = stackgap_init();
621 	CHECKALTEXIST(p, &sg, args->path);
622 
623 #ifdef DEBUG
624 	if (ldebug(chdir))
625 		printf(ARGS(chdir, "%s"), args->path);
626 #endif
627 	bsd.path = args->path;
628 
629 	return chdir(p, &bsd);
630 }
631 
632 int
633 linux_chmod(struct proc *p, struct linux_chmod_args *args)
634 {
635 	struct chmod_args bsd;
636 	caddr_t sg;
637 
638 	sg = stackgap_init();
639 	CHECKALTEXIST(p, &sg, args->path);
640 
641 #ifdef DEBUG
642 	if (ldebug(chmod))
643 		printf(ARGS(chmod, "%s, %d"), args->path, args->mode);
644 #endif
645 	bsd.path = args->path;
646 	bsd.mode = args->mode;
647 
648 	return chmod(p, &bsd);
649 }
650 
651 int
652 linux_chown(struct proc *p, struct linux_chown_args *args)
653 {
654 	struct chown_args bsd;
655 	caddr_t sg;
656 
657 	sg = stackgap_init();
658 	CHECKALTEXIST(p, &sg, args->path);
659 
660 #ifdef DEBUG
661 	if (ldebug(chown))
662 		printf(ARGS(chown, "%s, %d, %d"),
663 		    args->path, args->uid, args->gid);
664 #endif
665 	bsd.path = args->path;
666 	/* XXX size casts here */
667 	bsd.uid = args->uid;
668 	bsd.gid = args->gid;
669 
670 	return chown(p, &bsd);
671 }
672 
673 int
674 linux_lchown(struct proc *p, struct linux_lchown_args *args)
675 {
676 	struct lchown_args bsd;
677 	caddr_t sg;
678 
679 	sg = stackgap_init();
680 	CHECKALTEXIST(p, &sg, args->path);
681 
682 #ifdef DEBUG
683 	if (ldebug(lchown))
684 		printf(ARGS(lchown, "%s, %d, %d"),
685 		    args->path, args->uid, args->gid);
686 #endif
687 	bsd.path = args->path;
688 	/* XXX size casts here */
689 	bsd.uid = args->uid;
690 	bsd.gid = args->gid;
691 
692 	return lchown(p, &bsd);
693 }
694 
695 int
696 linux_mkdir(struct proc *p, struct linux_mkdir_args *args)
697 {
698 	struct mkdir_args bsd;
699 	caddr_t sg;
700 
701 	sg = stackgap_init();
702 	CHECKALTCREAT(p, &sg, args->path);
703 
704 #ifdef DEBUG
705 	if (ldebug(mkdir))
706 		printf(ARGS(mkdir, "%s, %d"), args->path, args->mode);
707 #endif
708 	bsd.path = args->path;
709 	bsd.mode = args->mode;
710 
711 	return mkdir(p, &bsd);
712 }
713 
714 int
715 linux_rmdir(struct proc *p, struct linux_rmdir_args *args)
716 {
717 	struct rmdir_args bsd;
718 	caddr_t sg;
719 
720 	sg = stackgap_init();
721 	CHECKALTEXIST(p, &sg, args->path);
722 
723 #ifdef DEBUG
724 	if (ldebug(rmdir))
725 		printf(ARGS(rmdir, "%s"), args->path);
726 #endif
727 	bsd.path = args->path;
728 
729 	return rmdir(p, &bsd);
730 }
731 
732 int
733 linux_rename(struct proc *p, struct linux_rename_args *args)
734 {
735 	struct rename_args bsd;
736 	caddr_t sg;
737 
738 	sg = stackgap_init();
739 	CHECKALTEXIST(p, &sg, args->from);
740 	CHECKALTCREAT(p, &sg, args->to);
741 
742 #ifdef DEBUG
743 	if (ldebug(rename))
744 		printf(ARGS(rename, "%s, %s"), args->from, args->to);
745 #endif
746 	bsd.from = args->from;
747 	bsd.to = args->to;
748 
749 	return rename(p, &bsd);
750 }
751 
752 int
753 linux_symlink(struct proc *p, struct linux_symlink_args *args)
754 {
755 	struct symlink_args bsd;
756 	caddr_t sg;
757 
758 	sg = stackgap_init();
759 	CHECKALTEXIST(p, &sg, args->path);
760 	CHECKALTCREAT(p, &sg, args->to);
761 
762 #ifdef DEBUG
763 	if (ldebug(symlink))
764 		printf(ARGS(symlink, "%s, %s"), args->path, args->to);
765 #endif
766 	bsd.path = args->path;
767 	bsd.link = args->to;
768 
769 	return symlink(p, &bsd);
770 }
771 
772 int
773 linux_readlink(struct proc *p, struct linux_readlink_args *args)
774 {
775 	struct readlink_args bsd;
776 	caddr_t sg;
777 
778 	sg = stackgap_init();
779 	CHECKALTEXIST(p, &sg, args->name);
780 
781 #ifdef DEBUG
782 	if (ldebug(readlink))
783 		printf(ARGS(readlink, "%s, %p, %d"),
784 		    args->name, (void *)args->buf, args->count);
785 #endif
786 	bsd.path = args->name;
787 	bsd.buf = args->buf;
788 	bsd.count = args->count;
789 
790 	return readlink(p, &bsd);
791 }
792 
793 int
794 linux_truncate(struct proc *p, struct linux_truncate_args *args)
795 {
796 	struct truncate_args bsd;
797 	caddr_t sg;
798 
799 	sg = stackgap_init();
800 	CHECKALTEXIST(p, &sg, args->path);
801 
802 #ifdef DEBUG
803 	if (ldebug(truncate))
804 		printf(ARGS(truncate, "%s, %ld"), args->path, args->length);
805 #endif
806 	bsd.path = args->path;
807 	bsd.length = args->length;
808 
809 	return truncate(p, &bsd);
810 }
811 
812 int
813 linux_link(struct proc *p, struct linux_link_args *args)
814 {
815     struct link_args bsd;
816     caddr_t sg;
817 
818     sg = stackgap_init();
819     CHECKALTEXIST(p, &sg, args->path);
820     CHECKALTCREAT(p, &sg, args->to);
821 
822 #ifdef DEBUG
823 	if (ldebug(link))
824 		printf(ARGS(link, "%s, %s"), args->path, args->to);
825 #endif
826 
827     bsd.path = args->path;
828     bsd.link = args->to;
829 
830     return link(p, &bsd);
831 }
832 
833 int
834 linux_getcwd(struct proc *p, struct linux_getcwd_args *args)
835 {
836 	struct __getcwd_args bsd;
837 	caddr_t sg;
838 	int error, len;
839 
840 #ifdef DEBUG
841 	if (ldebug(getcwd))
842 		printf(ARGS(getcwd, "%p, %ld"), args->buf, args->bufsize);
843 #endif
844 
845 	sg = stackgap_init();
846 	bsd.buf = stackgap_alloc(&sg, SPARE_USRSPACE);
847 	bsd.buflen = SPARE_USRSPACE;
848 	error = __getcwd(p, &bsd);
849 	if (!error) {
850 		len = strlen(bsd.buf) + 1;
851 		if (len <= args->bufsize) {
852 			p->p_retval[0] = len;
853 			error = copyout(bsd.buf, args->buf, len);
854 		}
855 		else
856 			error = ERANGE;
857 	}
858 	return (error);
859 }
860 
861 #ifndef __alpha__
862 int
863 linux_fdatasync(p, uap)
864 	struct proc *p;
865 	struct linux_fdatasync_args *uap;
866 {
867 	struct fsync_args bsd;
868 
869 	bsd.fd = uap->fd;
870 	return fsync(p, &bsd);
871 }
872 #endif /*!__alpha__*/
873 
874 int
875 linux_pread(p, uap)
876 	struct proc *p;
877 	struct linux_pread_args *uap;
878 {
879 	struct pread_args bsd;
880 
881 	bsd.fd = uap->fd;
882 	bsd.buf = uap->buf;
883 	bsd.nbyte = uap->nbyte;
884 	bsd.offset = uap->offset;
885 	return pread(p, &bsd);
886 }
887 
888 int
889 linux_pwrite(p, uap)
890 	struct proc *p;
891 	struct linux_pwrite_args *uap;
892 {
893 	struct pwrite_args bsd;
894 
895 	bsd.fd = uap->fd;
896 	bsd.buf = uap->buf;
897 	bsd.nbyte = uap->nbyte;
898 	bsd.offset = uap->offset;
899 	return pwrite(p, &bsd);
900 }
901 
902 int
903 linux_mount(struct proc *p, struct linux_mount_args *args)
904 {
905 	struct ufs_args ufs;
906         char fstypename[MFSNAMELEN];
907         char mntonname[MNAMELEN], mntfromname[MNAMELEN];
908 	int error;
909 	int fsflags;
910 	const char *fstype;
911 	void *fsdata;
912 
913         error = copyinstr(args->filesystemtype, fstypename, MFSNAMELEN - 1,
914 	    NULL);
915 	if (error)
916                 return (error);
917         error = copyinstr(args->specialfile, mntfromname, MFSNAMELEN - 1, NULL);
918 	if (error)
919                 return (error);
920         error = copyinstr(args->dir, mntonname, MFSNAMELEN - 1, NULL);
921 	if (error)
922                 return (error);
923 
924 #ifdef DEBUG
925 	if (ldebug(mount))
926 		printf(ARGS(mount, "%s, %s, %s"),
927 		    fstypename, mntfromname, mntonname);
928 #endif
929 
930 	if (strcmp(fstypename, "ext2") == 0) {
931 		fstype = "ext2fs";
932 		fsdata = &ufs;
933 		ufs.fspec = mntfromname;
934 #define DEFAULT_ROOTID		-2
935 		ufs.export.ex_root = DEFAULT_ROOTID;
936 		ufs.export.ex_flags =
937 		    args->rwflag & LINUX_MS_RDONLY ? MNT_EXRDONLY : 0;
938 	} else if (strcmp(fstypename, "proc") == 0) {
939 		fstype = "linprocfs";
940 		fsdata = NULL;
941 	} else {
942 		return (ENODEV);
943 	}
944 
945 	fsflags = 0;
946 
947 	if ((args->rwflag & 0xffff0000) == 0xc0ed0000) {
948 		/*
949 		 * Linux SYNC flag is not included; the closest equivalent
950 		 * FreeBSD has is !ASYNC, which is our default.
951 		 */
952 		if (args->rwflag & LINUX_MS_RDONLY)
953 			fsflags |= MNT_RDONLY;
954 		if (args->rwflag & LINUX_MS_NOSUID)
955 			fsflags |= MNT_NOSUID;
956 		if (args->rwflag & LINUX_MS_NODEV)
957 			fsflags |= MNT_NODEV;
958 		if (args->rwflag & LINUX_MS_NOEXEC)
959 			fsflags |= MNT_NOEXEC;
960 		if (args->rwflag & LINUX_MS_REMOUNT)
961 			fsflags |= MNT_UPDATE;
962 	}
963 
964 	return (vfs_mount(p, fstype, mntonname, fsflags, fsdata));
965 }
966 
967 int
968 linux_umount(struct proc *p, struct linux_umount_args *args)
969 {
970 	struct linux_umount2_args args2;
971 
972 	args2.path = args->path;
973 	args2.flags = 0;
974 	return (linux_umount2(p, &args2));
975 }
976 
977 int
978 linux_umount2(struct proc *p, struct linux_umount2_args *args)
979 {
980 	struct unmount_args bsd;
981 
982 	bsd.path = args->path;
983 	bsd.flags = args->flags;	/* XXX correct? */
984 	return (unmount(p, &bsd));
985 }
986