1 | /* $NetBSD: linux_file.c,v 1.115 2015/03/01 13:19:39 njoly Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 1995, 1998, 2008 The NetBSD Foundation, Inc. |
5 | * All rights reserved. |
6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Frank van der Linden and Eric Haszlakiewicz. |
9 | * |
10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions |
12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. |
15 | * 2. Redistributions in binary form must reproduce the above copyright |
16 | * notice, this list of conditions and the following disclaimer in the |
17 | * documentation and/or other materials provided with the distribution. |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ |
31 | |
32 | /* |
33 | * Functions in multiarch: |
34 | * linux_sys_llseek : linux_llseek.c |
35 | */ |
36 | |
37 | #include <sys/cdefs.h> |
38 | __KERNEL_RCSID(0, "$NetBSD: linux_file.c,v 1.115 2015/03/01 13:19:39 njoly Exp $" ); |
39 | |
40 | #include <sys/param.h> |
41 | #include <sys/systm.h> |
42 | #include <sys/namei.h> |
43 | #include <sys/proc.h> |
44 | #include <sys/file.h> |
45 | #include <sys/fcntl.h> |
46 | #include <sys/stat.h> |
47 | #include <sys/filedesc.h> |
48 | #include <sys/ioctl.h> |
49 | #include <sys/kernel.h> |
50 | #include <sys/mount.h> |
51 | #include <sys/namei.h> |
52 | #include <sys/vnode.h> |
53 | #include <sys/tty.h> |
54 | #include <sys/socketvar.h> |
55 | #include <sys/conf.h> |
56 | #include <sys/pipe.h> |
57 | |
58 | #include <sys/syscallargs.h> |
59 | #include <sys/vfs_syscalls.h> |
60 | |
61 | #include <compat/linux/common/linux_types.h> |
62 | #include <compat/linux/common/linux_signal.h> |
63 | #include <compat/linux/common/linux_fcntl.h> |
64 | #include <compat/linux/common/linux_util.h> |
65 | #include <compat/linux/common/linux_machdep.h> |
66 | #include <compat/linux/common/linux_ipc.h> |
67 | #include <compat/linux/common/linux_sem.h> |
68 | |
69 | #include <compat/linux/linux_syscallargs.h> |
70 | |
71 | static int bsd_to_linux_ioflags(int); |
72 | #ifndef __amd64__ |
73 | static void bsd_to_linux_stat(struct stat *, struct linux_stat *); |
74 | #endif |
75 | |
76 | conv_linux_flock(linux, flock) |
77 | |
78 | /* |
79 | * Some file-related calls are handled here. The usual flag conversion |
80 | * an structure conversion is done, and alternate emul path searching. |
81 | */ |
82 | |
83 | /* |
84 | * The next two functions convert between the Linux and NetBSD values |
85 | * of the flags used in open(2) and fcntl(2). |
86 | */ |
87 | int |
88 | linux_to_bsd_ioflags(int lflags) |
89 | { |
90 | int res = 0; |
91 | |
92 | res |= cvtto_bsd_mask(lflags, LINUX_O_WRONLY, O_WRONLY); |
93 | res |= cvtto_bsd_mask(lflags, LINUX_O_RDONLY, O_RDONLY); |
94 | res |= cvtto_bsd_mask(lflags, LINUX_O_RDWR, O_RDWR); |
95 | |
96 | res |= cvtto_bsd_mask(lflags, LINUX_O_CREAT, O_CREAT); |
97 | res |= cvtto_bsd_mask(lflags, LINUX_O_EXCL, O_EXCL); |
98 | res |= cvtto_bsd_mask(lflags, LINUX_O_NOCTTY, O_NOCTTY); |
99 | res |= cvtto_bsd_mask(lflags, LINUX_O_TRUNC, O_TRUNC); |
100 | res |= cvtto_bsd_mask(lflags, LINUX_O_APPEND, O_APPEND); |
101 | res |= cvtto_bsd_mask(lflags, LINUX_O_NONBLOCK, O_NONBLOCK); |
102 | res |= cvtto_bsd_mask(lflags, LINUX_O_NDELAY, O_NDELAY); |
103 | res |= cvtto_bsd_mask(lflags, LINUX_O_SYNC, O_FSYNC); |
104 | res |= cvtto_bsd_mask(lflags, LINUX_FASYNC, O_ASYNC); |
105 | res |= cvtto_bsd_mask(lflags, LINUX_O_DIRECT, O_DIRECT); |
106 | res |= cvtto_bsd_mask(lflags, LINUX_O_DIRECTORY, O_DIRECTORY); |
107 | res |= cvtto_bsd_mask(lflags, LINUX_O_NOFOLLOW, O_NOFOLLOW); |
108 | res |= cvtto_bsd_mask(lflags, LINUX_O_CLOEXEC, O_CLOEXEC); |
109 | |
110 | return res; |
111 | } |
112 | |
113 | static int |
114 | bsd_to_linux_ioflags(int bflags) |
115 | { |
116 | int res = 0; |
117 | |
118 | res |= cvtto_linux_mask(bflags, O_WRONLY, LINUX_O_WRONLY); |
119 | res |= cvtto_linux_mask(bflags, O_RDONLY, LINUX_O_RDONLY); |
120 | res |= cvtto_linux_mask(bflags, O_RDWR, LINUX_O_RDWR); |
121 | |
122 | res |= cvtto_linux_mask(bflags, O_CREAT, LINUX_O_CREAT); |
123 | res |= cvtto_linux_mask(bflags, O_EXCL, LINUX_O_EXCL); |
124 | res |= cvtto_linux_mask(bflags, O_NOCTTY, LINUX_O_NOCTTY); |
125 | res |= cvtto_linux_mask(bflags, O_TRUNC, LINUX_O_TRUNC); |
126 | res |= cvtto_linux_mask(bflags, O_APPEND, LINUX_O_APPEND); |
127 | res |= cvtto_linux_mask(bflags, O_NONBLOCK, LINUX_O_NONBLOCK); |
128 | res |= cvtto_linux_mask(bflags, O_NDELAY, LINUX_O_NDELAY); |
129 | res |= cvtto_linux_mask(bflags, O_FSYNC, LINUX_O_SYNC); |
130 | res |= cvtto_linux_mask(bflags, O_ASYNC, LINUX_FASYNC); |
131 | res |= cvtto_linux_mask(bflags, O_DIRECT, LINUX_O_DIRECT); |
132 | res |= cvtto_linux_mask(bflags, O_DIRECTORY, LINUX_O_DIRECTORY); |
133 | res |= cvtto_linux_mask(bflags, O_NOFOLLOW, LINUX_O_NOFOLLOW); |
134 | res |= cvtto_linux_mask(bflags, O_CLOEXEC, LINUX_O_CLOEXEC); |
135 | |
136 | return res; |
137 | } |
138 | |
139 | /* |
140 | * creat(2) is an obsolete function, but it's present as a Linux |
141 | * system call, so let's deal with it. |
142 | * |
143 | * Note: On the Alpha this doesn't really exist in Linux, but it's defined |
144 | * in syscalls.master anyway so this doesn't have to be special cased. |
145 | * |
146 | * Just call open(2) with the TRUNC, CREAT and WRONLY flags. |
147 | */ |
148 | int |
149 | linux_sys_creat(struct lwp *l, const struct linux_sys_creat_args *uap, register_t *retval) |
150 | { |
151 | /* { |
152 | syscallarg(const char *) path; |
153 | syscallarg(linux_umode_t) mode; |
154 | } */ |
155 | struct sys_open_args oa; |
156 | |
157 | SCARG(&oa, path) = SCARG(uap, path); |
158 | SCARG(&oa, flags) = O_CREAT | O_TRUNC | O_WRONLY; |
159 | SCARG(&oa, mode) = SCARG(uap, mode); |
160 | |
161 | return sys_open(l, &oa, retval); |
162 | } |
163 | |
164 | static void |
165 | linux_open_ctty(struct lwp *l, int flags, int fd) |
166 | { |
167 | struct proc *p = l->l_proc; |
168 | |
169 | /* |
170 | * this bit from sunos_misc.c (and svr4_fcntl.c). |
171 | * If we are a session leader, and we don't have a controlling |
172 | * terminal yet, and the O_NOCTTY flag is not set, try to make |
173 | * this the controlling terminal. |
174 | */ |
175 | if (!(flags & O_NOCTTY) && SESS_LEADER(p) && !(p->p_lflag & PL_CONTROLT)) { |
176 | file_t *fp; |
177 | |
178 | fp = fd_getfile(fd); |
179 | |
180 | /* ignore any error, just give it a try */ |
181 | if (fp != NULL) { |
182 | if (fp->f_type == DTYPE_VNODE) { |
183 | (fp->f_ops->fo_ioctl) (fp, TIOCSCTTY, NULL); |
184 | } |
185 | fd_putfile(fd); |
186 | } |
187 | } |
188 | } |
189 | |
190 | /* |
191 | * open(2). Take care of the different flag values, and let the |
192 | * NetBSD syscall do the real work. See if this operation |
193 | * gives the current process a controlling terminal. |
194 | * (XXX is this necessary?) |
195 | */ |
196 | int |
197 | linux_sys_open(struct lwp *l, const struct linux_sys_open_args *uap, register_t *retval) |
198 | { |
199 | /* { |
200 | syscallarg(const char *) path; |
201 | syscallarg(int) flags; |
202 | syscallarg(linux_umode_t) mode; |
203 | } */ |
204 | int error, fl; |
205 | struct sys_open_args boa; |
206 | |
207 | fl = linux_to_bsd_ioflags(SCARG(uap, flags)); |
208 | |
209 | SCARG(&boa, path) = SCARG(uap, path); |
210 | SCARG(&boa, flags) = fl; |
211 | SCARG(&boa, mode) = SCARG(uap, mode); |
212 | |
213 | if ((error = sys_open(l, &boa, retval))) |
214 | return (error == EFTYPE) ? ELOOP : error; |
215 | |
216 | linux_open_ctty(l, fl, *retval); |
217 | return 0; |
218 | } |
219 | |
220 | int |
221 | linux_sys_openat(struct lwp *l, const struct linux_sys_openat_args *uap, register_t *retval) |
222 | { |
223 | /* { |
224 | syscallarg(int) fd; |
225 | syscallarg(const char *) path; |
226 | syscallarg(int) flags; |
227 | syscallarg(linux_umode_t) mode; |
228 | } */ |
229 | int error, fl; |
230 | struct sys_openat_args boa; |
231 | |
232 | fl = linux_to_bsd_ioflags(SCARG(uap, flags)); |
233 | |
234 | SCARG(&boa, fd) = SCARG(uap, fd); |
235 | SCARG(&boa, path) = SCARG(uap, path); |
236 | SCARG(&boa, oflags) = fl; |
237 | SCARG(&boa, mode) = SCARG(uap, mode); |
238 | |
239 | if ((error = sys_openat(l, &boa, retval))) |
240 | return (error == EFTYPE) ? ELOOP : error; |
241 | |
242 | linux_open_ctty(l, fl, *retval); |
243 | return 0; |
244 | } |
245 | |
246 | /* |
247 | * Most actions in the fcntl() call are straightforward; simply |
248 | * pass control to the NetBSD system call. A few commands need |
249 | * conversions after the actual system call has done its work, |
250 | * because the flag values and lock structure are different. |
251 | */ |
252 | int |
253 | linux_sys_fcntl(struct lwp *l, const struct linux_sys_fcntl_args *uap, register_t *retval) |
254 | { |
255 | /* { |
256 | syscallarg(int) fd; |
257 | syscallarg(int) cmd; |
258 | syscallarg(void *) arg; |
259 | } */ |
260 | struct proc *p = l->l_proc; |
261 | int fd, cmd, error; |
262 | u_long val; |
263 | void *arg; |
264 | struct sys_fcntl_args fca; |
265 | file_t *fp; |
266 | struct vnode *vp; |
267 | struct vattr va; |
268 | long pgid; |
269 | struct pgrp *pgrp; |
270 | struct tty *tp; |
271 | |
272 | fd = SCARG(uap, fd); |
273 | cmd = SCARG(uap, cmd); |
274 | arg = SCARG(uap, arg); |
275 | |
276 | switch (cmd) { |
277 | |
278 | case LINUX_F_DUPFD: |
279 | cmd = F_DUPFD; |
280 | break; |
281 | |
282 | case LINUX_F_GETFD: |
283 | cmd = F_GETFD; |
284 | break; |
285 | |
286 | case LINUX_F_SETFD: |
287 | cmd = F_SETFD; |
288 | break; |
289 | |
290 | case LINUX_F_GETFL: |
291 | SCARG(&fca, fd) = fd; |
292 | SCARG(&fca, cmd) = F_GETFL; |
293 | SCARG(&fca, arg) = arg; |
294 | if ((error = sys_fcntl(l, &fca, retval))) |
295 | return error; |
296 | retval[0] = bsd_to_linux_ioflags(retval[0]); |
297 | return 0; |
298 | |
299 | case LINUX_F_SETFL: { |
300 | file_t *fp1 = NULL; |
301 | |
302 | val = linux_to_bsd_ioflags((unsigned long)SCARG(uap, arg)); |
303 | /* |
304 | * Linux seems to have same semantics for sending SIGIO to the |
305 | * read side of socket, but slightly different semantics |
306 | * for SIGIO to the write side. Rather than sending the SIGIO |
307 | * every time it's possible to write (directly) more data, it |
308 | * only sends SIGIO if last write(2) failed due to insufficient |
309 | * memory to hold the data. This is compatible enough |
310 | * with NetBSD semantics to not do anything about the |
311 | * difference. |
312 | * |
313 | * Linux does NOT send SIGIO for pipes. Deal with socketpair |
314 | * ones and DTYPE_PIPE ones. For these, we don't set |
315 | * the underlying flags (we don't pass O_ASYNC flag down |
316 | * to sys_fcntl()), but set the FASYNC flag for file descriptor, |
317 | * so that F_GETFL would report the ASYNC i/o is on. |
318 | */ |
319 | if (val & O_ASYNC) { |
320 | if (((fp1 = fd_getfile(fd)) == NULL)) |
321 | return (EBADF); |
322 | if (((fp1->f_type == DTYPE_SOCKET) && fp1->f_data |
323 | && ((struct socket *)fp1->f_data)->so_state & SS_ISAPIPE) |
324 | || (fp1->f_type == DTYPE_PIPE)) |
325 | val &= ~O_ASYNC; |
326 | else { |
327 | /* not a pipe, do not modify anything */ |
328 | fd_putfile(fd); |
329 | fp1 = NULL; |
330 | } |
331 | } |
332 | |
333 | SCARG(&fca, fd) = fd; |
334 | SCARG(&fca, cmd) = F_SETFL; |
335 | SCARG(&fca, arg) = (void *) val; |
336 | |
337 | error = sys_fcntl(l, &fca, retval); |
338 | |
339 | /* Now set the FASYNC flag for pipes */ |
340 | if (fp1) { |
341 | if (!error) { |
342 | mutex_enter(&fp1->f_lock); |
343 | fp1->f_flag |= FASYNC; |
344 | mutex_exit(&fp1->f_lock); |
345 | } |
346 | fd_putfile(fd); |
347 | } |
348 | |
349 | return (error); |
350 | } |
351 | |
352 | case LINUX_F_GETLK: |
353 | do_linux_getlk(fd, cmd, arg, linux, flock); |
354 | |
355 | case LINUX_F_SETLK: |
356 | case LINUX_F_SETLKW: |
357 | do_linux_setlk(fd, cmd, arg, linux, flock, LINUX_F_SETLK); |
358 | |
359 | case LINUX_F_SETOWN: |
360 | case LINUX_F_GETOWN: |
361 | /* |
362 | * We need to route fcntl() for tty descriptors around normal |
363 | * fcntl(), since NetBSD tty TIOC{G,S}PGRP semantics is too |
364 | * restrictive for Linux F_{G,S}ETOWN. For non-tty descriptors, |
365 | * this is not a problem. |
366 | */ |
367 | if ((fp = fd_getfile(fd)) == NULL) |
368 | return EBADF; |
369 | |
370 | /* Check it's a character device vnode */ |
371 | if (fp->f_type != DTYPE_VNODE |
372 | || (vp = (struct vnode *)fp->f_data) == NULL |
373 | || vp->v_type != VCHR) { |
374 | fd_putfile(fd); |
375 | |
376 | not_tty: |
377 | /* Not a tty, proceed with common fcntl() */ |
378 | cmd = cmd == LINUX_F_SETOWN ? F_SETOWN : F_GETOWN; |
379 | break; |
380 | } |
381 | |
382 | vn_lock(vp, LK_SHARED | LK_RETRY); |
383 | error = VOP_GETATTR(vp, &va, l->l_cred); |
384 | VOP_UNLOCK(vp); |
385 | |
386 | fd_putfile(fd); |
387 | |
388 | if (error) |
389 | return error; |
390 | |
391 | if ((tp = cdev_tty(va.va_rdev)) == NULL) |
392 | goto not_tty; |
393 | |
394 | /* set tty pg_id appropriately */ |
395 | mutex_enter(proc_lock); |
396 | if (cmd == LINUX_F_GETOWN) { |
397 | retval[0] = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PGID; |
398 | mutex_exit(proc_lock); |
399 | return 0; |
400 | } |
401 | if ((long)arg <= 0) { |
402 | pgid = -(long)arg; |
403 | } else { |
404 | struct proc *p1 = proc_find((long)arg); |
405 | if (p1 == NULL) { |
406 | mutex_exit(proc_lock); |
407 | return (ESRCH); |
408 | } |
409 | pgid = (long)p1->p_pgrp->pg_id; |
410 | } |
411 | pgrp = pgrp_find(pgid); |
412 | if (pgrp == NULL || pgrp->pg_session != p->p_session) { |
413 | mutex_exit(proc_lock); |
414 | return EPERM; |
415 | } |
416 | tp->t_pgrp = pgrp; |
417 | mutex_exit(proc_lock); |
418 | return 0; |
419 | |
420 | case LINUX_F_DUPFD_CLOEXEC: |
421 | cmd = F_DUPFD_CLOEXEC; |
422 | break; |
423 | |
424 | default: |
425 | return EOPNOTSUPP; |
426 | } |
427 | |
428 | SCARG(&fca, fd) = fd; |
429 | SCARG(&fca, cmd) = cmd; |
430 | SCARG(&fca, arg) = arg; |
431 | |
432 | return sys_fcntl(l, &fca, retval); |
433 | } |
434 | |
435 | #if !defined(__amd64__) |
436 | /* |
437 | * Convert a NetBSD stat structure to a Linux stat structure. |
438 | * Only the order of the fields and the padding in the structure |
439 | * is different. linux_fakedev is a machine-dependent function |
440 | * which optionally converts device driver major/minor numbers |
441 | * (XXX horrible, but what can you do against code that compares |
442 | * things against constant major device numbers? sigh) |
443 | */ |
444 | static void |
445 | bsd_to_linux_stat(struct stat *bsp, struct linux_stat *lsp) |
446 | { |
447 | |
448 | lsp->lst_dev = linux_fakedev(bsp->st_dev, 0); |
449 | lsp->lst_ino = bsp->st_ino; |
450 | lsp->lst_mode = (linux_mode_t)bsp->st_mode; |
451 | if (bsp->st_nlink >= (1 << 15)) |
452 | lsp->lst_nlink = (1 << 15) - 1; |
453 | else |
454 | lsp->lst_nlink = (linux_nlink_t)bsp->st_nlink; |
455 | lsp->lst_uid = bsp->st_uid; |
456 | lsp->lst_gid = bsp->st_gid; |
457 | lsp->lst_rdev = linux_fakedev(bsp->st_rdev, 1); |
458 | lsp->lst_size = bsp->st_size; |
459 | lsp->lst_blksize = bsp->st_blksize; |
460 | lsp->lst_blocks = bsp->st_blocks; |
461 | lsp->lst_atime = bsp->st_atime; |
462 | lsp->lst_mtime = bsp->st_mtime; |
463 | lsp->lst_ctime = bsp->st_ctime; |
464 | #ifdef LINUX_STAT_HAS_NSEC |
465 | lsp->lst_atime_nsec = bsp->st_atimensec; |
466 | lsp->lst_mtime_nsec = bsp->st_mtimensec; |
467 | lsp->lst_ctime_nsec = bsp->st_ctimensec; |
468 | #endif |
469 | } |
470 | |
471 | /* |
472 | * The stat functions below are plain sailing. stat and lstat are handled |
473 | * by one function to avoid code duplication. |
474 | */ |
475 | int |
476 | linux_sys_fstat(struct lwp *l, const struct linux_sys_fstat_args *uap, register_t *retval) |
477 | { |
478 | /* { |
479 | syscallarg(int) fd; |
480 | syscallarg(linux_stat *) sp; |
481 | } */ |
482 | struct linux_stat tmplst; |
483 | struct stat tmpst; |
484 | int error; |
485 | |
486 | error = do_sys_fstat(SCARG(uap, fd), &tmpst); |
487 | if (error != 0) |
488 | return error; |
489 | bsd_to_linux_stat(&tmpst, &tmplst); |
490 | |
491 | return copyout(&tmplst, SCARG(uap, sp), sizeof tmplst); |
492 | } |
493 | |
494 | static int |
495 | linux_stat1(const struct linux_sys_stat_args *uap, register_t *retval, int flags) |
496 | { |
497 | struct linux_stat tmplst; |
498 | struct stat tmpst; |
499 | int error; |
500 | |
501 | error = do_sys_stat(SCARG(uap, path), flags, &tmpst); |
502 | if (error != 0) |
503 | return error; |
504 | |
505 | bsd_to_linux_stat(&tmpst, &tmplst); |
506 | |
507 | return copyout(&tmplst, SCARG(uap, sp), sizeof tmplst); |
508 | } |
509 | |
510 | int |
511 | linux_sys_stat(struct lwp *l, const struct linux_sys_stat_args *uap, register_t *retval) |
512 | { |
513 | /* { |
514 | syscallarg(const char *) path; |
515 | syscallarg(struct linux_stat *) sp; |
516 | } */ |
517 | |
518 | return linux_stat1(uap, retval, FOLLOW); |
519 | } |
520 | |
521 | /* Note: this is "newlstat" in the Linux sources */ |
522 | /* (we don't bother with the old lstat currently) */ |
523 | int |
524 | linux_sys_lstat(struct lwp *l, const struct linux_sys_lstat_args *uap, register_t *retval) |
525 | { |
526 | /* { |
527 | syscallarg(const char *) path; |
528 | syscallarg(struct linux_stat *) sp; |
529 | } */ |
530 | |
531 | return linux_stat1((const void *)uap, retval, NOFOLLOW); |
532 | } |
533 | #endif /* !__amd64__ */ |
534 | |
535 | /* |
536 | * The following syscalls are mostly here because of the alternate path check. |
537 | */ |
538 | |
539 | int |
540 | linux_sys_linkat(struct lwp *l, const struct linux_sys_linkat_args *uap, register_t *retval) |
541 | { |
542 | /* { |
543 | syscallarg(int) fd1; |
544 | syscallarg(const char *) name1; |
545 | syscallarg(int) fd2; |
546 | syscallarg(const char *) name2; |
547 | syscallarg(int) flags; |
548 | } */ |
549 | int fd1 = SCARG(uap, fd1); |
550 | const char *name1 = SCARG(uap, name1); |
551 | int fd2 = SCARG(uap, fd2); |
552 | const char *name2 = SCARG(uap, name2); |
553 | int follow; |
554 | |
555 | follow = SCARG(uap, flags) & LINUX_AT_SYMLINK_FOLLOW; |
556 | |
557 | return do_sys_linkat(l, fd1, name1, fd2, name2, follow, retval); |
558 | } |
559 | |
560 | static int |
561 | linux_unlink_dircheck(const char *path) |
562 | { |
563 | struct nameidata nd; |
564 | struct pathbuf *pb; |
565 | int error; |
566 | |
567 | /* |
568 | * Linux returns EISDIR if unlink(2) is called on a directory. |
569 | * We return EPERM in such cases. To emulate correct behaviour, |
570 | * check if the path points to directory and return EISDIR if this |
571 | * is the case. |
572 | * |
573 | * XXX this should really not copy in the path buffer twice... |
574 | */ |
575 | error = pathbuf_copyin(path, &pb); |
576 | if (error) { |
577 | return error; |
578 | } |
579 | NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | TRYEMULROOT, pb); |
580 | if (namei(&nd) == 0) { |
581 | struct stat sb; |
582 | |
583 | if (vn_stat(nd.ni_vp, &sb) == 0 |
584 | && S_ISDIR(sb.st_mode)) |
585 | error = EISDIR; |
586 | |
587 | vput(nd.ni_vp); |
588 | } |
589 | pathbuf_destroy(pb); |
590 | return error ? error : EPERM; |
591 | } |
592 | |
593 | int |
594 | linux_sys_unlink(struct lwp *l, const struct linux_sys_unlink_args *uap, register_t *retval) |
595 | { |
596 | /* { |
597 | syscallarg(const char *) path; |
598 | } */ |
599 | int error; |
600 | |
601 | error = sys_unlink(l, (const void *)uap, retval); |
602 | if (error == EPERM) |
603 | error = linux_unlink_dircheck(SCARG(uap, path)); |
604 | |
605 | return error; |
606 | } |
607 | |
608 | int |
609 | linux_sys_unlinkat(struct lwp *l, const struct linux_sys_unlinkat_args *uap, register_t *retval) |
610 | { |
611 | /* { |
612 | syscallarg(int) fd; |
613 | syscallarg(const char *) path; |
614 | syscallarg(int) flag; |
615 | } */ |
616 | struct sys_unlinkat_args ua; |
617 | int error; |
618 | |
619 | SCARG(&ua, fd) = SCARG(uap, fd); |
620 | SCARG(&ua, path) = SCARG(uap, path); |
621 | SCARG(&ua, flag) = linux_to_bsd_atflags(SCARG(uap, flag)); |
622 | |
623 | error = sys_unlinkat(l, &ua, retval); |
624 | if (error == EPERM) |
625 | error = linux_unlink_dircheck(SCARG(uap, path)); |
626 | |
627 | return error; |
628 | } |
629 | |
630 | int |
631 | linux_sys_mknod(struct lwp *l, const struct linux_sys_mknod_args *uap, register_t *retval) |
632 | { |
633 | /* { |
634 | syscallarg(const char *) path; |
635 | syscallarg(linux_umode_t) mode; |
636 | syscallarg(unsigned) dev; |
637 | } */ |
638 | struct linux_sys_mknodat_args ua; |
639 | |
640 | SCARG(&ua, fd) = LINUX_AT_FDCWD; |
641 | SCARG(&ua, path) = SCARG(uap, path); |
642 | SCARG(&ua, mode) = SCARG(uap, mode); |
643 | SCARG(&ua, dev) = SCARG(uap, dev); |
644 | |
645 | return linux_sys_mknodat(l, &ua, retval); |
646 | } |
647 | |
648 | int |
649 | linux_sys_mknodat(struct lwp *l, const struct linux_sys_mknodat_args *uap, register_t *retval) |
650 | { |
651 | /* { |
652 | syscallarg(int) fd; |
653 | syscallarg(const char *) path; |
654 | syscallarg(linux_umode_t) mode; |
655 | syscallarg(unsigned) dev; |
656 | } */ |
657 | |
658 | /* |
659 | * BSD handles FIFOs separately |
660 | */ |
661 | if (S_ISFIFO(SCARG(uap, mode))) { |
662 | struct sys_mkfifoat_args bma; |
663 | |
664 | SCARG(&bma, fd) = SCARG(uap, fd); |
665 | SCARG(&bma, path) = SCARG(uap, path); |
666 | SCARG(&bma, mode) = SCARG(uap, mode); |
667 | return sys_mkfifoat(l, &bma, retval); |
668 | } else { |
669 | |
670 | /* |
671 | * Linux device numbers uses 8 bits for minor and 8 bits |
672 | * for major. Due to how we map our major and minor, |
673 | * this just fits into our dev_t. Just mask off the |
674 | * upper 16bit to remove any random junk. |
675 | */ |
676 | |
677 | return do_sys_mknodat(l, SCARG(uap, fd), SCARG(uap, path), |
678 | SCARG(uap, mode), SCARG(uap, dev) & 0xffff, retval, |
679 | UIO_USERSPACE); |
680 | } |
681 | } |
682 | |
683 | int |
684 | linux_sys_fchmodat(struct lwp *l, const struct linux_sys_fchmodat_args *uap, register_t *retval) |
685 | { |
686 | /* { |
687 | syscallarg(int) fd; |
688 | syscallarg(const char *) path; |
689 | syscallarg(linux_umode_t) mode; |
690 | } */ |
691 | |
692 | return do_sys_chmodat(l, SCARG(uap, fd), SCARG(uap, path), |
693 | SCARG(uap, mode), AT_SYMLINK_FOLLOW); |
694 | } |
695 | |
696 | int |
697 | linux_sys_fchownat(struct lwp *l, const struct linux_sys_fchownat_args *uap, register_t *retval) |
698 | { |
699 | /* { |
700 | syscallarg(int) fd; |
701 | syscallarg(const char *) path; |
702 | syscallarg(uid_t) owner; |
703 | syscallarg(gid_t) group; |
704 | syscallarg(int) flag; |
705 | } */ |
706 | int flag; |
707 | |
708 | flag = linux_to_bsd_atflags(SCARG(uap, flag)); |
709 | return do_sys_chownat(l, SCARG(uap, fd), SCARG(uap, path), |
710 | SCARG(uap, owner), SCARG(uap, group), flag); |
711 | } |
712 | |
713 | int |
714 | linux_sys_faccessat(struct lwp *l, const struct linux_sys_faccessat_args *uap, register_t *retval) |
715 | { |
716 | /* { |
717 | syscallarg(int) fd; |
718 | syscallarg(const char *) path; |
719 | syscallarg(int) amode; |
720 | } */ |
721 | |
722 | return do_sys_accessat(l, SCARG(uap, fd), SCARG(uap, path), |
723 | SCARG(uap, amode), AT_SYMLINK_FOLLOW); |
724 | } |
725 | |
726 | /* |
727 | * This is just fsync() for now (just as it is in the Linux kernel) |
728 | * Note: this is not implemented under Linux on Alpha and Arm |
729 | * but should still be defined in our syscalls.master. |
730 | * (syscall #148 on the arm) |
731 | */ |
732 | int |
733 | linux_sys_fdatasync(struct lwp *l, const struct linux_sys_fdatasync_args *uap, register_t *retval) |
734 | { |
735 | /* { |
736 | syscallarg(int) fd; |
737 | } */ |
738 | |
739 | return sys_fsync(l, (const void *)uap, retval); |
740 | } |
741 | |
742 | /* |
743 | * pread(2). |
744 | */ |
745 | int |
746 | linux_sys_pread(struct lwp *l, const struct linux_sys_pread_args *uap, register_t *retval) |
747 | { |
748 | /* { |
749 | syscallarg(int) fd; |
750 | syscallarg(void *) buf; |
751 | syscallarg(size_t) nbyte; |
752 | syscallarg(off_t) offset; |
753 | } */ |
754 | struct sys_pread_args pra; |
755 | |
756 | SCARG(&pra, fd) = SCARG(uap, fd); |
757 | SCARG(&pra, buf) = SCARG(uap, buf); |
758 | SCARG(&pra, nbyte) = SCARG(uap, nbyte); |
759 | SCARG(&pra, PAD) = 0; |
760 | SCARG(&pra, offset) = SCARG(uap, offset); |
761 | |
762 | return sys_pread(l, &pra, retval); |
763 | } |
764 | |
765 | /* |
766 | * pwrite(2). |
767 | */ |
768 | int |
769 | linux_sys_pwrite(struct lwp *l, const struct linux_sys_pwrite_args *uap, register_t *retval) |
770 | { |
771 | /* { |
772 | syscallarg(int) fd; |
773 | syscallarg(void *) buf; |
774 | syscallarg(size_t) nbyte; |
775 | syscallarg(off_t) offset; |
776 | } */ |
777 | struct sys_pwrite_args pra; |
778 | |
779 | SCARG(&pra, fd) = SCARG(uap, fd); |
780 | SCARG(&pra, buf) = SCARG(uap, buf); |
781 | SCARG(&pra, nbyte) = SCARG(uap, nbyte); |
782 | SCARG(&pra, PAD) = 0; |
783 | SCARG(&pra, offset) = SCARG(uap, offset); |
784 | |
785 | return sys_pwrite(l, &pra, retval); |
786 | } |
787 | |
788 | int |
789 | linux_sys_dup3(struct lwp *l, const struct linux_sys_dup3_args *uap, |
790 | register_t *retval) |
791 | { |
792 | /* { |
793 | syscallarg(int) from; |
794 | syscallarg(int) to; |
795 | syscallarg(int) flags; |
796 | } */ |
797 | int flags; |
798 | |
799 | flags = linux_to_bsd_ioflags(SCARG(uap, flags)); |
800 | if ((flags & ~O_CLOEXEC) != 0) |
801 | return EINVAL; |
802 | |
803 | if (SCARG(uap, from) == SCARG(uap, to)) |
804 | return EINVAL; |
805 | |
806 | return dodup(l, SCARG(uap, from), SCARG(uap, to), flags, retval); |
807 | } |
808 | |
809 | |
810 | int |
811 | linux_to_bsd_atflags(int lflags) |
812 | { |
813 | int bflags = 0; |
814 | |
815 | if (lflags & LINUX_AT_SYMLINK_NOFOLLOW) |
816 | bflags |= AT_SYMLINK_NOFOLLOW; |
817 | if (lflags & LINUX_AT_REMOVEDIR) |
818 | bflags |= AT_REMOVEDIR; |
819 | if (lflags & LINUX_AT_SYMLINK_FOLLOW) |
820 | bflags |= AT_SYMLINK_FOLLOW; |
821 | |
822 | return bflags; |
823 | } |
824 | |
825 | |
826 | #define LINUX_NOT_SUPPORTED(fun) \ |
827 | int \ |
828 | fun(struct lwp *l, const struct fun##_args *uap, register_t *retval) \ |
829 | { \ |
830 | return EOPNOTSUPP; \ |
831 | } |
832 | |
833 | LINUX_NOT_SUPPORTED(linux_sys_setxattr) |
834 | LINUX_NOT_SUPPORTED(linux_sys_lsetxattr) |
835 | LINUX_NOT_SUPPORTED(linux_sys_fsetxattr) |
836 | |
837 | LINUX_NOT_SUPPORTED(linux_sys_getxattr) |
838 | LINUX_NOT_SUPPORTED(linux_sys_lgetxattr) |
839 | LINUX_NOT_SUPPORTED(linux_sys_fgetxattr) |
840 | |
841 | LINUX_NOT_SUPPORTED(linux_sys_listxattr) |
842 | LINUX_NOT_SUPPORTED(linux_sys_llistxattr) |
843 | LINUX_NOT_SUPPORTED(linux_sys_flistxattr) |
844 | |
845 | LINUX_NOT_SUPPORTED(linux_sys_removexattr) |
846 | LINUX_NOT_SUPPORTED(linux_sys_lremovexattr) |
847 | LINUX_NOT_SUPPORTED(linux_sys_fremovexattr) |
848 | |