1 | /* $NetBSD: linux32_misc.c,v 1.25 2014/11/22 13:12:22 njoly Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 1995, 1998, 1999 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; by Jason R. Thorpe |
9 | * of the Numerical Aerospace Simulation Facility, NASA Ames Research Center; |
10 | * by Edgar Fu\ss, Mathematisches Institut der Uni Bonn. |
11 | * |
12 | * Redistribution and use in source and binary forms, with or without |
13 | * modification, are permitted provided that the following conditions |
14 | * are met: |
15 | * 1. Redistributions of source code must retain the above copyright |
16 | * notice, this list of conditions and the following disclaimer. |
17 | * 2. Redistributions in binary form must reproduce the above copyright |
18 | * notice, this list of conditions and the following disclaimer in the |
19 | * documentation and/or other materials provided with the distribution. |
20 | * |
21 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
22 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
23 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
24 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
25 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
26 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
27 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
29 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
30 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
31 | * POSSIBILITY OF SUCH DAMAGE. |
32 | */ |
33 | |
34 | #include <sys/cdefs.h> |
35 | __KERNEL_RCSID(0, "$NetBSD: linux32_misc.c,v 1.25 2014/11/22 13:12:22 njoly Exp $" ); |
36 | |
37 | #include <sys/param.h> |
38 | #include <sys/proc.h> |
39 | #include <sys/time.h> |
40 | #include <sys/types.h> |
41 | #include <sys/fstypes.h> |
42 | #include <sys/vfs_syscalls.h> |
43 | #include <sys/ptrace.h> |
44 | #include <sys/syscall.h> |
45 | #include <sys/poll.h> |
46 | |
47 | #include <compat/netbsd32/netbsd32.h> |
48 | #include <compat/netbsd32/netbsd32_syscallargs.h> |
49 | |
50 | #include <compat/linux/common/linux_types.h> |
51 | |
52 | #include <compat/linux32/common/linux32_types.h> |
53 | #include <compat/linux32/common/linux32_signal.h> |
54 | #include <compat/linux32/common/linux32_sched.h> |
55 | #include <compat/linux32/linux32_syscallargs.h> |
56 | |
57 | #include <compat/linux/common/linux_ptrace.h> |
58 | #include <compat/linux/common/linux_emuldata.h> |
59 | #include <compat/linux/common/linux_signal.h> |
60 | #include <compat/linux/common/linux_misc.h> |
61 | #include <compat/linux/common/linux_statfs.h> |
62 | #include <compat/linux/common/linux_ipc.h> |
63 | #include <compat/linux/common/linux_sem.h> |
64 | #include <compat/linux/common/linux_futex.h> |
65 | #include <compat/linux/linux_syscallargs.h> |
66 | |
67 | extern const struct linux_mnttypes linux_fstypes[]; |
68 | extern const int linux_fstypes_cnt; |
69 | |
70 | void linux32_to_native_timespec(struct timespec *, struct linux32_timespec *); |
71 | |
72 | /* |
73 | * Implement the fs stat functions. Straightforward. |
74 | */ |
75 | int |
76 | linux32_sys_statfs(struct lwp *l, const struct linux32_sys_statfs_args *uap, register_t *retval) |
77 | { |
78 | /* { |
79 | syscallarg(const netbsd32_charp char) path; |
80 | syscallarg(linux32_statfsp) sp; |
81 | } */ |
82 | struct statvfs *sb; |
83 | struct linux_statfs ltmp; |
84 | int error; |
85 | |
86 | sb = STATVFSBUF_GET(); |
87 | error = do_sys_pstatvfs(l, SCARG_P32(uap, path), ST_WAIT, sb); |
88 | if (error == 0) { |
89 | bsd_to_linux_statfs(sb, <mp); |
90 | error = copyout(<mp, SCARG_P32(uap, sp), sizeof ltmp); |
91 | } |
92 | |
93 | STATVFSBUF_PUT(sb); |
94 | return error; |
95 | } |
96 | |
97 | int |
98 | linux32_sys_fstatfs(struct lwp *l, const struct linux32_sys_fstatfs_args *uap, register_t *retval) |
99 | { |
100 | /* { |
101 | syscallarg(int) fd; |
102 | syscallarg(linux32_statfsp) sp; |
103 | } */ |
104 | struct statvfs *sb; |
105 | struct linux_statfs ltmp; |
106 | int error; |
107 | |
108 | sb = STATVFSBUF_GET(); |
109 | error = do_sys_fstatvfs(l, SCARG(uap, fd), ST_WAIT, sb); |
110 | if (error == 0) { |
111 | bsd_to_linux_statfs(sb, <mp); |
112 | error = copyout(<mp, SCARG_P32(uap, sp), sizeof ltmp); |
113 | } |
114 | STATVFSBUF_PUT(sb); |
115 | |
116 | return error; |
117 | } |
118 | |
119 | int |
120 | linux32_sys_statfs64(struct lwp *l, const struct linux32_sys_statfs64_args *uap, register_t *retval) |
121 | { |
122 | /* { |
123 | syscallarg(const netbsd32_charp char) path; |
124 | syscallarg(linux32_statfs64p) sp; |
125 | } */ |
126 | struct statvfs *sb; |
127 | struct linux_statfs64 ltmp; |
128 | int error; |
129 | |
130 | sb = STATVFSBUF_GET(); |
131 | error = do_sys_pstatvfs(l, SCARG_P32(uap, path), ST_WAIT, sb); |
132 | if (error == 0) { |
133 | bsd_to_linux_statfs64(sb, <mp); |
134 | error = copyout(<mp, SCARG_P32(uap, sp), sizeof ltmp); |
135 | } |
136 | |
137 | STATVFSBUF_PUT(sb); |
138 | return error; |
139 | } |
140 | |
141 | int |
142 | linux32_sys_fstatfs64(struct lwp *l, const struct linux32_sys_fstatfs64_args *uap, register_t *retval) |
143 | { |
144 | /* { |
145 | syscallarg(int) fd; |
146 | syscallarg(linux32_statfs64p) sp; |
147 | } */ |
148 | struct statvfs *sb; |
149 | struct linux_statfs64 ltmp; |
150 | int error; |
151 | |
152 | sb = STATVFSBUF_GET(); |
153 | error = do_sys_fstatvfs(l, SCARG(uap, fd), ST_WAIT, sb); |
154 | if (error == 0) { |
155 | bsd_to_linux_statfs64(sb, <mp); |
156 | error = copyout(<mp, SCARG_P32(uap, sp), sizeof ltmp); |
157 | } |
158 | STATVFSBUF_PUT(sb); |
159 | |
160 | return error; |
161 | } |
162 | |
163 | extern const int linux_ptrace_request_map[]; |
164 | |
165 | int |
166 | linux32_sys_ptrace(struct lwp *l, const struct linux32_sys_ptrace_args *uap, register_t *retval) |
167 | { |
168 | /* { |
169 | i386, m68k, powerpc: T=int |
170 | alpha, amd64: T=long |
171 | syscallarg(T) request; |
172 | syscallarg(T) pid; |
173 | syscallarg(T) addr; |
174 | syscallarg(T) data; |
175 | } */ |
176 | const int *ptr; |
177 | int request; |
178 | int error; |
179 | |
180 | ptr = linux_ptrace_request_map; |
181 | request = SCARG(uap, request); |
182 | while (*ptr != -1) |
183 | if (*ptr++ == request) { |
184 | struct sys_ptrace_args pta; |
185 | |
186 | SCARG(&pta, req) = *ptr; |
187 | SCARG(&pta, pid) = SCARG(uap, pid); |
188 | SCARG(&pta, addr) = NETBSD32IPTR64(SCARG(uap, addr)); |
189 | SCARG(&pta, data) = SCARG(uap, data); |
190 | |
191 | /* |
192 | * Linux ptrace(PTRACE_CONT, pid, 0, 0) means actually |
193 | * to continue where the process left off previously. |
194 | * The same thing is achieved by addr == (void *) 1 |
195 | * on NetBSD, so rewrite 'addr' appropriately. |
196 | */ |
197 | if (request == LINUX_PTRACE_CONT && SCARG(uap, addr)==0) |
198 | SCARG(&pta, addr) = (void *) 1; |
199 | |
200 | error = sysent[SYS_ptrace].sy_call(l, &pta, retval); |
201 | if (error) |
202 | return error; |
203 | switch (request) { |
204 | case LINUX_PTRACE_PEEKTEXT: |
205 | case LINUX_PTRACE_PEEKDATA: |
206 | error = copyout (retval, |
207 | NETBSD32IPTR64(SCARG(uap, data)), |
208 | sizeof *retval); |
209 | *retval = SCARG(uap, data); |
210 | break; |
211 | default: |
212 | break; |
213 | } |
214 | return error; |
215 | } |
216 | else |
217 | ptr++; |
218 | |
219 | return EIO; |
220 | } |
221 | |
222 | int |
223 | linux32_sys_personality(struct lwp *l, const struct linux32_sys_personality_args *uap, register_t *retval) |
224 | { |
225 | /* { |
226 | syscallarg(netbsd32_u_long) per; |
227 | } */ |
228 | struct linux_sys_personality_args ua; |
229 | |
230 | NETBSD32TOX_UAP(per, long); |
231 | return linux_sys_personality(l, &ua, retval); |
232 | } |
233 | |
234 | int |
235 | linux32_sys_futex(struct lwp *l, |
236 | const struct linux32_sys_futex_args *uap, register_t *retval) |
237 | { |
238 | /* { |
239 | syscallarg(linux32_intp_t) uaddr; |
240 | syscallarg(int) op; |
241 | syscallarg(int) val; |
242 | syscallarg(linux32_timespecp_t) timeout; |
243 | syscallarg(linux32_intp_t) uaddr2; |
244 | syscallarg(int) val3; |
245 | } */ |
246 | struct linux_sys_futex_args ua; |
247 | struct linux32_timespec lts; |
248 | struct timespec ts = { 0, 0 }; |
249 | int error; |
250 | |
251 | NETBSD32TOP_UAP(uaddr, int); |
252 | NETBSD32TO64_UAP(op); |
253 | NETBSD32TO64_UAP(val); |
254 | NETBSD32TOP_UAP(timeout, struct linux_timespec); |
255 | NETBSD32TOP_UAP(uaddr2, int); |
256 | NETBSD32TO64_UAP(val3); |
257 | if ((SCARG(uap, op) & ~LINUX_FUTEX_PRIVATE_FLAG) == LINUX_FUTEX_WAIT && |
258 | SCARG_P32(uap, timeout) != NULL) { |
259 | if ((error = copyin((void *)SCARG_P32(uap, timeout), |
260 | <s, sizeof(lts))) != 0) { |
261 | return error; |
262 | } |
263 | linux32_to_native_timespec(&ts, <s); |
264 | } |
265 | return linux_do_futex(l, &ua, retval, &ts); |
266 | } |
267 | |
268 | int |
269 | linux32_sys_set_robust_list(struct lwp *l, |
270 | const struct linux32_sys_set_robust_list_args *uap, register_t *retval) |
271 | { |
272 | /* { |
273 | syscallarg(linux32_robust_list_headp_t) head; |
274 | syscallarg(linux32_size_t) len; |
275 | } */ |
276 | struct linux_sys_set_robust_list_args ua; |
277 | struct linux_emuldata *led; |
278 | |
279 | if (SCARG(uap, len) != 12) |
280 | return EINVAL; |
281 | |
282 | NETBSD32TOP_UAP(head, struct robust_list_head); |
283 | NETBSD32TOX64_UAP(len, size_t); |
284 | |
285 | led = l->l_emuldata; |
286 | led->led_robust_head = SCARG(&ua, head); |
287 | *retval = 0; |
288 | return 0; |
289 | } |
290 | |
291 | int |
292 | linux32_sys_get_robust_list(struct lwp *l, |
293 | const struct linux32_sys_get_robust_list_args *uap, register_t *retval) |
294 | { |
295 | /* { |
296 | syscallarg(linux32_robust_list_headpp_t) head; |
297 | syscallarg(linux32_sizep_t) len; |
298 | } */ |
299 | struct linux_sys_get_robust_list_args ua; |
300 | |
301 | NETBSD32TOP_UAP(head, struct robust_list_head *); |
302 | NETBSD32TOP_UAP(len, size_t *); |
303 | return linux_sys_get_robust_list(l, &ua, retval); |
304 | } |
305 | |
306 | int |
307 | linux32_sys_truncate64(struct lwp *l, const struct linux32_sys_truncate64_args *uap, register_t *retval) |
308 | { |
309 | /* { |
310 | syscallarg(netbsd32_charp) path; |
311 | syscallarg(off_t) length; |
312 | } */ |
313 | struct sys_truncate_args ua; |
314 | |
315 | /* Linux doesn't have the 'pad' pseudo-parameter */ |
316 | NETBSD32TOP_UAP(path, const char *); |
317 | SCARG(&ua, PAD) = 0; |
318 | SCARG(&ua, length) = ((off_t)SCARG(uap, lenhi) << 32) + SCARG(uap, lenlo); |
319 | return sys_truncate(l, &ua, retval); |
320 | } |
321 | |
322 | int |
323 | linux32_sys_ftruncate64(struct lwp *l, const struct linux32_sys_ftruncate64_args *uap, register_t *retval) |
324 | { |
325 | /* { |
326 | syscallarg(unsigned int) fd; |
327 | syscallarg(off_t) length; |
328 | } */ |
329 | struct sys_ftruncate_args ua; |
330 | |
331 | /* Linux doesn't have the 'pad' pseudo-parameter */ |
332 | NETBSD32TO64_UAP(fd); |
333 | SCARG(&ua, PAD) = 0; |
334 | SCARG(&ua, length) = ((off_t)SCARG(uap, lenhi) << 32) + SCARG(uap, lenlo); |
335 | return sys_ftruncate(l, &ua, retval); |
336 | } |
337 | |
338 | int |
339 | linux32_sys_setdomainname(struct lwp *l, const struct linux32_sys_setdomainname_args *uap, register_t *retval) |
340 | { |
341 | /* { |
342 | syscallarg(netbsd32_charp) domainname; |
343 | syscallarg(int) len; |
344 | } */ |
345 | struct linux_sys_setdomainname_args ua; |
346 | |
347 | NETBSD32TOP_UAP(domainname, char); |
348 | NETBSD32TO64_UAP(len); |
349 | return linux_sys_setdomainname(l, &ua, retval); |
350 | } |
351 | |
352 | int |
353 | linux32_sys_ppoll(struct lwp *l, const struct linux32_sys_ppoll_args *uap, |
354 | register_t *retval) |
355 | { |
356 | /* { |
357 | syscallarg(netbsd32_pollfdp_t) fds; |
358 | syscallarg(u_int) nfds; |
359 | syscallarg(linux32_timespecp_t) timeout; |
360 | syscallarg(linux32_sigsetp_t) sigset; |
361 | } */ |
362 | struct linux32_timespec lts0, *lts; |
363 | struct timespec ts0, *ts = NULL; |
364 | linux32_sigset_t lsigmask0, *lsigmask; |
365 | sigset_t sigmask0, *sigmask = NULL; |
366 | int error; |
367 | |
368 | lts = SCARG_P32(uap, timeout); |
369 | if (lts) { |
370 | if ((error = copyin(lts, <s0, sizeof(lts0))) != 0) |
371 | return error; |
372 | linux32_to_native_timespec(&ts0, <s0); |
373 | ts = &ts0; |
374 | } |
375 | |
376 | lsigmask = SCARG_P32(uap, sigset); |
377 | if (lsigmask) { |
378 | if ((error = copyin(lsigmask, &lsigmask0, sizeof(lsigmask0)))) |
379 | return error; |
380 | linux32_to_native_sigset(&sigmask0, &lsigmask0); |
381 | sigmask = &sigmask0; |
382 | } |
383 | |
384 | return pollcommon(retval, SCARG_P32(uap, fds), SCARG(uap, nfds), |
385 | ts, sigmask); |
386 | } |
387 | |