linux_file.c revision 1.10 1 /* $NetBSD: linux_file.c,v 1.10 1995/09/07 21:48:59 fvdl Exp $ */
2
3 /*
4 * Copyright (c) 1995 Frank van der Linden
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed for the NetBSD Project
18 * by Frank van der Linden
19 * 4. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/namei.h>
37 #include <sys/proc.h>
38 #include <sys/file.h>
39 #include <sys/stat.h>
40 #include <sys/filedesc.h>
41 #include <sys/ioctl.h>
42 #include <sys/kernel.h>
43 #include <sys/mount.h>
44 #include <sys/malloc.h>
45
46 #include <sys/syscallargs.h>
47
48 #include <compat/linux/linux_types.h>
49 #include <compat/linux/linux_signal.h>
50 #include <compat/linux/linux_syscallargs.h>
51 #include <compat/linux/linux_fcntl.h>
52 #include <compat/linux/linux_util.h>
53
54 /*
55 * Some file-related calls are handled here. The usual flag conversion
56 * an structure conversion is done, and alternate emul path searching.
57 */
58
59 /*
60 * The next two functions convert between the Linux and NetBSD values
61 * of the flags used in open(2) and fcntl(2).
62 */
63 static int
64 linux_to_bsd_ioflags(int lflags)
65 {
66 int res = 0;
67
68 res |= cvtto_bsd_mask(lflags, LINUX_O_WRONLY, O_WRONLY);
69 res |= cvtto_bsd_mask(lflags, LINUX_O_RDONLY, O_RDONLY);
70 res |= cvtto_bsd_mask(lflags, LINUX_O_RDWR, O_RDWR);
71 res |= cvtto_bsd_mask(lflags, LINUX_O_CREAT, O_CREAT);
72 res |= cvtto_bsd_mask(lflags, LINUX_O_EXCL, O_EXCL);
73 res |= cvtto_bsd_mask(lflags, LINUX_O_NOCTTY, O_NOCTTY);
74 res |= cvtto_bsd_mask(lflags, LINUX_O_TRUNC, O_TRUNC);
75 res |= cvtto_bsd_mask(lflags, LINUX_O_NDELAY, O_NDELAY);
76 res |= cvtto_bsd_mask(lflags, LINUX_O_SYNC, O_FSYNC);
77 res |= cvtto_bsd_mask(lflags, LINUX_FASYNC, O_ASYNC);
78 res |= cvtto_bsd_mask(lflags, LINUX_O_APPEND, O_APPEND);
79
80 return res;
81 }
82
83 static int
84 bsd_to_linux_ioflags(int bflags)
85 {
86 int res = 0;
87
88 res |= cvtto_linux_mask(bflags, O_WRONLY, LINUX_O_WRONLY);
89 res |= cvtto_linux_mask(bflags, O_RDONLY, LINUX_O_RDONLY);
90 res |= cvtto_linux_mask(bflags, O_RDWR, LINUX_O_RDWR);
91 res |= cvtto_linux_mask(bflags, O_CREAT, LINUX_O_CREAT);
92 res |= cvtto_linux_mask(bflags, O_EXCL, LINUX_O_EXCL);
93 res |= cvtto_linux_mask(bflags, O_NOCTTY, LINUX_O_NOCTTY);
94 res |= cvtto_linux_mask(bflags, O_TRUNC, LINUX_O_TRUNC);
95 res |= cvtto_linux_mask(bflags, O_NDELAY, LINUX_O_NDELAY);
96 res |= cvtto_linux_mask(bflags, O_FSYNC, LINUX_O_SYNC);
97 res |= cvtto_linux_mask(bflags, O_ASYNC, LINUX_FASYNC);
98 res |= cvtto_linux_mask(bflags, O_APPEND, LINUX_O_APPEND);
99
100 return res;
101 }
102
103 /*
104 * creat(2) is an obsolete function, but it's present as a Linux
105 * system call, so let's deal with it.
106 *
107 * Just call open(2) with the TRUNC, CREAT and WRONLY flags.
108 */
109 int
110 linux_creat(p, uap, retval)
111 struct proc *p;
112 struct linux_creat_args /* {
113 syscallarg(char *) path;
114 syscallarg(int) mode;
115 } */ *uap;
116 register_t *retval;
117 {
118 struct open_args oa;
119 caddr_t sg;
120
121 sg = stackgap_init(p->p_emul);
122 LINUX_CHECK_ALT_CREAT(p, &sg, SCARG(uap, path));
123
124 SCARG(&oa, path) = SCARG(uap, path);
125 SCARG(&oa, flags) = O_CREAT | O_TRUNC | O_WRONLY;
126 SCARG(&oa, mode) = SCARG(uap, mode);
127 return open(p, &oa, retval);
128 }
129
130 /*
131 * open(2). Take care of the different flag values, and let the
132 * NetBSD syscall do the real work. See if this operation
133 * gives the current process a controlling terminal.
134 * (XXX is this necessary?)
135 */
136 int
137 linux_open(p, uap, retval)
138 struct proc *p;
139 struct linux_open_args /* {
140 syscallarg(char *) path;
141 syscallarg(int) flags;
142 syscallarg(int) mode;
143 } */ *uap;
144 register_t *retval;
145 {
146 int error, fl;
147 struct open_args boa;
148 caddr_t sg;
149
150 sg = stackgap_init(p->p_emul);
151
152 fl = linux_to_bsd_ioflags(SCARG(uap, flags));
153
154 if (fl & O_CREAT)
155 LINUX_CHECK_ALT_CREAT(p, &sg, SCARG(uap, path));
156 else
157 LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
158
159 SCARG(&boa, path) = SCARG(uap, path);
160 SCARG(&boa, flags) = fl;
161 SCARG(&boa, mode) = SCARG(uap, mode);
162
163 if ((error = open(p, &boa, retval)))
164 return error;
165
166 /*
167 * this bit from sunos_misc.c (and svr4_fcntl.c).
168 * If we are a session leader, and we don't have a controlling
169 * terminal yet, and the O_NOCTTY flag is not set, try to make
170 * this the controlling terminal.
171 */
172 if (!(fl & O_NOCTTY) && SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
173 struct filedesc *fdp = p->p_fd;
174 struct file *fp = fdp->fd_ofiles[*retval];
175
176 /* ignore any error, just give it a try */
177 if (fp->f_type == DTYPE_VNODE)
178 (fp->f_ops->fo_ioctl) (fp, TIOCSCTTY, (caddr_t) 0, p);
179 }
180 return 0;
181 }
182
183 /*
184 * This appears to be part of a Linux attempt to switch to 64 bits file sizes.
185 */
186 int
187 linux_llseek(p, uap, retval)
188 struct proc *p;
189 struct linux_llseek_args /* {
190 syscallarg(int) fd;
191 syscallarg(uint32_t) ohigh;
192 syscallarg(uint32_t) olow;
193 syscallarg(caddr_t) res;
194 syscallarg(int) whence;
195 } */ *uap;
196 register_t *retval;
197 {
198 struct lseek_args bla;
199 int error;
200 off_t off;
201
202 off = SCARG(uap, olow) | (((off_t) SCARG(uap, ohigh)) << 32);
203
204 SCARG(&bla, fd) = SCARG(uap, fd);
205 SCARG(&bla, offset) = off;
206 SCARG(&bla, whence) = SCARG(uap, whence);
207
208 if ((error = lseek(p, &bla, retval)))
209 return error;
210
211 if ((error = copyout(retval, SCARG(uap, res), sizeof (off_t))))
212 return error;
213
214 retval[0] = 0;
215 return 0;
216 }
217
218 /*
219 * The next two functions take care of converting the flock
220 * structure back and forth between Linux and NetBSD format.
221 * The only difference in the structures is the order of
222 * the fields, and the 'whence' value.
223 */
224 static void
225 bsd_to_linux_flock(bfp, lfp)
226 struct flock *bfp;
227 struct linux_flock *lfp;
228 {
229 lfp->l_start = bfp->l_start;
230 lfp->l_len = bfp->l_len;
231 lfp->l_pid = bfp->l_pid;
232 lfp->l_whence = bfp->l_whence;
233 switch (bfp->l_type) {
234 case F_RDLCK:
235 lfp->l_type = LINUX_F_RDLCK;
236 break;
237 case F_UNLCK:
238 lfp->l_type = LINUX_F_UNLCK;
239 break;
240 case F_WRLCK:
241 lfp->l_type = LINUX_F_WRLCK;
242 break;
243 }
244 }
245
246 static void
247 linux_to_bsd_flock(lfp, bfp)
248 struct linux_flock *lfp;
249 struct flock *bfp;
250 {
251 bfp->l_start = lfp->l_start;
252 bfp->l_len = lfp->l_len;
253 bfp->l_pid = lfp->l_pid;
254 bfp->l_whence = lfp->l_whence;
255 switch (lfp->l_type) {
256 case LINUX_F_RDLCK:
257 bfp->l_type = F_RDLCK;
258 break;
259 case LINUX_F_UNLCK:
260 bfp->l_type = F_UNLCK;
261 break;
262 case LINUX_F_WRLCK:
263 bfp->l_type = F_WRLCK;
264 break;
265 }
266 }
267
268 /*
269 * Most actions in the fcntl() call are straightforward; simply
270 * pass control to the NetBSD system call. A few commands need
271 * conversions after the actual system call has done its work,
272 * because the flag values and lock structure are different.
273 */
274 int
275 linux_fcntl(p, uap, retval)
276 struct proc *p;
277 struct linux_fcntl_args /* {
278 syscallarg(int) fd;
279 syscallarg(int) cmd;
280 syscallarg(void *) arg;
281 } */ *uap;
282 register_t *retval;
283 {
284 int fd, cmd, error, val;
285 caddr_t arg, sg;
286 struct linux_flock lfl;
287 struct flock *bfp, bfl;
288 struct fcntl_args fca;
289
290 fd = SCARG(uap, fd);
291 cmd = SCARG(uap, cmd);
292 arg = (caddr_t) SCARG(uap, arg);
293
294 switch (cmd) {
295 case LINUX_F_DUPFD:
296 cmd = F_DUPFD;
297 break;
298 case LINUX_F_GETFD:
299 cmd = F_GETFD;
300 break;
301 case LINUX_F_SETFD:
302 cmd = F_SETFD;
303 break;
304 case LINUX_F_GETFL:
305 SCARG(&fca, fd) = fd;
306 SCARG(&fca, cmd) = F_GETFL;
307 SCARG(&fca, arg) = arg;
308 if ((error = fcntl(p, &fca, retval)))
309 return error;
310 retval[0] = bsd_to_linux_ioflags(retval[0]);
311 return 0;
312 case LINUX_F_SETFL:
313 val = linux_to_bsd_ioflags((int)SCARG(uap, arg));
314 SCARG(&fca, fd) = fd;
315 SCARG(&fca, cmd) = F_SETFL;
316 SCARG(&fca, arg) = (caddr_t) val;
317 return fcntl(p, &fca, retval);
318 case LINUX_F_GETLK:
319 sg = stackgap_init(p->p_emul);
320 bfp = (struct flock *) stackgap_alloc(&sg, sizeof *bfp);
321 SCARG(&fca, fd) = fd;
322 SCARG(&fca, cmd) = F_GETLK;
323 SCARG(&fca, arg) = bfp;
324 if ((error = fcntl(p, &fca, retval)))
325 return error;
326 if ((error = copyin(bfp, &bfl, sizeof bfl)))
327 return error;
328 bsd_to_linux_flock(&bfl, &lfl);
329 return copyout(&lfl, arg, sizeof lfl);
330 break;
331 case LINUX_F_SETLK:
332 case LINUX_F_SETLKW:
333 cmd = (cmd == LINUX_F_SETLK ? F_SETLK : F_SETLKW);
334 if ((error = copyin(arg, &lfl, sizeof lfl)))
335 return error;
336 linux_to_bsd_flock(&lfl, &bfl);
337 sg = stackgap_init(p->p_emul);
338 bfp = (struct flock *) stackgap_alloc(&sg, sizeof *bfp);
339 if ((error = copyout(&bfl, bfp, sizeof bfl)))
340 return error;
341 SCARG(&fca, fd) = fd;
342 SCARG(&fca, cmd) = cmd;
343 SCARG(&fca, arg) = bfp;
344 return fcntl(p, &fca, retval);
345 break;
346 case LINUX_F_SETOWN:
347 cmd = F_SETOWN;
348 break;
349 case LINUX_F_GETOWN:
350 cmd = F_GETOWN;
351 break;
352 default:
353 return EOPNOTSUPP;
354 }
355
356 SCARG(&fca, fd) = fd;
357 SCARG(&fca, cmd) = cmd;
358 SCARG(&fca, arg) = arg;
359 return fcntl(p, &fca, retval);
360 }
361
362 /*
363 * Convert a NetBSD stat structure to a Linux stat structure.
364 * Only the order of the fields and the padding in the structure
365 * is different. linux_fakedev is a machine-dependent function
366 * which optionally converts device driver major/minor numbers
367 * (XXX horrible, but what can you do against code that compares
368 * things against constant major device numbers? sigh)
369 */
370 static void
371 bsd_to_linux_stat(bsp, lsp)
372 struct stat *bsp;
373 struct linux_stat *lsp;
374 {
375 lsp->lst_dev = bsp->st_dev;
376 lsp->lst_ino = bsp->st_ino;
377 lsp->lst_mode = bsp->st_mode;
378 lsp->lst_nlink = bsp->st_nlink;
379 lsp->lst_uid = bsp->st_uid;
380 lsp->lst_gid = bsp->st_gid;
381 lsp->lst_rdev = linux_fakedev(bsp->st_rdev);
382 lsp->lst_size = bsp->st_size;
383 lsp->lst_blksize = bsp->st_blksize;
384 lsp->lst_blocks = bsp->st_blocks;
385 lsp->lst_atime = bsp->st_atime;
386 lsp->lst_mtime = bsp->st_mtime;
387 lsp->lst_ctime = bsp->st_ctime;
388 }
389
390 /*
391 * The stat functions below are plain sailing. stat and lstat are handled
392 * by one function to avoid code duplication.
393 */
394 int
395 linux_fstat(p, uap, retval)
396 struct proc *p;
397 struct linux_fstat_args /* {
398 syscallarg(int) fd;
399 syscallarg(linux_stat *) sp;
400 } */ *uap;
401 register_t *retval;
402 {
403 struct fstat_args fsa;
404 struct linux_stat tmplst;
405 struct stat *st,tmpst;
406 caddr_t sg;
407 int error;
408
409 sg = stackgap_init(p->p_emul);
410
411 st = stackgap_alloc(&sg, sizeof (struct stat));
412
413 SCARG(&fsa, fd) = SCARG(uap, fd);
414 SCARG(&fsa, sb) = st;
415
416 if ((error = fstat(p, &fsa, retval)))
417 return error;
418
419 if ((error = copyin(st, &tmpst, sizeof tmpst)))
420 return error;
421
422 bsd_to_linux_stat(&tmpst, &tmplst);
423
424 if ((error = copyout(&tmplst, SCARG(uap, sp), sizeof tmplst)))
425 return error;
426
427 return 0;
428 }
429
430 static int
431 linux_stat1(p, uap, retval, dolstat)
432 struct proc *p;
433 struct linux_stat_args *uap;
434 register_t *retval;
435 int dolstat;
436 {
437 struct stat_args sa;
438 struct linux_stat tmplst;
439 struct stat *st, tmpst;
440 caddr_t sg;
441 int error;
442
443 sg = stackgap_init(p->p_emul);
444
445 LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
446
447 st = stackgap_alloc(&sg, sizeof (struct stat));
448 SCARG(&sa, ub) = st;
449 SCARG(&sa, path) = SCARG(uap, path);
450
451 if ((error = (dolstat ? lstat(p, &sa, retval) : stat(p, &sa, retval))))
452 return error;
453
454 if ((error = copyin(st, &tmpst, sizeof tmpst)))
455 return error;
456
457 bsd_to_linux_stat(&tmpst, &tmplst);
458
459 if ((error = copyout(&tmplst, SCARG(uap, sp), sizeof tmplst)))
460 return error;
461
462 return 0;
463 }
464
465 int
466 linux_stat(p, uap, retval)
467 struct proc *p;
468 struct linux_stat_args /* {
469 syscallarg(char *) path;
470 syscallarg(struct linux_stat *) sp;
471 } */ *uap;
472 register_t *retval;
473 {
474 return linux_stat1(p, uap, retval, 0);
475 }
476
477 int
478 linux_lstat(p, uap, retval)
479 struct proc *p;
480 struct linux_lstat_args /* {
481 syscallarg(char *) path;
482 syscallarg(struct linux_stat *) sp;
483 } */ *uap;
484 register_t *retval;
485 {
486 return linux_stat1(p, uap, retval, 1);
487 }
488
489 /*
490 * The following syscalls are mostly here because of the alternate path check.
491 */
492 int
493 linux_access(p, uap, retval)
494 struct proc *p;
495 struct linux_access_args /* {
496 syscallarg(char *) path;
497 syscallarg(int) flags;
498 } */ *uap;
499 register_t *retval;
500 {
501 caddr_t sg = stackgap_init(p->p_emul);
502
503 LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
504
505 return access(p, uap, retval);
506 }
507
508 int
509 linux_unlink(p, uap, retval)
510 struct proc *p;
511 struct linux_unlink_args /* {
512 syscallarg(char *) path;
513 } */ *uap;
514 register_t *retval;
515
516 {
517 caddr_t sg = stackgap_init(p->p_emul);
518
519 LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
520
521 return unlink(p, uap, retval);
522 }
523
524 int
525 linux_chdir(p, uap, retval)
526 struct proc *p;
527 struct linux_chdir_args /* {
528 syscallarg(char *) path;
529 } */ *uap;
530 register_t *retval;
531 {
532 caddr_t sg = stackgap_init(p->p_emul);
533
534 LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
535
536 return chdir(p, uap, retval);
537 }
538
539 int
540 linux_mknod(p, uap, retval)
541 struct proc *p;
542 struct linux_mknod_args /* {
543 syscallarg(char *) path;
544 syscallarg(int) mode;
545 syscallarg(int) dev;
546 } */ *uap;
547 register_t *retval;
548 {
549 caddr_t sg = stackgap_init(p->p_emul);
550 struct mkfifo_args bma;
551
552 LINUX_CHECK_ALT_CREAT(p, &sg, SCARG(uap, path));
553
554 /*
555 * BSD handles FIFOs seperately
556 */
557 if (SCARG(uap, mode) & S_IFIFO) {
558 SCARG(&bma, path) = SCARG(uap, path);
559 SCARG(&bma, mode) = SCARG(uap, mode);
560 return mkfifo(p, uap, retval);
561 } else
562 return mknod(p, uap, retval);
563 }
564
565 int
566 linux_chmod(p, uap, retval)
567 struct proc *p;
568 struct linux_chmod_args /* {
569 syscallarg(char *) path;
570 syscallarg(int) mode;
571 } */ *uap;
572 register_t *retval;
573 {
574 caddr_t sg = stackgap_init(p->p_emul);
575
576 LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
577
578 return chmod(p, uap, retval);
579 }
580
581 int
582 linux_chown(p, uap, retval)
583 struct proc *p;
584 struct linux_chown_args /* {
585 syscallarg(char *) path;
586 syscallarg(int) uid;
587 syscallarg(int) gid;
588 } */ *uap;
589 register_t *retval;
590 {
591 struct chown_args bca;
592 caddr_t sg = stackgap_init(p->p_emul);
593
594 LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
595
596 SCARG(&bca, path) = SCARG(uap, path);
597 SCARG(&bca, uid) = ((linux_uid_t)SCARG(uap, uid) == (linux_uid_t)-1) ?
598 (uid_t)-1 : SCARG(uap, uid);
599 SCARG(&bca, gid) = ((linux_gid_t)SCARG(uap, gid) == (linux_gid_t)-1) ?
600 (gid_t)-1 : SCARG(uap, gid);
601
602 return chown(p, &bca, retval);
603 }
604
605 int
606 linux_fchown(p, uap, retval)
607 struct proc *p;
608 struct linux_fchown_args /* {
609 syscallarg(int) fd;
610 syscallarg(int) uid;
611 syscallarg(int) gid;
612 } */ *uap;
613 register_t *retval;
614 {
615 struct fchown_args bfa;
616
617 SCARG(&bfa, fd) = SCARG(uap, fd);
618 SCARG(&bfa, uid) = ((linux_uid_t)SCARG(uap, uid) == (linux_uid_t)-1) ?
619 (uid_t)-1 : SCARG(uap, uid);
620 SCARG(&bfa, gid) = ((linux_gid_t)SCARG(uap, gid) == (linux_gid_t)-1) ?
621 (gid_t)-1 : SCARG(uap, gid);
622
623 return fchown(p, &bfa, retval);
624 }
625
626 int
627 linux_rename(p, uap, retval)
628 struct proc *p;
629 struct linux_rename_args /* {
630 syscallarg(char *) from;
631 syscallarg(char *) to;
632 } */ *uap;
633 register_t *retval;
634 {
635 caddr_t sg = stackgap_init(p->p_emul);
636
637 LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, from));
638 LINUX_CHECK_ALT_CREAT(p, &sg, SCARG(uap, to));
639
640 return rename(p, uap, retval);
641 }
642
643 int
644 linux_mkdir(p, uap, retval)
645 struct proc *p;
646 struct linux_mkdir_args /* {
647 syscallarg(char *) path;
648 syscallarg(int) mode;
649 } */ *uap;
650 register_t *retval;
651 {
652 caddr_t sg = stackgap_init(p->p_emul);
653
654 LINUX_CHECK_ALT_CREAT(p, &sg, SCARG(uap, path));
655 return mkdir(p, uap, retval);
656 }
657
658 int
659 linux_rmdir(p, uap, retval)
660 struct proc *p;
661 struct linux_rmdir_args /* {
662 syscallarg(char *) path;
663 } */ *uap;
664 register_t *retval;
665 {
666 caddr_t sg = stackgap_init(p->p_emul);
667
668 LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
669 return rmdir(p, uap, retval);
670 }
671
672 int
673 linux_symlink(p, uap, retval)
674 struct proc *p;
675 struct linux_symlink_args /* {
676 syscallarg(char *) path;
677 syscallarg(char *) to;
678 } */ *uap;
679 register_t *retval;
680 {
681 caddr_t sg = stackgap_init(p->p_emul);
682
683 LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
684 LINUX_CHECK_ALT_CREAT(p, &sg, SCARG(uap, to));
685
686 return symlink(p, uap, retval);
687 }
688
689 int
690 linux_readlink(p, uap, retval)
691 struct proc *p;
692 struct linux_readlink_args /* {
693 syscallarg(char *) name;
694 syscallarg(char *) buf;
695 syscallarg(int) count;
696 } */ *uap;
697 {
698 caddr_t sg = stackgap_init(p->p_emul);
699
700 LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, name));
701 return readlink(p, uap, retval);
702 }
703
704 int
705 linux_truncate(p, uap, retval)
706 struct proc *p;
707 struct linux_truncate_args /* {
708 syscallarg(char *) path;
709 syscallarg(long) length;
710 } */ *uap;
711 {
712 caddr_t sg = stackgap_init(p->p_emul);
713
714 LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
715 return compat_43_truncate(p, uap, retval);
716 }
717