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