linux_llseek.c revision 1.11 1 /* $NetBSD: linux_llseek.c,v 1.11 1995/09/19 22:37:28 thorpej 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, v, retval)
111 struct proc *p;
112 void *v;
113 register_t *retval;
114 {
115 struct linux_creat_args /* {
116 syscallarg(char *) path;
117 syscallarg(int) mode;
118 } */ *uap = v;
119 struct open_args oa;
120 caddr_t sg;
121
122 sg = stackgap_init(p->p_emul);
123 LINUX_CHECK_ALT_CREAT(p, &sg, SCARG(uap, path));
124
125 SCARG(&oa, path) = SCARG(uap, path);
126 SCARG(&oa, flags) = O_CREAT | O_TRUNC | O_WRONLY;
127 SCARG(&oa, mode) = SCARG(uap, mode);
128 return open(p, &oa, retval);
129 }
130
131 /*
132 * open(2). Take care of the different flag values, and let the
133 * NetBSD syscall do the real work. See if this operation
134 * gives the current process a controlling terminal.
135 * (XXX is this necessary?)
136 */
137 int
138 linux_open(p, v, retval)
139 struct proc *p;
140 void *v;
141 register_t *retval;
142 {
143 struct linux_open_args /* {
144 syscallarg(char *) path;
145 syscallarg(int) flags;
146 syscallarg(int) mode;
147 } */ *uap = v;
148 int error, fl;
149 struct open_args boa;
150 caddr_t sg;
151
152 sg = stackgap_init(p->p_emul);
153
154 fl = linux_to_bsd_ioflags(SCARG(uap, flags));
155
156 if (fl & O_CREAT)
157 LINUX_CHECK_ALT_CREAT(p, &sg, SCARG(uap, path));
158 else
159 LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
160
161 SCARG(&boa, path) = SCARG(uap, path);
162 SCARG(&boa, flags) = fl;
163 SCARG(&boa, mode) = SCARG(uap, mode);
164
165 if ((error = open(p, &boa, retval)))
166 return error;
167
168 /*
169 * this bit from sunos_misc.c (and svr4_fcntl.c).
170 * If we are a session leader, and we don't have a controlling
171 * terminal yet, and the O_NOCTTY flag is not set, try to make
172 * this the controlling terminal.
173 */
174 if (!(fl & O_NOCTTY) && SESS_LEADER(p) && !(p->p_flag & P_CONTROLT)) {
175 struct filedesc *fdp = p->p_fd;
176 struct file *fp = fdp->fd_ofiles[*retval];
177
178 /* ignore any error, just give it a try */
179 if (fp->f_type == DTYPE_VNODE)
180 (fp->f_ops->fo_ioctl) (fp, TIOCSCTTY, (caddr_t) 0, p);
181 }
182 return 0;
183 }
184
185 /*
186 * This appears to be part of a Linux attempt to switch to 64 bits file sizes.
187 */
188 int
189 linux_llseek(p, v, retval)
190 struct proc *p;
191 void *v;
192 register_t *retval;
193 {
194 struct linux_llseek_args /* {
195 syscallarg(int) fd;
196 syscallarg(uint32_t) ohigh;
197 syscallarg(uint32_t) olow;
198 syscallarg(caddr_t) res;
199 syscallarg(int) whence;
200 } */ *uap = v;
201 struct lseek_args bla;
202 int error;
203 off_t off;
204
205 off = SCARG(uap, olow) | (((off_t) SCARG(uap, ohigh)) << 32);
206
207 SCARG(&bla, fd) = SCARG(uap, fd);
208 SCARG(&bla, offset) = off;
209 SCARG(&bla, whence) = SCARG(uap, whence);
210
211 if ((error = lseek(p, &bla, retval)))
212 return error;
213
214 if ((error = copyout(retval, SCARG(uap, res), sizeof (off_t))))
215 return error;
216
217 retval[0] = 0;
218 return 0;
219 }
220
221 /*
222 * The next two functions take care of converting the flock
223 * structure back and forth between Linux and NetBSD format.
224 * The only difference in the structures is the order of
225 * the fields, and the 'whence' value.
226 */
227 static void
228 bsd_to_linux_flock(bfp, lfp)
229 struct flock *bfp;
230 struct linux_flock *lfp;
231 {
232 lfp->l_start = bfp->l_start;
233 lfp->l_len = bfp->l_len;
234 lfp->l_pid = bfp->l_pid;
235 lfp->l_whence = bfp->l_whence;
236 switch (bfp->l_type) {
237 case F_RDLCK:
238 lfp->l_type = LINUX_F_RDLCK;
239 break;
240 case F_UNLCK:
241 lfp->l_type = LINUX_F_UNLCK;
242 break;
243 case F_WRLCK:
244 lfp->l_type = LINUX_F_WRLCK;
245 break;
246 }
247 }
248
249 static void
250 linux_to_bsd_flock(lfp, bfp)
251 struct linux_flock *lfp;
252 struct flock *bfp;
253 {
254 bfp->l_start = lfp->l_start;
255 bfp->l_len = lfp->l_len;
256 bfp->l_pid = lfp->l_pid;
257 bfp->l_whence = lfp->l_whence;
258 switch (lfp->l_type) {
259 case LINUX_F_RDLCK:
260 bfp->l_type = F_RDLCK;
261 break;
262 case LINUX_F_UNLCK:
263 bfp->l_type = F_UNLCK;
264 break;
265 case LINUX_F_WRLCK:
266 bfp->l_type = F_WRLCK;
267 break;
268 }
269 }
270
271 /*
272 * Most actions in the fcntl() call are straightforward; simply
273 * pass control to the NetBSD system call. A few commands need
274 * conversions after the actual system call has done its work,
275 * because the flag values and lock structure are different.
276 */
277 int
278 linux_fcntl(p, v, retval)
279 struct proc *p;
280 void *v;
281 register_t *retval;
282 {
283 struct linux_fcntl_args /* {
284 syscallarg(int) fd;
285 syscallarg(int) cmd;
286 syscallarg(void *) arg;
287 } */ *uap = v;
288 int fd, cmd, error, val;
289 caddr_t arg, sg;
290 struct linux_flock lfl;
291 struct flock *bfp, bfl;
292 struct fcntl_args fca;
293
294 fd = SCARG(uap, fd);
295 cmd = SCARG(uap, cmd);
296 arg = (caddr_t) SCARG(uap, arg);
297
298 switch (cmd) {
299 case LINUX_F_DUPFD:
300 cmd = F_DUPFD;
301 break;
302 case LINUX_F_GETFD:
303 cmd = F_GETFD;
304 break;
305 case LINUX_F_SETFD:
306 cmd = F_SETFD;
307 break;
308 case LINUX_F_GETFL:
309 SCARG(&fca, fd) = fd;
310 SCARG(&fca, cmd) = F_GETFL;
311 SCARG(&fca, arg) = arg;
312 if ((error = fcntl(p, &fca, retval)))
313 return error;
314 retval[0] = bsd_to_linux_ioflags(retval[0]);
315 return 0;
316 case LINUX_F_SETFL:
317 val = linux_to_bsd_ioflags((int)SCARG(uap, arg));
318 SCARG(&fca, fd) = fd;
319 SCARG(&fca, cmd) = F_SETFL;
320 SCARG(&fca, arg) = (caddr_t) val;
321 return fcntl(p, &fca, retval);
322 case LINUX_F_GETLK:
323 sg = stackgap_init(p->p_emul);
324 bfp = (struct flock *) stackgap_alloc(&sg, sizeof *bfp);
325 SCARG(&fca, fd) = fd;
326 SCARG(&fca, cmd) = F_GETLK;
327 SCARG(&fca, arg) = bfp;
328 if ((error = fcntl(p, &fca, retval)))
329 return error;
330 if ((error = copyin(bfp, &bfl, sizeof bfl)))
331 return error;
332 bsd_to_linux_flock(&bfl, &lfl);
333 return copyout(&lfl, arg, sizeof lfl);
334 break;
335 case LINUX_F_SETLK:
336 case LINUX_F_SETLKW:
337 cmd = (cmd == LINUX_F_SETLK ? F_SETLK : F_SETLKW);
338 if ((error = copyin(arg, &lfl, sizeof lfl)))
339 return error;
340 linux_to_bsd_flock(&lfl, &bfl);
341 sg = stackgap_init(p->p_emul);
342 bfp = (struct flock *) stackgap_alloc(&sg, sizeof *bfp);
343 if ((error = copyout(&bfl, bfp, sizeof bfl)))
344 return error;
345 SCARG(&fca, fd) = fd;
346 SCARG(&fca, cmd) = cmd;
347 SCARG(&fca, arg) = bfp;
348 return fcntl(p, &fca, retval);
349 break;
350 case LINUX_F_SETOWN:
351 cmd = F_SETOWN;
352 break;
353 case LINUX_F_GETOWN:
354 cmd = F_GETOWN;
355 break;
356 default:
357 return EOPNOTSUPP;
358 }
359
360 SCARG(&fca, fd) = fd;
361 SCARG(&fca, cmd) = cmd;
362 SCARG(&fca, arg) = arg;
363 return fcntl(p, &fca, retval);
364 }
365
366 /*
367 * Convert a NetBSD stat structure to a Linux stat structure.
368 * Only the order of the fields and the padding in the structure
369 * is different. linux_fakedev is a machine-dependent function
370 * which optionally converts device driver major/minor numbers
371 * (XXX horrible, but what can you do against code that compares
372 * things against constant major device numbers? sigh)
373 */
374 static void
375 bsd_to_linux_stat(bsp, lsp)
376 struct stat *bsp;
377 struct linux_stat *lsp;
378 {
379 lsp->lst_dev = bsp->st_dev;
380 lsp->lst_ino = bsp->st_ino;
381 lsp->lst_mode = bsp->st_mode;
382 lsp->lst_nlink = bsp->st_nlink;
383 lsp->lst_uid = bsp->st_uid;
384 lsp->lst_gid = bsp->st_gid;
385 lsp->lst_rdev = linux_fakedev(bsp->st_rdev);
386 lsp->lst_size = bsp->st_size;
387 lsp->lst_blksize = bsp->st_blksize;
388 lsp->lst_blocks = bsp->st_blocks;
389 lsp->lst_atime = bsp->st_atime;
390 lsp->lst_mtime = bsp->st_mtime;
391 lsp->lst_ctime = bsp->st_ctime;
392 }
393
394 /*
395 * The stat functions below are plain sailing. stat and lstat are handled
396 * by one function to avoid code duplication.
397 */
398 int
399 linux_fstat(p, v, retval)
400 struct proc *p;
401 void *v;
402 register_t *retval;
403 {
404 struct linux_fstat_args /* {
405 syscallarg(int) fd;
406 syscallarg(linux_stat *) sp;
407 } */ *uap = v;
408 struct fstat_args fsa;
409 struct linux_stat tmplst;
410 struct stat *st,tmpst;
411 caddr_t sg;
412 int error;
413
414 sg = stackgap_init(p->p_emul);
415
416 st = stackgap_alloc(&sg, sizeof (struct stat));
417
418 SCARG(&fsa, fd) = SCARG(uap, fd);
419 SCARG(&fsa, sb) = st;
420
421 if ((error = fstat(p, &fsa, retval)))
422 return error;
423
424 if ((error = copyin(st, &tmpst, sizeof tmpst)))
425 return error;
426
427 bsd_to_linux_stat(&tmpst, &tmplst);
428
429 if ((error = copyout(&tmplst, SCARG(uap, sp), sizeof tmplst)))
430 return error;
431
432 return 0;
433 }
434
435 static int
436 linux_stat1(p, uap, retval, dolstat)
437 struct proc *p;
438 struct linux_stat_args *uap;
439 register_t *retval;
440 int dolstat;
441 {
442 struct stat_args sa;
443 struct linux_stat tmplst;
444 struct stat *st, tmpst;
445 caddr_t sg;
446 int error;
447
448 sg = stackgap_init(p->p_emul);
449
450 LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
451
452 st = stackgap_alloc(&sg, sizeof (struct stat));
453 SCARG(&sa, ub) = st;
454 SCARG(&sa, path) = SCARG(uap, path);
455
456 if ((error = (dolstat ? lstat(p, &sa, retval) : stat(p, &sa, retval))))
457 return error;
458
459 if ((error = copyin(st, &tmpst, sizeof tmpst)))
460 return error;
461
462 bsd_to_linux_stat(&tmpst, &tmplst);
463
464 if ((error = copyout(&tmplst, SCARG(uap, sp), sizeof tmplst)))
465 return error;
466
467 return 0;
468 }
469
470 int
471 linux_stat(p, v, retval)
472 struct proc *p;
473 void *v;
474 register_t *retval;
475 {
476 struct linux_stat_args /* {
477 syscallarg(char *) path;
478 syscallarg(struct linux_stat *) sp;
479 } */ *uap = v;
480
481 return linux_stat1(p, uap, retval, 0);
482 }
483
484 int
485 linux_lstat(p, v, retval)
486 struct proc *p;
487 void *v;
488 register_t *retval;
489 {
490 struct linux_lstat_args /* {
491 syscallarg(char *) path;
492 syscallarg(struct linux_stat *) sp;
493 } */ *uap = v;
494
495 return linux_stat1(p, uap, retval, 1);
496 }
497
498 /*
499 * The following syscalls are mostly here because of the alternate path check.
500 */
501 int
502 linux_access(p, v, retval)
503 struct proc *p;
504 void *v;
505 register_t *retval;
506 {
507 struct linux_access_args /* {
508 syscallarg(char *) path;
509 syscallarg(int) flags;
510 } */ *uap = v;
511 caddr_t sg = stackgap_init(p->p_emul);
512
513 LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
514
515 return access(p, uap, retval);
516 }
517
518 int
519 linux_unlink(p, v, retval)
520 struct proc *p;
521 void *v;
522 register_t *retval;
523
524 {
525 struct linux_unlink_args /* {
526 syscallarg(char *) path;
527 } */ *uap = v;
528 caddr_t sg = stackgap_init(p->p_emul);
529
530 LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
531
532 return unlink(p, uap, retval);
533 }
534
535 int
536 linux_chdir(p, v, retval)
537 struct proc *p;
538 void *v;
539 register_t *retval;
540 {
541 struct linux_chdir_args /* {
542 syscallarg(char *) path;
543 } */ *uap = v;
544 caddr_t sg = stackgap_init(p->p_emul);
545
546 LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
547
548 return chdir(p, uap, retval);
549 }
550
551 int
552 linux_mknod(p, v, retval)
553 struct proc *p;
554 void *v;
555 register_t *retval;
556 {
557 struct linux_mknod_args /* {
558 syscallarg(char *) path;
559 syscallarg(int) mode;
560 syscallarg(int) dev;
561 } */ *uap = v;
562 caddr_t sg = stackgap_init(p->p_emul);
563 struct mkfifo_args bma;
564
565 LINUX_CHECK_ALT_CREAT(p, &sg, SCARG(uap, path));
566
567 /*
568 * BSD handles FIFOs seperately
569 */
570 if (SCARG(uap, mode) & S_IFIFO) {
571 SCARG(&bma, path) = SCARG(uap, path);
572 SCARG(&bma, mode) = SCARG(uap, mode);
573 return mkfifo(p, uap, retval);
574 } else
575 return mknod(p, uap, retval);
576 }
577
578 int
579 linux_chmod(p, v, retval)
580 struct proc *p;
581 void *v;
582 register_t *retval;
583 {
584 struct linux_chmod_args /* {
585 syscallarg(char *) path;
586 syscallarg(int) mode;
587 } */ *uap = v;
588 caddr_t sg = stackgap_init(p->p_emul);
589
590 LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
591
592 return chmod(p, uap, retval);
593 }
594
595 int
596 linux_chown(p, v, retval)
597 struct proc *p;
598 void *v;
599 register_t *retval;
600 {
601 struct linux_chown_args /* {
602 syscallarg(char *) path;
603 syscallarg(int) uid;
604 syscallarg(int) gid;
605 } */ *uap = v;
606 struct chown_args bca;
607 caddr_t sg = stackgap_init(p->p_emul);
608
609 LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
610
611 SCARG(&bca, path) = SCARG(uap, path);
612 SCARG(&bca, uid) = ((linux_uid_t)SCARG(uap, uid) == (linux_uid_t)-1) ?
613 (uid_t)-1 : SCARG(uap, uid);
614 SCARG(&bca, gid) = ((linux_gid_t)SCARG(uap, gid) == (linux_gid_t)-1) ?
615 (gid_t)-1 : SCARG(uap, gid);
616
617 return chown(p, &bca, retval);
618 }
619
620 int
621 linux_fchown(p, v, retval)
622 struct proc *p;
623 void *v;
624 register_t *retval;
625 {
626 struct linux_fchown_args /* {
627 syscallarg(int) fd;
628 syscallarg(int) uid;
629 syscallarg(int) gid;
630 } */ *uap = v;
631 struct fchown_args bfa;
632
633 SCARG(&bfa, fd) = SCARG(uap, fd);
634 SCARG(&bfa, uid) = ((linux_uid_t)SCARG(uap, uid) == (linux_uid_t)-1) ?
635 (uid_t)-1 : SCARG(uap, uid);
636 SCARG(&bfa, gid) = ((linux_gid_t)SCARG(uap, gid) == (linux_gid_t)-1) ?
637 (gid_t)-1 : SCARG(uap, gid);
638
639 return fchown(p, &bfa, retval);
640 }
641
642 int
643 linux_rename(p, v, retval)
644 struct proc *p;
645 void *v;
646 register_t *retval;
647 {
648 struct linux_rename_args /* {
649 syscallarg(char *) from;
650 syscallarg(char *) to;
651 } */ *uap = v;
652 caddr_t sg = stackgap_init(p->p_emul);
653
654 LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, from));
655 LINUX_CHECK_ALT_CREAT(p, &sg, SCARG(uap, to));
656
657 return rename(p, uap, retval);
658 }
659
660 int
661 linux_mkdir(p, v, retval)
662 struct proc *p;
663 void *v;
664 register_t *retval;
665 {
666 struct linux_mkdir_args /* {
667 syscallarg(char *) path;
668 syscallarg(int) mode;
669 } */ *uap = v;
670 caddr_t sg = stackgap_init(p->p_emul);
671
672 LINUX_CHECK_ALT_CREAT(p, &sg, SCARG(uap, path));
673 return mkdir(p, uap, retval);
674 }
675
676 int
677 linux_rmdir(p, v, retval)
678 struct proc *p;
679 void *v;
680 register_t *retval;
681 {
682 struct linux_rmdir_args /* {
683 syscallarg(char *) path;
684 } */ *uap = v;
685 caddr_t sg = stackgap_init(p->p_emul);
686
687 LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
688 return rmdir(p, uap, retval);
689 }
690
691 int
692 linux_symlink(p, v, retval)
693 struct proc *p;
694 void *v;
695 register_t *retval;
696 {
697 struct linux_symlink_args /* {
698 syscallarg(char *) path;
699 syscallarg(char *) to;
700 } */ *uap = v;
701 caddr_t sg = stackgap_init(p->p_emul);
702
703 LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
704 LINUX_CHECK_ALT_CREAT(p, &sg, SCARG(uap, to));
705
706 return symlink(p, uap, retval);
707 }
708
709 int
710 linux_readlink(p, v, retval)
711 struct proc *p;
712 void *v;
713 register_t *retval;
714 {
715 struct linux_readlink_args /* {
716 syscallarg(char *) name;
717 syscallarg(char *) buf;
718 syscallarg(int) count;
719 } */ *uap = v;
720 caddr_t sg = stackgap_init(p->p_emul);
721
722 LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, name));
723 return readlink(p, uap, retval);
724 }
725
726 int
727 linux_truncate(p, v, retval)
728 struct proc *p;
729 void *v;
730 register_t *retval;
731 {
732 struct linux_truncate_args /* {
733 syscallarg(char *) path;
734 syscallarg(long) length;
735 } */ *uap = v;
736 caddr_t sg = stackgap_init(p->p_emul);
737
738 LINUX_CHECK_ALT_EXIST(p, &sg, SCARG(uap, path));
739 return compat_43_truncate(p, uap, retval);
740 }
741