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