1 | /* $NetBSD: linux_misc_notalpha.c,v 1.109 2014/11/09 17:48:08 maxv 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; by Jason R. Thorpe |
9 | * of the Numerical Aerospace Simulation Facility, NASA Ames Research Center. |
10 | * |
11 | * Redistribution and use in source and binary forms, with or without |
12 | * modification, are permitted provided that the following conditions |
13 | * are met: |
14 | * 1. Redistributions of source code must retain the above copyright |
15 | * notice, this list of conditions and the following disclaimer. |
16 | * 2. Redistributions in binary form must reproduce the above copyright |
17 | * notice, this list of conditions and the following disclaimer in the |
18 | * documentation and/or other materials provided with the distribution. |
19 | * |
20 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
21 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
22 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
23 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
24 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
30 | * POSSIBILITY OF SUCH DAMAGE. |
31 | */ |
32 | |
33 | #include <sys/cdefs.h> |
34 | __KERNEL_RCSID(0, "$NetBSD: linux_misc_notalpha.c,v 1.109 2014/11/09 17:48:08 maxv Exp $" ); |
35 | |
36 | /* |
37 | * Note that we must NOT include "opt_compat_linux32.h" here, |
38 | * the maze of ifdefs below relies on COMPAT_LINUX32 only being |
39 | * defined when this file is built for linux32. |
40 | */ |
41 | |
42 | #include <sys/param.h> |
43 | #include <sys/systm.h> |
44 | #include <sys/kernel.h> |
45 | #include <sys/mman.h> |
46 | #include <sys/mount.h> |
47 | #include <sys/mbuf.h> |
48 | #include <sys/namei.h> |
49 | #include <sys/proc.h> |
50 | #include <sys/prot.h> |
51 | #include <sys/ptrace.h> |
52 | #include <sys/resource.h> |
53 | #include <sys/resourcevar.h> |
54 | #include <sys/time.h> |
55 | #include <sys/vfs_syscalls.h> |
56 | #include <sys/wait.h> |
57 | #include <sys/kauth.h> |
58 | |
59 | #include <sys/syscallargs.h> |
60 | |
61 | #include <compat/linux/common/linux_types.h> |
62 | #include <compat/linux/common/linux_fcntl.h> |
63 | #include <compat/linux/common/linux_misc.h> |
64 | #include <compat/linux/common/linux_mmap.h> |
65 | #include <compat/linux/common/linux_signal.h> |
66 | #include <compat/linux/common/linux_util.h> |
67 | #include <compat/linux/common/linux_ipc.h> |
68 | #include <compat/linux/common/linux_sem.h> |
69 | #include <compat/linux/common/linux_statfs.h> |
70 | |
71 | #include <compat/linux/linux_syscallargs.h> |
72 | |
73 | /* |
74 | * This file contains routines which are used |
75 | * on every linux architechture except the Alpha. |
76 | */ |
77 | |
78 | /* Used on: arm, i386, m68k, mips, ppc, sparc, sparc64 */ |
79 | /* Not used on: alpha */ |
80 | |
81 | #ifdef DEBUG_LINUX |
82 | #define DPRINTF(a) uprintf a |
83 | #else |
84 | #define DPRINTF(a) |
85 | #endif |
86 | |
87 | #ifndef COMPAT_LINUX32 |
88 | |
89 | /* |
90 | * Alarm. This is a libc call which uses setitimer(2) in NetBSD. |
91 | * Fiddle with the timers to make it work. |
92 | * |
93 | * XXX This shouldn't be dicking about with the ptimer stuff directly. |
94 | */ |
95 | int |
96 | linux_sys_alarm(struct lwp *l, const struct linux_sys_alarm_args *uap, register_t *retval) |
97 | { |
98 | /* { |
99 | syscallarg(unsigned int) secs; |
100 | } */ |
101 | struct proc *p = l->l_proc; |
102 | struct timespec now; |
103 | struct itimerspec *itp, it; |
104 | struct ptimer *ptp, *spare; |
105 | extern kmutex_t timer_lock; |
106 | struct ptimers *pts; |
107 | |
108 | if ((pts = p->p_timers) == NULL) |
109 | pts = timers_alloc(p); |
110 | spare = NULL; |
111 | |
112 | retry: |
113 | mutex_spin_enter(&timer_lock); |
114 | if (pts && pts->pts_timers[ITIMER_REAL]) |
115 | itp = &pts->pts_timers[ITIMER_REAL]->pt_time; |
116 | else |
117 | itp = NULL; |
118 | /* |
119 | * Clear any pending timer alarms. |
120 | */ |
121 | if (itp) { |
122 | callout_stop(&pts->pts_timers[ITIMER_REAL]->pt_ch); |
123 | timespecclear(&itp->it_interval); |
124 | getnanotime(&now); |
125 | if (timespecisset(&itp->it_value) && |
126 | timespeccmp(&itp->it_value, &now, >)) |
127 | timespecsub(&itp->it_value, &now, &itp->it_value); |
128 | /* |
129 | * Return how many seconds were left (rounded up) |
130 | */ |
131 | retval[0] = itp->it_value.tv_sec; |
132 | if (itp->it_value.tv_nsec) |
133 | retval[0]++; |
134 | } else { |
135 | retval[0] = 0; |
136 | } |
137 | |
138 | /* |
139 | * alarm(0) just resets the timer. |
140 | */ |
141 | if (SCARG(uap, secs) == 0) { |
142 | if (itp) |
143 | timespecclear(&itp->it_value); |
144 | mutex_spin_exit(&timer_lock); |
145 | return 0; |
146 | } |
147 | |
148 | /* |
149 | * Check the new alarm time for sanity, and set it. |
150 | */ |
151 | timespecclear(&it.it_interval); |
152 | it.it_value.tv_sec = SCARG(uap, secs); |
153 | it.it_value.tv_nsec = 0; |
154 | if (itimespecfix(&it.it_value) || itimespecfix(&it.it_interval)) { |
155 | mutex_spin_exit(&timer_lock); |
156 | return (EINVAL); |
157 | } |
158 | |
159 | ptp = pts->pts_timers[ITIMER_REAL]; |
160 | if (ptp == NULL) { |
161 | if (spare == NULL) { |
162 | mutex_spin_exit(&timer_lock); |
163 | spare = pool_get(&ptimer_pool, PR_WAITOK); |
164 | goto retry; |
165 | } |
166 | ptp = spare; |
167 | spare = NULL; |
168 | ptp->pt_ev.sigev_notify = SIGEV_SIGNAL; |
169 | ptp->pt_ev.sigev_signo = SIGALRM; |
170 | ptp->pt_overruns = 0; |
171 | ptp->pt_proc = p; |
172 | ptp->pt_type = CLOCK_REALTIME; |
173 | ptp->pt_entry = CLOCK_REALTIME; |
174 | ptp->pt_active = 0; |
175 | ptp->pt_queued = 0; |
176 | callout_init(&ptp->pt_ch, CALLOUT_MPSAFE); |
177 | pts->pts_timers[ITIMER_REAL] = ptp; |
178 | } |
179 | |
180 | if (timespecisset(&it.it_value)) { |
181 | /* |
182 | * Don't need to check tvhzto() return value, here. |
183 | * callout_reset() does it for us. |
184 | */ |
185 | getnanotime(&now); |
186 | timespecadd(&it.it_value, &now, &it.it_value); |
187 | callout_reset(&ptp->pt_ch, tshzto(&it.it_value), |
188 | realtimerexpire, ptp); |
189 | } |
190 | ptp->pt_time = it; |
191 | mutex_spin_exit(&timer_lock); |
192 | |
193 | return 0; |
194 | } |
195 | #endif /* !COMPAT_LINUX32 */ |
196 | |
197 | #if !defined(__amd64__) |
198 | int |
199 | linux_sys_nice(struct lwp *l, const struct linux_sys_nice_args *uap, register_t *retval) |
200 | { |
201 | /* { |
202 | syscallarg(int) incr; |
203 | } */ |
204 | struct proc *p = l->l_proc; |
205 | struct sys_setpriority_args bsa; |
206 | int error; |
207 | |
208 | SCARG(&bsa, which) = PRIO_PROCESS; |
209 | SCARG(&bsa, who) = 0; |
210 | SCARG(&bsa, prio) = p->p_nice - NZERO + SCARG(uap, incr); |
211 | |
212 | error = sys_setpriority(l, &bsa, retval); |
213 | return (error) ? EPERM : 0; |
214 | } |
215 | #endif /* !__amd64__ */ |
216 | |
217 | #ifndef COMPAT_LINUX32 |
218 | #ifndef __amd64__ |
219 | /* |
220 | * The old Linux readdir was only able to read one entry at a time, |
221 | * even though it had a 'count' argument. In fact, the emulation |
222 | * of the old call was better than the original, because it did handle |
223 | * the count arg properly. Don't bother with it anymore now, and use |
224 | * it to distinguish between old and new. The difference is that the |
225 | * newer one actually does multiple entries, and the reclen field |
226 | * really is the reclen, not the namelength. |
227 | */ |
228 | int |
229 | linux_sys_readdir(struct lwp *l, const struct linux_sys_readdir_args *uap, register_t *retval) |
230 | { |
231 | /* { |
232 | syscallarg(int) fd; |
233 | syscallarg(struct linux_dirent *) dent; |
234 | syscallarg(unsigned int) count; |
235 | } */ |
236 | int error; |
237 | struct linux_sys_getdents_args da; |
238 | |
239 | SCARG(&da, fd) = SCARG(uap, fd); |
240 | SCARG(&da, dent) = SCARG(uap, dent); |
241 | SCARG(&da, count) = 1; |
242 | |
243 | error = linux_sys_getdents(l, &da, retval); |
244 | if (error == 0 && *retval > 1) |
245 | *retval = 1; |
246 | |
247 | return error; |
248 | } |
249 | #endif /* !amd64 */ |
250 | |
251 | /* |
252 | * I wonder why Linux has gettimeofday() _and_ time().. Still, we |
253 | * need to deal with it. |
254 | */ |
255 | int |
256 | linux_sys_time(struct lwp *l, const struct linux_sys_time_args *uap, register_t *retval) |
257 | { |
258 | /* { |
259 | syscallarg(linux_time_t) *t; |
260 | } */ |
261 | struct timeval atv; |
262 | linux_time_t tt; |
263 | int error; |
264 | |
265 | microtime(&atv); |
266 | |
267 | tt = atv.tv_sec; |
268 | if (SCARG(uap, t) && (error = copyout(&tt, SCARG(uap, t), sizeof tt))) |
269 | return error; |
270 | |
271 | retval[0] = tt; |
272 | return 0; |
273 | } |
274 | |
275 | /* |
276 | * utime(). Do conversion to things that utimes() understands, |
277 | * and pass it on. |
278 | */ |
279 | int |
280 | linux_sys_utime(struct lwp *l, const struct linux_sys_utime_args *uap, register_t *retval) |
281 | { |
282 | /* { |
283 | syscallarg(const char *) path; |
284 | syscallarg(struct linux_utimbuf *)times; |
285 | } */ |
286 | int error; |
287 | struct timeval tv[2], *tvp; |
288 | struct linux_utimbuf lut; |
289 | |
290 | if (SCARG(uap, times) != NULL) { |
291 | if ((error = copyin(SCARG(uap, times), &lut, sizeof lut))) |
292 | return error; |
293 | tv[0].tv_usec = tv[1].tv_usec = 0; |
294 | tv[0].tv_sec = lut.l_actime; |
295 | tv[1].tv_sec = lut.l_modtime; |
296 | tvp = tv; |
297 | } else |
298 | tvp = NULL; |
299 | |
300 | return do_sys_utimes(l, NULL, SCARG(uap, path), FOLLOW, |
301 | tvp, UIO_SYSSPACE); |
302 | } |
303 | |
304 | #ifndef __amd64__ |
305 | /* |
306 | * waitpid(2). Just forward on to linux_sys_wait4 with a NULL rusage. |
307 | */ |
308 | int |
309 | linux_sys_waitpid(struct lwp *l, const struct linux_sys_waitpid_args *uap, register_t *retval) |
310 | { |
311 | /* { |
312 | syscallarg(int) pid; |
313 | syscallarg(int *) status; |
314 | syscallarg(int) options; |
315 | } */ |
316 | struct linux_sys_wait4_args linux_w4a; |
317 | |
318 | SCARG(&linux_w4a, pid) = SCARG(uap, pid); |
319 | SCARG(&linux_w4a, status) = SCARG(uap, status); |
320 | SCARG(&linux_w4a, options) = SCARG(uap, options); |
321 | SCARG(&linux_w4a, rusage) = NULL; |
322 | |
323 | return linux_sys_wait4(l, &linux_w4a, retval); |
324 | } |
325 | #endif /* !amd64 */ |
326 | |
327 | int |
328 | linux_sys_setresgid(struct lwp *l, const struct linux_sys_setresgid_args *uap, register_t *retval) |
329 | { |
330 | /* { |
331 | syscallarg(gid_t) rgid; |
332 | syscallarg(gid_t) egid; |
333 | syscallarg(gid_t) sgid; |
334 | } */ |
335 | |
336 | /* |
337 | * Note: These checks are a little different than the NetBSD |
338 | * setregid(2) call performs. This precisely follows the |
339 | * behavior of the Linux kernel. |
340 | */ |
341 | return do_setresgid(l, SCARG(uap,rgid), SCARG(uap, egid), |
342 | SCARG(uap, sgid), |
343 | ID_R_EQ_R | ID_R_EQ_E | ID_R_EQ_S | |
344 | ID_E_EQ_R | ID_E_EQ_E | ID_E_EQ_S | |
345 | ID_S_EQ_R | ID_S_EQ_E | ID_S_EQ_S ); |
346 | } |
347 | |
348 | int |
349 | linux_sys_getresgid(struct lwp *l, const struct linux_sys_getresgid_args *uap, register_t *retval) |
350 | { |
351 | /* { |
352 | syscallarg(gid_t *) rgid; |
353 | syscallarg(gid_t *) egid; |
354 | syscallarg(gid_t *) sgid; |
355 | } */ |
356 | kauth_cred_t pc = l->l_cred; |
357 | int error; |
358 | gid_t gid; |
359 | |
360 | /* |
361 | * Linux copies these values out to userspace like so: |
362 | * |
363 | * 1. Copy out rgid. |
364 | * 2. If that succeeds, copy out egid. |
365 | * 3. If both of those succeed, copy out sgid. |
366 | */ |
367 | gid = kauth_cred_getgid(pc); |
368 | if ((error = copyout(&gid, SCARG(uap, rgid), sizeof(gid_t))) != 0) |
369 | return (error); |
370 | |
371 | gid = kauth_cred_getegid(pc); |
372 | if ((error = copyout(&gid, SCARG(uap, egid), sizeof(gid_t))) != 0) |
373 | return (error); |
374 | |
375 | gid = kauth_cred_getsvgid(pc); |
376 | |
377 | return (copyout(&gid, SCARG(uap, sgid), sizeof(gid_t))); |
378 | } |
379 | |
380 | #ifndef __amd64__ |
381 | /* |
382 | * I wonder why Linux has settimeofday() _and_ stime().. Still, we |
383 | * need to deal with it. |
384 | */ |
385 | int |
386 | linux_sys_stime(struct lwp *l, const struct linux_sys_stime_args *uap, register_t *retval) |
387 | { |
388 | /* { |
389 | syscallarg(linux_time_t) *t; |
390 | } */ |
391 | struct timespec ats; |
392 | linux_time_t tt; |
393 | int error; |
394 | |
395 | if ((error = copyin(SCARG(uap, t), &tt, sizeof tt)) != 0) |
396 | return error; |
397 | |
398 | ats.tv_sec = tt; |
399 | ats.tv_nsec = 0; |
400 | |
401 | if ((error = settime(l->l_proc, &ats))) |
402 | return (error); |
403 | |
404 | return 0; |
405 | } |
406 | |
407 | /* |
408 | * Implement the fs stat functions. Straightforward. |
409 | */ |
410 | int |
411 | linux_sys_statfs64(struct lwp *l, const struct linux_sys_statfs64_args *uap, register_t *retval) |
412 | { |
413 | /* { |
414 | syscallarg(const char *) path; |
415 | syscallarg(size_t) sz; |
416 | syscallarg(struct linux_statfs64 *) sp; |
417 | } */ |
418 | struct statvfs *sb; |
419 | struct linux_statfs64 ltmp; |
420 | int error; |
421 | |
422 | if (SCARG(uap, sz) != sizeof ltmp) |
423 | return (EINVAL); |
424 | |
425 | sb = STATVFSBUF_GET(); |
426 | error = do_sys_pstatvfs(l, SCARG(uap, path), ST_WAIT, sb); |
427 | if (error == 0) { |
428 | bsd_to_linux_statfs64(sb, <mp); |
429 | error = copyout(<mp, SCARG(uap, sp), sizeof ltmp); |
430 | } |
431 | STATVFSBUF_PUT(sb); |
432 | return error; |
433 | } |
434 | |
435 | int |
436 | linux_sys_fstatfs64(struct lwp *l, const struct linux_sys_fstatfs64_args *uap, register_t *retval) |
437 | { |
438 | /* { |
439 | syscallarg(int) fd; |
440 | syscallarg(size_t) sz; |
441 | syscallarg(struct linux_statfs64 *) sp; |
442 | } */ |
443 | struct statvfs *sb; |
444 | struct linux_statfs64 ltmp; |
445 | int error; |
446 | |
447 | if (SCARG(uap, sz) != sizeof ltmp) |
448 | return (EINVAL); |
449 | |
450 | sb = STATVFSBUF_GET(); |
451 | error = do_sys_fstatvfs(l, SCARG(uap, fd), ST_WAIT, sb); |
452 | if (error == 0) { |
453 | bsd_to_linux_statfs64(sb, <mp); |
454 | error = copyout(<mp, SCARG(uap, sp), sizeof ltmp); |
455 | } |
456 | STATVFSBUF_PUT(sb); |
457 | return error; |
458 | } |
459 | #endif /* !__amd64__ */ |
460 | #endif /* !COMPAT_LINUX32 */ |
461 | |