xref: /netbsd-src/sys/compat/common/kern_time_50.c (revision c2f76ff004a2cb67efe5b12d97bd3ef7fe89e18d)
1 /*	$NetBSD: kern_time_50.c,v 1.18 2011/01/19 10:21:16 tsutsui Exp $	*/
2 
3 /*-
4  * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Christos Zoulas.
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 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: kern_time_50.c,v 1.18 2011/01/19 10:21:16 tsutsui Exp $");
33 
34 #ifdef _KERNEL_OPT
35 #include "opt_aio.h"
36 #include "opt_ntp.h"
37 #include "opt_mqueue.h"
38 #endif
39 
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/namei.h>
43 #include <sys/filedesc.h>
44 #include <sys/kernel.h>
45 #include <sys/file.h>
46 #include <sys/stat.h>
47 #include <sys/socketvar.h>
48 #include <sys/vnode.h>
49 #include <sys/proc.h>
50 #include <sys/uio.h>
51 #include <sys/dirent.h>
52 #include <sys/malloc.h>
53 #include <sys/kauth.h>
54 #include <sys/time.h>
55 #include <sys/timex.h>
56 #include <sys/aio.h>
57 #include <sys/poll.h>
58 #include <sys/syscallargs.h>
59 #include <sys/resource.h>
60 
61 #include <compat/common/compat_util.h>
62 #include <compat/sys/time.h>
63 #include <compat/sys/timex.h>
64 #include <compat/sys/resource.h>
65 #include <compat/sys/clockctl.h>
66 
67 int
68 compat_50_sys_clock_gettime(struct lwp *l,
69     const struct compat_50_sys_clock_gettime_args *uap, register_t *retval)
70 {
71 	/* {
72 		syscallarg(clockid_t) clock_id;
73 		syscallarg(struct timespec50 *) tp;
74 	} */
75 	int error;
76 	struct timespec ats;
77 	struct timespec50 ats50;
78 
79 	error = clock_gettime1(SCARG(uap, clock_id), &ats);
80 	if (error != 0)
81 		return error;
82 
83 	timespec_to_timespec50(&ats, &ats50);
84 
85 	return copyout(&ats50, SCARG(uap, tp), sizeof(ats50));
86 }
87 
88 /* ARGSUSED */
89 int
90 compat_50_sys_clock_settime(struct lwp *l,
91     const struct compat_50_sys_clock_settime_args *uap, register_t *retval)
92 {
93 	/* {
94 		syscallarg(clockid_t) clock_id;
95 		syscallarg(const struct timespec50 *) tp;
96 	} */
97 	int error;
98 	struct timespec ats;
99 	struct timespec50 ats50;
100 
101 	error = copyin(SCARG(uap, tp), &ats50, sizeof(ats50));
102 	if (error)
103 		return error;
104 	timespec50_to_timespec(&ats50, &ats);
105 
106 	return clock_settime1(l->l_proc, SCARG(uap, clock_id), &ats,
107 	    true);
108 }
109 
110 
111 int
112 compat_50_sys_clock_getres(struct lwp *l,
113     const struct compat_50_sys_clock_getres_args *uap, register_t *retval)
114 {
115 	/* {
116 		syscallarg(clockid_t) clock_id;
117 		syscallarg(struct timespec50 *) tp;
118 	} */
119 	struct timespec50 ats50;
120 	struct timespec ats;
121 	int error = 0;
122 
123 	error = clock_getres1(SCARG(uap, clock_id), &ats);
124 	if (error != 0)
125 		return error;
126 
127 	if (SCARG(uap, tp)) {
128 		timespec_to_timespec50(&ats, &ats50);
129 		error = copyout(&ats50, SCARG(uap, tp), sizeof(ats50));
130 	}
131 
132 	return error;
133 }
134 
135 /* ARGSUSED */
136 int
137 compat_50_sys_nanosleep(struct lwp *l,
138     const struct compat_50_sys_nanosleep_args *uap, register_t *retval)
139 {
140 	/* {
141 		syscallarg(struct timespec50 *) rqtp;
142 		syscallarg(struct timespec50 *) rmtp;
143 	} */
144 	struct timespec rmt, rqt;
145 	struct timespec50 rmt50, rqt50;
146 	int error, error1;
147 
148 	error = copyin(SCARG(uap, rqtp), &rqt50, sizeof(rqt50));
149 	if (error)
150 		return error;
151 	timespec50_to_timespec(&rqt50, &rqt);
152 
153 	error = nanosleep1(l, &rqt, SCARG(uap, rmtp) ? &rmt : NULL);
154 	if (SCARG(uap, rmtp) == NULL || (error != 0 && error != EINTR))
155 		return error;
156 
157 	timespec_to_timespec50(&rmt, &rmt50);
158 	error1 = copyout(&rmt50, SCARG(uap, rmtp), sizeof(*SCARG(uap, rmtp)));
159 	return error1 ? error1 : error;
160 }
161 
162 /* ARGSUSED */
163 int
164 compat_50_sys_gettimeofday(struct lwp *l,
165     const struct compat_50_sys_gettimeofday_args *uap, register_t *retval)
166 {
167 	/* {
168 		syscallarg(struct timeval50 *) tp;
169 		syscallarg(void *) tzp;		really "struct timezone *";
170 	} */
171 	struct timeval atv;
172 	struct timeval50 atv50;
173 	int error = 0;
174 	struct timezone tzfake;
175 
176 	if (SCARG(uap, tp)) {
177 		microtime(&atv);
178 		timeval_to_timeval50(&atv, &atv50);
179 		error = copyout(&atv50, SCARG(uap, tp), sizeof(*SCARG(uap, tp)));
180 		if (error)
181 			return error;
182 	}
183 	if (SCARG(uap, tzp)) {
184 		/*
185 		 * NetBSD has no kernel notion of time zone, so we just
186 		 * fake up a timezone struct and return it if demanded.
187 		 */
188 		tzfake.tz_minuteswest = 0;
189 		tzfake.tz_dsttime = 0;
190 		error = copyout(&tzfake, SCARG(uap, tzp), sizeof(tzfake));
191 	}
192 	return error;
193 }
194 
195 /* ARGSUSED */
196 int
197 compat_50_sys_settimeofday(struct lwp *l,
198     const struct compat_50_sys_settimeofday_args *uap, register_t *retval)
199 {
200 	/* {
201 		syscallarg(const struct timeval50 *) tv;
202 		syscallarg(const void *) tzp; really "const struct timezone *";
203 	} */
204 	struct timeval50 atv50;
205 	struct timeval atv;
206 	int error = copyin(SCARG(uap, tv), &atv50, sizeof(atv50));
207 	if (error)
208 		return error;
209 	timeval50_to_timeval(&atv50, &atv);
210 	return settimeofday1(&atv, false, SCARG(uap, tzp), l, true);
211 }
212 
213 /* ARGSUSED */
214 int
215 compat_50_sys_adjtime(struct lwp *l,
216     const struct compat_50_sys_adjtime_args *uap, register_t *retval)
217 {
218 	/* {
219 		syscallarg(const struct timeval50 *) delta;
220 		syscallarg(struct timeval50 *) olddelta;
221 	} */
222 	int error;
223 	struct timeval50 delta50, olddelta50;
224 	struct timeval delta, olddelta;
225 
226 	if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_TIME,
227 	    KAUTH_REQ_SYSTEM_TIME_ADJTIME, NULL, NULL, NULL)) != 0)
228 		return error;
229 
230 	if (SCARG(uap, delta)) {
231 		error = copyin(SCARG(uap, delta), &delta50,
232 		    sizeof(*SCARG(uap, delta)));
233 		if (error)
234 			return (error);
235 		timeval50_to_timeval(&delta50, &delta);
236 	}
237 	adjtime1(SCARG(uap, delta) ? &delta : NULL,
238 	    SCARG(uap, olddelta) ? &olddelta : NULL, l->l_proc);
239 	if (SCARG(uap, olddelta)) {
240 		timeval_to_timeval50(&olddelta, &olddelta50);
241 		error = copyout(&olddelta50, SCARG(uap, olddelta),
242 		    sizeof(*SCARG(uap, olddelta)));
243 	}
244 	return error;
245 }
246 
247 /* BSD routine to set/arm an interval timer. */
248 /* ARGSUSED */
249 int
250 compat_50_sys_getitimer(struct lwp *l,
251     const struct compat_50_sys_getitimer_args *uap, register_t *retval)
252 {
253 	/* {
254 		syscallarg(int) which;
255 		syscallarg(struct itimerval50 *) itv;
256 	} */
257 	struct proc *p = l->l_proc;
258 	struct itimerval aitv;
259 	struct itimerval50 aitv50;
260 	int error;
261 
262 	error = dogetitimer(p, SCARG(uap, which), &aitv);
263 	if (error)
264 		return error;
265 	itimerval_to_itimerval50(&aitv, &aitv50);
266 	return copyout(&aitv50, SCARG(uap, itv), sizeof(*SCARG(uap, itv)));
267 }
268 
269 int
270 compat_50_sys_setitimer(struct lwp *l,
271     const struct compat_50_sys_setitimer_args *uap, register_t *retval)
272 {
273 	/* {
274 		syscallarg(int) which;
275 		syscallarg(const struct itimerval50 *) itv;
276 		syscallarg(struct itimerval50 *) oitv;
277 	} */
278 	struct proc *p = l->l_proc;
279 	int which = SCARG(uap, which);
280 	struct compat_50_sys_getitimer_args getargs;
281 	const struct itimerval50 *itvp;
282 	struct itimerval50 aitv50;
283 	struct itimerval aitv;
284 	int error;
285 
286 	if ((u_int)which > ITIMER_PROF)
287 		return (EINVAL);
288 	itvp = SCARG(uap, itv);
289 	if (itvp &&
290 	    (error = copyin(itvp, &aitv50, sizeof(aitv50)) != 0))
291 		return (error);
292 	itimerval50_to_itimerval(&aitv50, &aitv);
293 	if (SCARG(uap, oitv) != NULL) {
294 		SCARG(&getargs, which) = which;
295 		SCARG(&getargs, itv) = SCARG(uap, oitv);
296 		if ((error = compat_50_sys_getitimer(l, &getargs, retval)) != 0)
297 			return (error);
298 	}
299 	if (itvp == 0)
300 		return (0);
301 
302 	return dosetitimer(p, which, &aitv);
303 }
304 
305 int
306 compat_50_sys_aio_suspend(struct lwp *l,
307     const struct compat_50_sys_aio_suspend_args *uap, register_t *retval)
308 {
309 	/* {
310 		syscallarg(const struct aiocb *const[]) list;
311 		syscallarg(int) nent;
312 		syscallarg(const struct timespec50 *) timeout;
313 	} */
314 #ifdef AIO
315 	struct aiocb **list;
316 	struct timespec ts;
317 	struct timespec50 ts50;
318 	int error, nent;
319 
320 	nent = SCARG(uap, nent);
321 	if (nent <= 0 || nent > aio_listio_max)
322 		return EAGAIN;
323 
324 	if (SCARG(uap, timeout)) {
325 		/* Convert timespec to ticks */
326 		error = copyin(SCARG(uap, timeout), &ts50,
327 		    sizeof(*SCARG(uap, timeout)));
328 		if (error)
329 			return error;
330 		timespec50_to_timespec(&ts50, &ts);
331 	}
332 	list = kmem_alloc(nent * sizeof(*list), KM_SLEEP);
333 	error = copyin(SCARG(uap, list), list, nent * sizeof(*list));
334 	if (error)
335 		goto out;
336 	error = aio_suspend1(l, list, nent, SCARG(uap, timeout) ? &ts : NULL);
337 out:
338 	kmem_free(list, nent * sizeof(*list));
339 	return error;
340 #else
341 	return ENOSYS;
342 #endif
343 }
344 
345 int
346 compat_50_sys__lwp_park(struct lwp *l,
347     const struct compat_50_sys__lwp_park_args *uap, register_t *retval)
348 {
349 	/* {
350 		syscallarg(const struct timespec50 *)	ts;
351 		syscallarg(lwpid_t)			unpark;
352 		syscallarg(const void *)		hint;
353 		syscallarg(const void *)		unparkhint;
354 	} */
355 	struct timespec ts, *tsp;
356 	struct timespec50 ts50;
357 	int error;
358 
359 	if (SCARG(uap, ts) == NULL)
360 		tsp = NULL;
361 	else {
362 		error = copyin(SCARG(uap, ts), &ts50, sizeof(ts50));
363 		if (error != 0)
364 			return error;
365 		timespec50_to_timespec(&ts50, &ts);
366 		tsp = &ts;
367 	}
368 
369 	if (SCARG(uap, unpark) != 0) {
370 		error = lwp_unpark(SCARG(uap, unpark), SCARG(uap, unparkhint));
371 		if (error != 0)
372 			return error;
373 	}
374 
375 	return lwp_park(tsp, SCARG(uap, hint));
376 }
377 
378 int
379 compat_50_sys_mq_timedsend(struct lwp *l,
380     const struct compat_50_sys_mq_timedsend_args *uap, register_t *retval)
381 {
382 	/* {
383 		syscallarg(mqd_t) mqdes;
384 		syscallarg(const char *) msg_ptr;
385 		syscallarg(size_t) msg_len;
386 		syscallarg(unsigned) msg_prio;
387 		syscallarg(const struct timespec50 *) abs_timeout;
388 	} */
389 #ifdef MQUEUE
390 	struct timespec50 ts50;
391 	struct timespec ts, *tsp;
392 	int error;
393 
394 	/* Get and convert time value */
395 	if (SCARG(uap, abs_timeout)) {
396 		error = copyin(SCARG(uap, abs_timeout), &ts50, sizeof(ts50));
397 		if (error)
398 			return error;
399 		timespec50_to_timespec(&ts50, &ts);
400 		tsp = &ts;
401 	} else {
402 		tsp = NULL;
403 	}
404 
405 	return mq_send1(SCARG(uap, mqdes), SCARG(uap, msg_ptr),
406 	    SCARG(uap, msg_len), SCARG(uap, msg_prio), tsp);
407 #else
408 	return ENOSYS;
409 #endif
410 }
411 
412 int
413 compat_50_sys_mq_timedreceive(struct lwp *l,
414     const struct compat_50_sys_mq_timedreceive_args *uap, register_t *retval)
415 {
416 	/* {
417 		syscallarg(mqd_t) mqdes;
418 		syscallarg(char *) msg_ptr;
419 		syscallarg(size_t) msg_len;
420 		syscallarg(unsigned *) msg_prio;
421 		syscallarg(const struct timespec50 *) abs_timeout;
422 	} */
423 #ifdef MQUEUE
424 	struct timespec ts, *tsp;
425 	struct timespec50 ts50;
426 	ssize_t mlen;
427 	int error;
428 
429 	/* Get and convert time value */
430 	if (SCARG(uap, abs_timeout)) {
431 		error = copyin(SCARG(uap, abs_timeout), &ts50, sizeof(ts50));
432 		if (error)
433 			return error;
434 
435 		timespec50_to_timespec(&ts50, &ts);
436 		tsp = &ts;
437 	} else {
438 		tsp = NULL;
439 	}
440 
441 	error = mq_recv1(SCARG(uap, mqdes), SCARG(uap, msg_ptr),
442 	    SCARG(uap, msg_len), SCARG(uap, msg_prio), tsp, &mlen);
443 	if (error == 0)
444 		*retval = mlen;
445 
446 	return error;
447 #else
448 	return ENOSYS;
449 #endif
450 }
451 
452 static int
453 tscopyin(const void *u, void *s, size_t len)
454 {
455 	struct timespec50 ts50;
456 	KASSERT(len == sizeof(ts50));
457 	int error = copyin(u, &ts50, len);
458 	if (error)
459 		return error;
460 	timespec50_to_timespec(&ts50, s);
461 	return 0;
462 }
463 
464 static int
465 tscopyout(const void *s, void *u, size_t len)
466 {
467 	struct timespec50 ts50;
468 	KASSERT(len == sizeof(ts50));
469 	timespec_to_timespec50(s, &ts50);
470 	int error = copyout(&ts50, u, len);
471 	if (error)
472 		return error;
473 	return 0;
474 }
475 
476 int
477 compat_50_sys___sigtimedwait(struct lwp *l,
478     const struct compat_50_sys___sigtimedwait_args *uap, register_t *retval)
479 {
480 	int res;
481 
482 	res = sigtimedwait1(l,
483 	    (const struct sys_____sigtimedwait50_args *)uap, retval, copyout,
484 	    tscopyin, tscopyout);
485 	if (!res)
486 		*retval = 0; /* XXX NetBSD<=5 was not POSIX compliant */
487 	return res;
488 }
489 
490 void
491 rusage_to_rusage50(const struct rusage *ru, struct rusage50 *ru50)
492 {
493 	(void)memcpy(&ru50->ru_first, &ru->ru_first,
494 	    (char *)&ru50->ru_last - (char *)&ru50->ru_first +
495 	    sizeof(ru50->ru_last));
496 	ru50->ru_maxrss = ru->ru_maxrss;
497 	timeval_to_timeval50(&ru->ru_utime, &ru50->ru_utime);
498 	timeval_to_timeval50(&ru->ru_stime, &ru50->ru_stime);
499 }
500 
501 int
502 compat_50_sys_getrusage(struct lwp *l,
503     const struct compat_50_sys_getrusage_args *uap, register_t *retval)
504 {
505 	/* {
506 		syscallarg(int) who;
507 		syscallarg(struct rusage50 *) rusage;
508 	} */
509 	struct rusage ru;
510 	struct rusage50 ru50;
511 	struct proc *p = l->l_proc;
512 
513 	switch (SCARG(uap, who)) {
514 	case RUSAGE_SELF:
515 		mutex_enter(p->p_lock);
516 		memcpy(&ru, &p->p_stats->p_ru, sizeof(ru));
517 		calcru(p, &ru.ru_utime, &ru.ru_stime, NULL, NULL);
518 		mutex_exit(p->p_lock);
519 		break;
520 
521 	case RUSAGE_CHILDREN:
522 		mutex_enter(p->p_lock);
523 		memcpy(&ru, &p->p_stats->p_cru, sizeof(ru));
524 		mutex_exit(p->p_lock);
525 		break;
526 
527 	default:
528 		return EINVAL;
529 	}
530 	rusage_to_rusage50(&ru, &ru50);
531 	return copyout(&ru50, SCARG(uap, rusage), sizeof(ru50));
532 }
533 
534 
535 /* Return the time remaining until a POSIX timer fires. */
536 int
537 compat_50_sys_timer_gettime(struct lwp *l,
538     const struct compat_50_sys_timer_gettime_args *uap, register_t *retval)
539 {
540 	/* {
541 		syscallarg(timer_t) timerid;
542 		syscallarg(struct itimerspec50 *) value;
543 	} */
544 	struct itimerspec its;
545 	struct itimerspec50 its50;
546 	int error;
547 
548 	if ((error = dotimer_gettime(SCARG(uap, timerid), l->l_proc,
549 	    &its)) != 0)
550 		return error;
551 	itimerspec_to_itimerspec50(&its, &its50);
552 
553 	return copyout(&its50, SCARG(uap, value), sizeof(its50));
554 }
555 
556 /* Set and arm a POSIX realtime timer */
557 int
558 compat_50_sys_timer_settime(struct lwp *l,
559     const struct compat_50_sys_timer_settime_args *uap, register_t *retval)
560 {
561 	/* {
562 		syscallarg(timer_t) timerid;
563 		syscallarg(int) flags;
564 		syscallarg(const struct itimerspec50 *) value;
565 		syscallarg(struct itimerspec50 *) ovalue;
566 	} */
567 	int error;
568 	struct itimerspec value, ovalue, *ovp = NULL;
569 	struct itimerspec50 value50, ovalue50;
570 
571 	if ((error = copyin(SCARG(uap, value), &value50, sizeof(value50))) != 0)
572 		return error;
573 
574 	itimerspec50_to_itimerspec(&value50, &value);
575 	if (SCARG(uap, ovalue))
576 		ovp = &ovalue;
577 
578 	if ((error = dotimer_settime(SCARG(uap, timerid), &value, ovp,
579 	    SCARG(uap, flags), l->l_proc)) != 0)
580 		return error;
581 
582 	if (ovp) {
583 		itimerspec_to_itimerspec50(&ovalue, &ovalue50);
584 		return copyout(&ovalue50, SCARG(uap, ovalue), sizeof(ovalue50));
585 	}
586 	return 0;
587 }
588 
589 /*
590  * ntp_gettime() - NTP user application interface
591  */
592 int
593 compat_50_sys___ntp_gettime30(struct lwp *l,
594     const struct compat_50_sys___ntp_gettime30_args *uap, register_t *retval)
595 {
596 #ifdef NTP
597 	/* {
598 		syscallarg(struct ntptimeval *) ntvp;
599 	} */
600 	struct ntptimeval ntv;
601 	struct ntptimeval50 ntv50;
602 	int error;
603 
604 	if (SCARG(uap, ntvp)) {
605 		ntp_gettime(&ntv);
606 		timespec_to_timespec50(&ntv.time, &ntv50.time);
607 		ntv50.maxerror = ntv.maxerror;
608 		ntv50.esterror = ntv.esterror;
609 		ntv50.tai = ntv.tai;
610 		ntv50.time_state = ntv.time_state;
611 
612 		error = copyout(&ntv50, SCARG(uap, ntvp), sizeof(ntv50));
613 		if (error)
614 			return error;
615 	}
616 	*retval = ntp_timestatus();
617 	return 0;
618 #else
619 	return ENOSYS;
620 #endif
621 }
622 int
623 compat50_clockctlioctl(dev_t dev, u_long cmd, void *data, int flags,
624     struct lwp *l)
625 {
626 	int error = 0;
627 
628 	switch (cmd) {
629 	case CLOCKCTL_OSETTIMEOFDAY: {
630 		struct timeval50 tv50;
631 		struct timeval tv;
632 		struct clockctl50_settimeofday *args = data;
633 
634 		error = copyin(args->tv, &tv50, sizeof(tv50));
635 		if (error)
636 			return (error);
637 		timeval50_to_timeval(&tv50, &tv);
638 		error = settimeofday1(&tv, false, args->tzp, l, false);
639 		break;
640 	}
641 	case CLOCKCTL_OADJTIME: {
642 		struct timeval atv, oldatv;
643 		struct timeval50 atv50;
644 		struct clockctl50_adjtime *args = data;
645 
646 		if (args->delta) {
647 			error = copyin(args->delta, &atv50, sizeof(atv50));
648 			if (error)
649 				return (error);
650 			timeval50_to_timeval(&atv50, &atv);
651 		}
652 		adjtime1(args->delta ? &atv : NULL,
653 		    args->olddelta ? &oldatv : NULL, l->l_proc);
654 		if (args->olddelta) {
655 			timeval_to_timeval50(&oldatv, &atv50);
656 			error = copyout(&atv50, args->olddelta, sizeof(atv50));
657 		}
658 		break;
659 	}
660 	case CLOCKCTL_OCLOCK_SETTIME: {
661 		struct timespec50 tp50;
662 		struct timespec tp;
663 		struct clockctl50_clock_settime *args = data;
664 
665 		error = copyin(args->tp, &tp50, sizeof(tp50));
666 		if (error)
667 			return (error);
668 		timespec50_to_timespec(&tp50, &tp);
669 		error = clock_settime1(l->l_proc, args->clock_id, &tp, true);
670 		break;
671 	}
672 	default:
673 		error = EINVAL;
674 	}
675 
676 	return (error);
677 }
678 int
679 compat_50_sys_wait4(struct lwp *l, const struct compat_50_sys_wait4_args *uap,
680     register_t *retval)
681 {
682 	/* {
683 		syscallarg(int)			pid;
684 		syscallarg(int *)		status;
685 		syscallarg(int)			options;
686 		syscallarg(struct rusage50 *)	rusage;
687 	} */
688 	int status, error, pid = SCARG(uap, pid);
689 	struct rusage50 ru50;
690 	struct rusage ru;
691 
692 	error = do_sys_wait(&pid, &status, SCARG(uap, options),
693 	    SCARG(uap, rusage) != NULL ? &ru : NULL);
694 
695 	retval[0] = pid;
696 	if (pid == 0)
697 		return error;
698 
699 	if (SCARG(uap, rusage)) {
700 		rusage_to_rusage50(&ru, &ru50);
701 		error = copyout(&ru50, SCARG(uap, rusage), sizeof(ru50));
702 	}
703 
704 	if (error == 0 && SCARG(uap, status))
705 		error = copyout(&status, SCARG(uap, status), sizeof(status));
706 
707 	return error;
708 }
709