1 | /* $NetBSD: netbsd32_time.c,v 1.48 2016/09/23 14:16:32 skrll Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 1998, 2001 Matthew R. Green |
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 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
21 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
25 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
26 | * SUCH DAMAGE. |
27 | */ |
28 | |
29 | #include <sys/cdefs.h> |
30 | __KERNEL_RCSID(0, "$NetBSD: netbsd32_time.c,v 1.48 2016/09/23 14:16:32 skrll Exp $" ); |
31 | |
32 | #if defined(_KERNEL_OPT) |
33 | #include "opt_ntp.h" |
34 | #include "opt_compat_netbsd.h" |
35 | #endif |
36 | |
37 | #include <sys/param.h> |
38 | #include <sys/systm.h> |
39 | #include <sys/mount.h> |
40 | #include <sys/time.h> |
41 | #include <sys/timex.h> |
42 | #include <sys/timevar.h> |
43 | #include <sys/proc.h> |
44 | #include <sys/pool.h> |
45 | #include <sys/resourcevar.h> |
46 | #include <sys/dirent.h> |
47 | #include <sys/kauth.h> |
48 | |
49 | #include <compat/netbsd32/netbsd32.h> |
50 | #include <compat/netbsd32/netbsd32_syscallargs.h> |
51 | #include <compat/netbsd32/netbsd32_conv.h> |
52 | |
53 | #ifdef NTP |
54 | |
55 | int |
56 | netbsd32___ntp_gettime50(struct lwp *l, |
57 | const struct netbsd32___ntp_gettime50_args *uap, register_t *retval) |
58 | { |
59 | /* { |
60 | syscallarg(netbsd32_ntptimevalp_t) ntvp; |
61 | } */ |
62 | struct netbsd32_ntptimeval ntv32; |
63 | struct ntptimeval ntv; |
64 | int error = 0; |
65 | |
66 | if (SCARG_P32(uap, ntvp)) { |
67 | ntp_gettime(&ntv); |
68 | |
69 | ntv32.time.tv_sec = ntv.time.tv_sec; |
70 | ntv32.time.tv_nsec = ntv.time.tv_nsec; |
71 | ntv32.maxerror = (netbsd32_long)ntv.maxerror; |
72 | ntv32.esterror = (netbsd32_long)ntv.esterror; |
73 | ntv32.tai = (netbsd32_long)ntv.tai; |
74 | ntv32.time_state = ntv.time_state; |
75 | error = copyout(&ntv32, SCARG_P32(uap, ntvp), sizeof(ntv32)); |
76 | } |
77 | if (!error) { |
78 | *retval = ntp_timestatus(); |
79 | } |
80 | |
81 | return (error); |
82 | } |
83 | |
84 | #ifdef COMPAT_50 |
85 | int |
86 | compat_50_netbsd32_ntp_gettime(struct lwp *l, |
87 | const struct compat_50_netbsd32_ntp_gettime_args *uap, register_t *retval) |
88 | { |
89 | /* { |
90 | syscallarg(netbsd32_ntptimeval50p_t) ntvp; |
91 | } */ |
92 | struct netbsd32_ntptimeval50 ntv32; |
93 | struct ntptimeval ntv; |
94 | int error = 0; |
95 | |
96 | if (SCARG_P32(uap, ntvp)) { |
97 | ntp_gettime(&ntv); |
98 | |
99 | ntv32.time.tv_sec = (int32_t)ntv.time.tv_sec; |
100 | ntv32.time.tv_nsec = ntv.time.tv_nsec; |
101 | ntv32.maxerror = (netbsd32_long)ntv.maxerror; |
102 | ntv32.esterror = (netbsd32_long)ntv.esterror; |
103 | ntv32.tai = (netbsd32_long)ntv.tai; |
104 | ntv32.time_state = ntv.time_state; |
105 | error = copyout(&ntv32, SCARG_P32(uap, ntvp), sizeof(ntv32)); |
106 | } |
107 | if (!error) { |
108 | *retval = ntp_timestatus(); |
109 | } |
110 | |
111 | return (error); |
112 | } |
113 | #endif |
114 | |
115 | #ifdef COMPAT_30 |
116 | int |
117 | compat_30_netbsd32_ntp_gettime(struct lwp *l, const struct compat_30_netbsd32_ntp_gettime_args *uap, register_t *retval) |
118 | { |
119 | /* { |
120 | syscallarg(netbsd32_ntptimevalp_t) ntvp; |
121 | } */ |
122 | struct netbsd32_ntptimeval30 ntv32; |
123 | struct ntptimeval ntv; |
124 | int error = 0; |
125 | |
126 | if (SCARG_P32(uap, ntvp)) { |
127 | ntp_gettime(&ntv); |
128 | |
129 | ntv32.time.tv_sec = ntv.time.tv_sec; |
130 | ntv32.time.tv_usec = ntv.time.tv_nsec / 1000; |
131 | ntv32.maxerror = (netbsd32_long)ntv.maxerror; |
132 | ntv32.esterror = (netbsd32_long)ntv.esterror; |
133 | error = copyout(&ntv32, SCARG_P32(uap, ntvp), sizeof(ntv32)); |
134 | } |
135 | if (!error) { |
136 | *retval = ntp_timestatus(); |
137 | } |
138 | |
139 | return (error); |
140 | } |
141 | #endif |
142 | |
143 | int |
144 | netbsd32_ntp_adjtime(struct lwp *l, const struct netbsd32_ntp_adjtime_args *uap, register_t *retval) |
145 | { |
146 | /* { |
147 | syscallarg(netbsd32_timexp_t) tp; |
148 | } */ |
149 | struct netbsd32_timex ntv32; |
150 | struct timex ntv; |
151 | int error = 0; |
152 | int modes; |
153 | |
154 | if ((error = copyin(SCARG_P32(uap, tp), &ntv32, sizeof(ntv32)))) |
155 | return (error); |
156 | |
157 | netbsd32_to_timex(&ntv32, &ntv); |
158 | |
159 | /* |
160 | * Update selected clock variables - only the superuser can |
161 | * change anything. Note that there is no error checking here on |
162 | * the assumption the superuser should know what it is doing. |
163 | */ |
164 | modes = ntv.modes; |
165 | if (modes != 0 && (error = kauth_authorize_system(l->l_cred, |
166 | KAUTH_SYSTEM_TIME, KAUTH_REQ_SYSTEM_TIME_NTPADJTIME, NULL, NULL, |
167 | NULL))) |
168 | return (error); |
169 | |
170 | ntp_adjtime1(&ntv); |
171 | |
172 | netbsd32_from_timex(&ntv, &ntv32); |
173 | error = copyout(&ntv32, SCARG_P32(uap, tp), sizeof(ntv32)); |
174 | if (!error) { |
175 | *retval = ntp_timestatus(); |
176 | } |
177 | return error; |
178 | } |
179 | #endif /* NTP */ |
180 | |
181 | int |
182 | netbsd32___setitimer50(struct lwp *l, const struct netbsd32___setitimer50_args *uap, register_t *retval) |
183 | { |
184 | /* { |
185 | syscallarg(int) which; |
186 | syscallarg(const netbsd32_itimervalp_t) itv; |
187 | syscallarg(netbsd32_itimervalp_t) oitv; |
188 | } */ |
189 | struct proc *p = l->l_proc; |
190 | struct netbsd32_itimerval s32it, *itv32; |
191 | int which = SCARG(uap, which); |
192 | struct netbsd32___getitimer50_args getargs; |
193 | struct itimerval aitv; |
194 | int error; |
195 | |
196 | if ((u_int)which > ITIMER_PROF) |
197 | return (EINVAL); |
198 | itv32 = SCARG_P32(uap, itv); |
199 | if (itv32) { |
200 | if ((error = copyin(itv32, &s32it, sizeof(s32it)))) |
201 | return (error); |
202 | netbsd32_to_itimerval(&s32it, &aitv); |
203 | } |
204 | if (SCARG_P32(uap, oitv) != 0) { |
205 | SCARG(&getargs, which) = which; |
206 | SCARG(&getargs, itv) = SCARG(uap, oitv); |
207 | if ((error = netbsd32___getitimer50(l, &getargs, retval)) != 0) |
208 | return (error); |
209 | } |
210 | if (itv32 == 0) |
211 | return 0; |
212 | |
213 | return dosetitimer(p, which, &aitv); |
214 | } |
215 | |
216 | int |
217 | netbsd32___getitimer50(struct lwp *l, const struct netbsd32___getitimer50_args *uap, register_t *retval) |
218 | { |
219 | /* { |
220 | syscallarg(int) which; |
221 | syscallarg(netbsd32_itimervalp_t) itv; |
222 | } */ |
223 | struct proc *p = l->l_proc; |
224 | struct netbsd32_itimerval s32it; |
225 | struct itimerval aitv; |
226 | int error; |
227 | |
228 | error = dogetitimer(p, SCARG(uap, which), &aitv); |
229 | if (error) |
230 | return error; |
231 | |
232 | netbsd32_from_itimerval(&aitv, &s32it); |
233 | return copyout(&s32it, SCARG_P32(uap, itv), sizeof(s32it)); |
234 | } |
235 | |
236 | int |
237 | netbsd32___gettimeofday50(struct lwp *l, const struct netbsd32___gettimeofday50_args *uap, register_t *retval) |
238 | { |
239 | /* { |
240 | syscallarg(netbsd32_timevalp_t) tp; |
241 | syscallarg(netbsd32_timezonep_t) tzp; |
242 | } */ |
243 | struct timeval atv; |
244 | struct netbsd32_timeval tv32; |
245 | int error = 0; |
246 | struct netbsd32_timezone tzfake; |
247 | |
248 | if (SCARG_P32(uap, tp)) { |
249 | microtime(&atv); |
250 | netbsd32_from_timeval(&atv, &tv32); |
251 | error = copyout(&tv32, SCARG_P32(uap, tp), sizeof(tv32)); |
252 | if (error) |
253 | return (error); |
254 | } |
255 | if (SCARG_P32(uap, tzp)) { |
256 | /* |
257 | * NetBSD has no kernel notion of time zone, so we just |
258 | * fake up a timezone struct and return it if demanded. |
259 | */ |
260 | tzfake.tz_minuteswest = 0; |
261 | tzfake.tz_dsttime = 0; |
262 | error = copyout(&tzfake, SCARG_P32(uap, tzp), sizeof(tzfake)); |
263 | } |
264 | return (error); |
265 | } |
266 | |
267 | int |
268 | netbsd32___settimeofday50(struct lwp *l, const struct netbsd32___settimeofday50_args *uap, register_t *retval) |
269 | { |
270 | /* { |
271 | syscallarg(const netbsd32_timevalp_t) tv; |
272 | syscallarg(const netbsd32_timezonep_t) tzp; |
273 | } */ |
274 | struct netbsd32_timeval atv32; |
275 | struct timeval atv; |
276 | struct timespec ats; |
277 | int error; |
278 | struct proc *p = l->l_proc; |
279 | |
280 | /* Verify all parameters before changing time. */ |
281 | |
282 | /* |
283 | * NetBSD has no kernel notion of time zone, and only an |
284 | * obsolete program would try to set it, so we log a warning. |
285 | */ |
286 | if (SCARG_P32(uap, tzp)) |
287 | printf("pid %d attempted to set the " |
288 | "(obsolete) kernel time zone\n" , p->p_pid); |
289 | |
290 | if (SCARG_P32(uap, tv) == 0) |
291 | return 0; |
292 | |
293 | if ((error = copyin(SCARG_P32(uap, tv), &atv32, sizeof(atv32))) != 0) |
294 | return error; |
295 | |
296 | netbsd32_to_timeval(&atv32, &atv); |
297 | TIMEVAL_TO_TIMESPEC(&atv, &ats); |
298 | return settime(p, &ats); |
299 | } |
300 | |
301 | int |
302 | netbsd32___adjtime50(struct lwp *l, const struct netbsd32___adjtime50_args *uap, register_t *retval) |
303 | { |
304 | /* { |
305 | syscallarg(const netbsd32_timevalp_t) delta; |
306 | syscallarg(netbsd32_timevalp_t) olddelta; |
307 | } */ |
308 | struct netbsd32_timeval atv; |
309 | int error; |
310 | |
311 | extern int time_adjusted; /* in kern_ntptime.c */ |
312 | extern int64_t time_adjtime; /* in kern_ntptime.c */ |
313 | |
314 | if ((error = kauth_authorize_system(l->l_cred, |
315 | KAUTH_SYSTEM_TIME, KAUTH_REQ_SYSTEM_TIME_ADJTIME, NULL, NULL, |
316 | NULL)) != 0) |
317 | return (error); |
318 | |
319 | if (SCARG_P32(uap, olddelta)) { |
320 | atv.tv_sec = time_adjtime / 1000000; |
321 | atv.tv_usec = time_adjtime % 1000000; |
322 | if (atv.tv_usec < 0) { |
323 | atv.tv_usec += 1000000; |
324 | atv.tv_sec--; |
325 | } |
326 | error = copyout(&atv, SCARG_P32(uap, olddelta), sizeof(atv)); |
327 | if (error) |
328 | return (error); |
329 | } |
330 | |
331 | if (SCARG_P32(uap, delta)) { |
332 | error = copyin(SCARG_P32(uap, delta), &atv, sizeof(atv)); |
333 | if (error) |
334 | return (error); |
335 | |
336 | time_adjtime = (int64_t)atv.tv_sec * 1000000 + atv.tv_usec; |
337 | |
338 | if (time_adjtime) |
339 | /* We need to save the system time during shutdown */ |
340 | time_adjusted |= 1; |
341 | } |
342 | |
343 | return (0); |
344 | } |
345 | |
346 | int |
347 | netbsd32___clock_gettime50(struct lwp *l, const struct netbsd32___clock_gettime50_args *uap, register_t *retval) |
348 | { |
349 | /* { |
350 | syscallarg(netbsd32_clockid_t) clock_id; |
351 | syscallarg(netbsd32_timespecp_t) tp; |
352 | } */ |
353 | int error; |
354 | struct timespec ats; |
355 | struct netbsd32_timespec ts32; |
356 | |
357 | error = clock_gettime1(SCARG(uap, clock_id), &ats); |
358 | if (error != 0) |
359 | return error; |
360 | |
361 | netbsd32_from_timespec(&ats, &ts32); |
362 | return copyout(&ts32, SCARG_P32(uap, tp), sizeof(ts32)); |
363 | } |
364 | |
365 | int |
366 | netbsd32___clock_settime50(struct lwp *l, const struct netbsd32___clock_settime50_args *uap, register_t *retval) |
367 | { |
368 | /* { |
369 | syscallarg(netbsd32_clockid_t) clock_id; |
370 | syscallarg(const netbsd32_timespecp_t) tp; |
371 | } */ |
372 | struct netbsd32_timespec ts32; |
373 | struct timespec ats; |
374 | int error; |
375 | |
376 | if ((error = copyin(SCARG_P32(uap, tp), &ts32, sizeof(ts32))) != 0) |
377 | return (error); |
378 | |
379 | netbsd32_to_timespec(&ts32, &ats); |
380 | return clock_settime1(l->l_proc, SCARG(uap, clock_id), &ats, true); |
381 | } |
382 | |
383 | int |
384 | netbsd32___clock_getres50(struct lwp *l, const struct netbsd32___clock_getres50_args *uap, register_t *retval) |
385 | { |
386 | /* { |
387 | syscallarg(netbsd32_clockid_t) clock_id; |
388 | syscallarg(netbsd32_timespecp_t) tp; |
389 | } */ |
390 | struct netbsd32_timespec ts32; |
391 | struct timespec ts; |
392 | int error = 0; |
393 | |
394 | error = clock_getres1(SCARG(uap, clock_id), &ts); |
395 | if (error != 0) |
396 | return error; |
397 | |
398 | if (SCARG_P32(uap, tp)) { |
399 | netbsd32_from_timespec(&ts, &ts32); |
400 | error = copyout(&ts32, SCARG_P32(uap, tp), sizeof(ts32)); |
401 | } |
402 | |
403 | return error; |
404 | } |
405 | |
406 | int |
407 | netbsd32___nanosleep50(struct lwp *l, const struct netbsd32___nanosleep50_args *uap, register_t *retval) |
408 | { |
409 | /* { |
410 | syscallarg(const netbsd32_timespecp_t) rqtp; |
411 | syscallarg(netbsd32_timespecp_t) rmtp; |
412 | } */ |
413 | struct netbsd32_timespec ts32; |
414 | struct timespec rqt, rmt; |
415 | int error, error1; |
416 | |
417 | error = copyin(SCARG_P32(uap, rqtp), &ts32, sizeof(ts32)); |
418 | if (error) |
419 | return (error); |
420 | netbsd32_to_timespec(&ts32, &rqt); |
421 | |
422 | error = nanosleep1(l, CLOCK_MONOTONIC, 0, &rqt, |
423 | SCARG_P32(uap, rmtp) ? &rmt : NULL); |
424 | if (SCARG_P32(uap, rmtp) == NULL || (error != 0 && error != EINTR)) |
425 | return error; |
426 | |
427 | netbsd32_from_timespec(&rmt, &ts32); |
428 | error1 = copyout(&ts32, SCARG_P32(uap, rmtp), sizeof(ts32)); |
429 | return error1 ? error1 : error; |
430 | } |
431 | |
432 | int |
433 | netbsd32_clock_nanosleep(struct lwp *l, const struct netbsd32_clock_nanosleep_args *uap, register_t *retval) |
434 | { |
435 | /* { |
436 | syscallarg(clockid_t) clock_id; |
437 | syscallarg(int) flags; |
438 | syscallarg(const netbsd32_timespecp_t) rqtp; |
439 | syscallarg(netbsd32_timespecp_t) rmtp; |
440 | } */ |
441 | struct netbsd32_timespec ts32; |
442 | struct timespec rqt, rmt; |
443 | int error, error1; |
444 | |
445 | error = copyin(SCARG_P32(uap, rqtp), &ts32, sizeof(ts32)); |
446 | if (error) |
447 | goto out; |
448 | netbsd32_to_timespec(&ts32, &rqt); |
449 | |
450 | error = nanosleep1(l, SCARG(uap, clock_id), SCARG(uap, flags), |
451 | &rqt, SCARG_P32(uap, rmtp) ? &rmt : NULL); |
452 | if (SCARG_P32(uap, rmtp) == NULL || (error != 0 && error != EINTR)) |
453 | goto out; |
454 | |
455 | netbsd32_from_timespec(&rmt, &ts32); |
456 | if ((error1 = copyout(&ts32, SCARG_P32(uap, rmtp), sizeof(ts32))) != 0) |
457 | error = error1; |
458 | out: |
459 | *retval = error; |
460 | return 0; |
461 | } |
462 | |
463 | static int |
464 | netbsd32_timer_create_fetch(const void *src, void *dst, size_t size) |
465 | { |
466 | struct sigevent *evp = dst; |
467 | struct netbsd32_sigevent ev32; |
468 | int error; |
469 | |
470 | error = copyin(src, &ev32, sizeof(ev32)); |
471 | if (error) |
472 | return error; |
473 | |
474 | netbsd32_to_sigevent(&ev32, evp); |
475 | return 0; |
476 | } |
477 | |
478 | int |
479 | netbsd32_timer_create(struct lwp *l, const struct netbsd32_timer_create_args *uap, register_t *retval) |
480 | { |
481 | /* { |
482 | syscallarg(netbsd32_clockid_t) clock_id; |
483 | syscallarg(netbsd32_sigeventp_t) evp; |
484 | syscallarg(netbsd32_timerp_t) timerid; |
485 | } */ |
486 | |
487 | return timer_create1(SCARG_P32(uap, timerid), |
488 | SCARG(uap, clock_id), SCARG_P32(uap, evp), |
489 | netbsd32_timer_create_fetch, l); |
490 | } |
491 | |
492 | int |
493 | netbsd32_timer_delete(struct lwp *l, const struct netbsd32_timer_delete_args *uap, register_t *retval) |
494 | { |
495 | /* { |
496 | syscallarg(netbsd32_timer_t) timerid; |
497 | } */ |
498 | struct sys_timer_delete_args ua; |
499 | |
500 | NETBSD32TO64_UAP(timerid); |
501 | return sys_timer_delete(l, (void *)&ua, retval); |
502 | } |
503 | |
504 | int |
505 | netbsd32___timer_settime50(struct lwp *l, const struct netbsd32___timer_settime50_args *uap, register_t *retval) |
506 | { |
507 | /* { |
508 | syscallarg(netbsd32_timer_t) timerid; |
509 | syscallarg(int) flags; |
510 | syscallarg(const netbsd32_itimerspecp_t) value; |
511 | syscallarg(netbsd32_itimerspecp_t) ovalue; |
512 | } */ |
513 | int error; |
514 | struct itimerspec value, ovalue, *ovp = NULL; |
515 | struct netbsd32_itimerspec its32; |
516 | |
517 | if ((error = copyin(SCARG_P32(uap, value), &its32, sizeof(its32))) != 0) |
518 | return (error); |
519 | netbsd32_to_timespec(&its32.it_interval, &value.it_interval); |
520 | netbsd32_to_timespec(&its32.it_value, &value.it_value); |
521 | |
522 | if (SCARG_P32(uap, ovalue)) |
523 | ovp = &ovalue; |
524 | |
525 | if ((error = dotimer_settime(SCARG(uap, timerid), &value, ovp, |
526 | SCARG(uap, flags), l->l_proc)) != 0) |
527 | return error; |
528 | |
529 | if (ovp) { |
530 | netbsd32_from_timespec(&ovp->it_interval, &its32.it_interval); |
531 | netbsd32_from_timespec(&ovp->it_value, &its32.it_value); |
532 | return copyout(&its32, SCARG_P32(uap, ovalue), sizeof(its32)); |
533 | } |
534 | return 0; |
535 | } |
536 | |
537 | int |
538 | netbsd32___timer_gettime50(struct lwp *l, const struct netbsd32___timer_gettime50_args *uap, register_t *retval) |
539 | { |
540 | /* { |
541 | syscallarg(netbsd32_timer_t) timerid; |
542 | syscallarg(netbsd32_itimerspecp_t) value; |
543 | } */ |
544 | int error; |
545 | struct itimerspec its; |
546 | struct netbsd32_itimerspec its32; |
547 | |
548 | if ((error = dotimer_gettime(SCARG(uap, timerid), l->l_proc, |
549 | &its)) != 0) |
550 | return error; |
551 | |
552 | netbsd32_from_timespec(&its.it_interval, &its32.it_interval); |
553 | netbsd32_from_timespec(&its.it_value, &its32.it_value); |
554 | |
555 | return copyout(&its32, SCARG_P32(uap, value), sizeof(its32)); |
556 | } |
557 | |
558 | int |
559 | netbsd32_timer_getoverrun(struct lwp *l, const struct netbsd32_timer_getoverrun_args *uap, register_t *retval) |
560 | { |
561 | /* { |
562 | syscallarg(netbsd32_timer_t) timerid; |
563 | } */ |
564 | struct sys_timer_getoverrun_args ua; |
565 | |
566 | NETBSD32TO64_UAP(timerid); |
567 | return sys_timer_getoverrun(l, (void *)&ua, retval); |
568 | } |
569 | |
570 | int |
571 | netbsd32_clock_getcpuclockid2(struct lwp *l, |
572 | const struct netbsd32_clock_getcpuclockid2_args *uap, |
573 | register_t *retval) |
574 | { |
575 | /* { |
576 | syscallarg(idtype_t) idtype; |
577 | syscallarg(id_t) id; |
578 | syscallarg(netbsd32_clockidp_t) clock_id; |
579 | } */ |
580 | pid_t pid; |
581 | lwpid_t lid; |
582 | clockid_t clock_id; |
583 | id_t id = SCARG(uap, id); |
584 | |
585 | switch (SCARG(uap, idtype)) { |
586 | case P_PID: |
587 | pid = id == 0 ? l->l_proc->p_pid : id; |
588 | clock_id = CLOCK_PROCESS_CPUTIME_ID | pid; |
589 | break; |
590 | case P_LWPID: |
591 | lid = id == 0 ? l->l_lid : id; |
592 | clock_id = CLOCK_THREAD_CPUTIME_ID | lid; |
593 | break; |
594 | default: |
595 | return EINVAL; |
596 | } |
597 | return copyout(&clock_id, SCARG_P32(uap, clock_id), sizeof(clock_id)); |
598 | } |
599 | |
600 | |