xref: /netbsd/sys/compat/netbsd32/netbsd32_time.c (revision c4a72b64)
1 /*	$NetBSD: netbsd32_time.c,v 1.4 2002/10/23 13:16:46 scw 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  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: netbsd32_time.c,v 1.4 2002/10/23 13:16:46 scw Exp $");
33 
34 #if defined(_KERNEL_OPT)
35 #include "opt_ntp.h"
36 #endif
37 
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/mount.h>
41 #include <sys/time.h>
42 #include <sys/timex.h>
43 #include <sys/proc.h>
44 #include <sys/resourcevar.h>
45 
46 #include <compat/netbsd32/netbsd32.h>
47 #include <compat/netbsd32/netbsd32_syscallargs.h>
48 #include <compat/netbsd32/netbsd32_conv.h>
49 
50 #ifdef NTP
51 int
52 netbsd32_ntp_gettime(p, v, retval)
53 	struct proc *p;
54 	void *v;
55 	register_t *retval;
56 {
57 	struct netbsd32_ntp_gettime_args /* {
58 		syscallarg(netbsd32_ntptimevalp_t) ntvp;
59 	} */ *uap = v;
60 	struct netbsd32_ntptimeval ntv32;
61 	struct timeval atv;
62 	struct ntptimeval ntv;
63 	int error = 0;
64 	int s;
65 
66 	/* The following are NTP variables */
67 	extern long time_maxerror;
68 	extern long time_esterror;
69 	extern int time_status;
70 	extern int time_state;	/* clock state */
71 	extern int time_status;	/* clock status bits */
72 
73 	if (SCARG(uap, ntvp)) {
74 		s = splclock();
75 #ifdef EXT_CLOCK
76 		/*
77 		 * The microtime() external clock routine returns a
78 		 * status code. If less than zero, we declare an error
79 		 * in the clock status word and return the kernel
80 		 * (software) time variable. While there are other
81 		 * places that call microtime(), this is the only place
82 		 * that matters from an application point of view.
83 		 */
84 		if (microtime(&atv) < 0) {
85 			time_status |= STA_CLOCKERR;
86 			ntv.time = time;
87 		} else
88 			time_status &= ~STA_CLOCKERR;
89 #else /* EXT_CLOCK */
90 		microtime(&atv);
91 #endif /* EXT_CLOCK */
92 		ntv.time = atv;
93 		ntv.maxerror = time_maxerror;
94 		ntv.esterror = time_esterror;
95 		(void) splx(s);
96 
97 		netbsd32_from_timeval(&ntv.time, &ntv32.time);
98 		ntv32.maxerror = (netbsd32_long)ntv.maxerror;
99 		ntv32.esterror = (netbsd32_long)ntv.esterror;
100 		error = copyout((caddr_t)&ntv32,
101 		    (caddr_t)NETBSD32PTR64(SCARG(uap, ntvp)), sizeof(ntv32));
102 	}
103 	if (!error) {
104 
105 		/*
106 		 * Status word error decode. If any of these conditions
107 		 * occur, an error is returned, instead of the status
108 		 * word. Most applications will care only about the fact
109 		 * the system clock may not be trusted, not about the
110 		 * details.
111 		 *
112 		 * Hardware or software error
113 		 */
114 		if ((time_status & (STA_UNSYNC | STA_CLOCKERR)) ||
115 
116 		/*
117 		 * PPS signal lost when either time or frequency
118 		 * synchronization requested
119 		 */
120 		    (time_status & (STA_PPSFREQ | STA_PPSTIME) &&
121 		    !(time_status & STA_PPSSIGNAL)) ||
122 
123 		/*
124 		 * PPS jitter exceeded when time synchronization
125 		 * requested
126 		 */
127 		    (time_status & STA_PPSTIME &&
128 		    time_status & STA_PPSJITTER) ||
129 
130 		/*
131 		 * PPS wander exceeded or calibration error when
132 		 * frequency synchronization requested
133 		 */
134 		    (time_status & STA_PPSFREQ &&
135 		    time_status & (STA_PPSWANDER | STA_PPSERROR)))
136 			*retval = TIME_ERROR;
137 		else
138 			*retval = time_state;
139 	}
140 	return (error);
141 }
142 
143 int
144 netbsd32_ntp_adjtime(p, v, retval)
145 	struct proc *p;
146 	void *v;
147 	register_t *retval;
148 {
149 	struct netbsd32_ntp_adjtime_args /* {
150 		syscallarg(netbsd32_timexp_t) tp;
151 	} */ *uap = v;
152 	struct netbsd32_timex ntv32;
153 	struct timex ntv;
154 	int error = 0;
155 	int modes;
156 	int s;
157 	extern long time_freq;		/* frequency offset (scaled ppm) */
158 	extern long time_maxerror;
159 	extern long time_esterror;
160 	extern int time_state;	/* clock state */
161 	extern int time_status;	/* clock status bits */
162 	extern long time_constant;		/* pll time constant */
163 	extern long time_offset;		/* time offset (us) */
164 	extern long time_tolerance;	/* frequency tolerance (scaled ppm) */
165 	extern long time_precision;	/* clock precision (us) */
166 
167 	if ((error = copyin((caddr_t)NETBSD32PTR64(SCARG(uap, tp)),
168 	    (caddr_t)&ntv32, sizeof(ntv32))))
169 		return (error);
170 	netbsd32_to_timex(&ntv32, &ntv);
171 
172 	/*
173 	 * Update selected clock variables - only the superuser can
174 	 * change anything. Note that there is no error checking here on
175 	 * the assumption the superuser should know what it is doing.
176 	 */
177 	modes = ntv.modes;
178 	if (modes != 0 && (error = suser(p->p_ucred, &p->p_acflag)))
179 		return (error);
180 
181 	s = splclock();
182 	if (modes & MOD_FREQUENCY)
183 #ifdef PPS_SYNC
184 		time_freq = ntv.freq - pps_freq;
185 #else /* PPS_SYNC */
186 		time_freq = ntv.freq;
187 #endif /* PPS_SYNC */
188 	if (modes & MOD_MAXERROR)
189 		time_maxerror = ntv.maxerror;
190 	if (modes & MOD_ESTERROR)
191 		time_esterror = ntv.esterror;
192 	if (modes & MOD_STATUS) {
193 		time_status &= STA_RONLY;
194 		time_status |= ntv.status & ~STA_RONLY;
195 	}
196 	if (modes & MOD_TIMECONST)
197 		time_constant = ntv.constant;
198 	if (modes & MOD_OFFSET)
199 		hardupdate(ntv.offset);
200 
201 	/*
202 	 * Retrieve all clock variables
203 	 */
204 	if (time_offset < 0)
205 		ntv.offset = -(-time_offset >> SHIFT_UPDATE);
206 	else
207 		ntv.offset = time_offset >> SHIFT_UPDATE;
208 #ifdef PPS_SYNC
209 	ntv.freq = time_freq + pps_freq;
210 #else /* PPS_SYNC */
211 	ntv.freq = time_freq;
212 #endif /* PPS_SYNC */
213 	ntv.maxerror = time_maxerror;
214 	ntv.esterror = time_esterror;
215 	ntv.status = time_status;
216 	ntv.constant = time_constant;
217 	ntv.precision = time_precision;
218 	ntv.tolerance = time_tolerance;
219 #ifdef PPS_SYNC
220 	ntv.shift = pps_shift;
221 	ntv.ppsfreq = pps_freq;
222 	ntv.jitter = pps_jitter >> PPS_AVG;
223 	ntv.stabil = pps_stabil;
224 	ntv.calcnt = pps_calcnt;
225 	ntv.errcnt = pps_errcnt;
226 	ntv.jitcnt = pps_jitcnt;
227 	ntv.stbcnt = pps_stbcnt;
228 #endif /* PPS_SYNC */
229 	(void)splx(s);
230 
231 	netbsd32_from_timex(&ntv, &ntv32);
232 	error = copyout((caddr_t)&ntv32, (caddr_t)NETBSD32PTR64(SCARG(uap, tp)),
233 	    sizeof(ntv32));
234 	if (!error) {
235 
236 		/*
237 		 * Status word error decode. See comments in
238 		 * ntp_gettime() routine.
239 		 */
240 		if ((time_status & (STA_UNSYNC | STA_CLOCKERR)) ||
241 		    (time_status & (STA_PPSFREQ | STA_PPSTIME) &&
242 		    !(time_status & STA_PPSSIGNAL)) ||
243 		    (time_status & STA_PPSTIME &&
244 		    time_status & STA_PPSJITTER) ||
245 		    (time_status & STA_PPSFREQ &&
246 		    time_status & (STA_PPSWANDER | STA_PPSERROR)))
247 			*retval = TIME_ERROR;
248 		else
249 			*retval = time_state;
250 	}
251 	return error;
252 }
253 #else
254 int
255 netbsd32_ntp_gettime(p, v, retval)
256 	struct proc *p;
257 	void *v;
258 	register_t *retval;
259 {
260 
261 	return (ENOSYS);
262 }
263 
264 int
265 netbsd32_ntp_adjtime(p, v, retval)
266 	struct proc *p;
267 	void *v;
268 	register_t *retval;
269 {
270 
271 	return (ENOSYS);
272 }
273 #endif
274 
275 int
276 netbsd32_setitimer(p, v, retval)
277 	struct proc *p;
278 	void *v;
279 	register_t *retval;
280 {
281 	struct netbsd32_setitimer_args /* {
282 		syscallarg(int) which;
283 		syscallarg(const netbsd32_itimervalp_t) itv;
284 		syscallarg(netbsd32_itimervalp_t) oitv;
285 	} */ *uap = v;
286 	struct netbsd32_itimerval s32it, *itvp;
287 	int which = SCARG(uap, which);
288 	struct netbsd32_getitimer_args getargs;
289 	struct itimerval aitv;
290 	int s, error;
291 
292 	if ((u_int)which > ITIMER_PROF)
293 		return (EINVAL);
294 	itvp = (struct netbsd32_itimerval *)NETBSD32PTR64(SCARG(uap, itv));
295 	if (itvp && (error = copyin(itvp, &s32it, sizeof(s32it))))
296 		return (error);
297 	netbsd32_to_itimerval(&s32it, &aitv);
298 	if (SCARG(uap, oitv) != NULL) {
299 		SCARG(&getargs, which) = which;
300 		SCARG(&getargs, itv) = SCARG(uap, oitv);
301 		if ((error = netbsd32_getitimer(p, &getargs, retval)) != 0)
302 			return (error);
303 	}
304 	if (itvp == 0)
305 		return (0);
306 	if (itimerfix(&aitv.it_value) || itimerfix(&aitv.it_interval))
307 		return (EINVAL);
308 	s = splclock();
309 	if (which == ITIMER_REAL) {
310 		callout_stop(&p->p_realit_ch);
311 		if (timerisset(&aitv.it_value)) {
312 			/*
313 			 * Don't need to check hzto() return value, here.
314 			 * callout_reset() does it for us.
315 			 */
316 			timeradd(&aitv.it_value, &time, &aitv.it_value);
317 			callout_reset(&p->p_realit_ch, hzto(&aitv.it_value),
318 			    realitexpire, p);
319 		}
320 		p->p_realtimer = aitv;
321 	} else
322 		p->p_stats->p_timer[which] = aitv;
323 	splx(s);
324 	return (0);
325 }
326 
327 int
328 netbsd32_getitimer(p, v, retval)
329 	struct proc *p;
330 	void *v;
331 	register_t *retval;
332 {
333 	struct netbsd32_getitimer_args /* {
334 		syscallarg(int) which;
335 		syscallarg(netbsd32_itimervalp_t) itv;
336 	} */ *uap = v;
337 	int which = SCARG(uap, which);
338 	struct netbsd32_itimerval s32it;
339 	struct itimerval aitv;
340 	int s;
341 
342 	if ((u_int)which > ITIMER_PROF)
343 		return (EINVAL);
344 	s = splclock();
345 	if (which == ITIMER_REAL) {
346 		/*
347 		 * Convert from absolute to relative time in .it_value
348 		 * part of real time timer.  If time for real time timer
349 		 * has passed return 0, else return difference between
350 		 * current time and time for the timer to go off.
351 		 */
352 		aitv = p->p_realtimer;
353 		if (timerisset(&aitv.it_value)) {
354 			if (timercmp(&aitv.it_value, &time, <))
355 				timerclear(&aitv.it_value);
356 			else
357 				timersub(&aitv.it_value, &time, &aitv.it_value);
358 		}
359 	} else
360 		aitv = p->p_stats->p_timer[which];
361 	splx(s);
362 	netbsd32_from_itimerval(&aitv, &s32it);
363 	return (copyout(&s32it, (caddr_t)NETBSD32PTR64(SCARG(uap, itv)),
364 	    sizeof(s32it)));
365 }
366 
367 int
368 netbsd32_gettimeofday(p, v, retval)
369 	struct proc *p;
370 	void *v;
371 	register_t *retval;
372 {
373 	struct netbsd32_gettimeofday_args /* {
374 		syscallarg(netbsd32_timevalp_t) tp;
375 		syscallarg(netbsd32_timezonep_t) tzp;
376 	} */ *uap = v;
377 	struct timeval atv;
378 	struct netbsd32_timeval tv32;
379 	int error = 0;
380 	struct netbsd32_timezone tzfake;
381 
382 	if (SCARG(uap, tp)) {
383 		microtime(&atv);
384 		netbsd32_from_timeval(&atv, &tv32);
385 		error = copyout(&tv32, (caddr_t)NETBSD32PTR64(SCARG(uap, tp)),
386 		    sizeof(tv32));
387 		if (error)
388 			return (error);
389 	}
390 	if (SCARG(uap, tzp)) {
391 		/*
392 		 * NetBSD has no kernel notion of time zone, so we just
393 		 * fake up a timezone struct and return it if demanded.
394 		 */
395 		tzfake.tz_minuteswest = 0;
396 		tzfake.tz_dsttime = 0;
397 		error = copyout(&tzfake,
398 		    (caddr_t)NETBSD32PTR64(SCARG(uap, tzp)), sizeof(tzfake));
399 	}
400 	return (error);
401 }
402 
403 int
404 netbsd32_settimeofday(p, v, retval)
405 	struct proc *p;
406 	void *v;
407 	register_t *retval;
408 {
409 	struct netbsd32_settimeofday_args /* {
410 		syscallarg(const netbsd32_timevalp_t) tv;
411 		syscallarg(const netbsd32_timezonep_t) tzp;
412 	} */ *uap = v;
413 	struct netbsd32_timeval atv32;
414 	struct timeval atv;
415 	int error;
416 
417 	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
418 		return (error);
419 	/* Verify all parameters before changing time. */
420 	if (SCARG(uap, tv) &&
421 	    (error = copyin((caddr_t)NETBSD32PTR64(SCARG(uap, tv)), &atv32,
422 	    sizeof(atv32))))
423 		return (error);
424 	netbsd32_to_timeval(&atv32, &atv);
425 	if (SCARG(uap, tv))
426 		if ((error = settime(&atv)))
427 			return (error);
428 	/* don't bother copying the tz in, we don't use it. */
429 	/*
430 	 * NetBSD has no kernel notion of time zone, and only an
431 	 * obsolete program would try to set it, so we log a warning.
432 	 */
433 	if (SCARG(uap, tzp))
434 		printf("pid %d attempted to set the "
435 		    "(obsolete) kernel time zone\n", p->p_pid);
436 	return (0);
437 }
438 
439 int
440 netbsd32_adjtime(p, v, retval)
441 	struct proc *p;
442 	void *v;
443 	register_t *retval;
444 {
445 	struct netbsd32_adjtime_args /* {
446 		syscallarg(const netbsd32_timevalp_t) delta;
447 		syscallarg(netbsd32_timevalp_t) olddelta;
448 	} */ *uap = v;
449 	struct netbsd32_timeval atv;
450 	int32_t ndelta, ntickdelta, odelta;
451 	int s, error;
452 	extern long bigadj, timedelta;
453 	extern int tickdelta;
454 
455 	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
456 		return (error);
457 
458 	error = copyin((caddr_t)NETBSD32PTR64(SCARG(uap, delta)), &atv,
459 	    sizeof(struct timeval));
460 	if (error)
461 		return (error);
462 	/*
463 	 * Compute the total correction and the rate at which to apply it.
464 	 * Round the adjustment down to a whole multiple of the per-tick
465 	 * delta, so that after some number of incremental changes in
466 	 * hardclock(), tickdelta will become zero, lest the correction
467 	 * overshoot and start taking us away from the desired final time.
468 	 */
469 	ndelta = atv.tv_sec * 1000000 + atv.tv_usec;
470 	if (ndelta > bigadj)
471 		ntickdelta = 10 * tickadj;
472 	else
473 		ntickdelta = tickadj;
474 	if (ndelta % ntickdelta)
475 		ndelta = ndelta / ntickdelta * ntickdelta;
476 
477 	/*
478 	 * To make hardclock()'s job easier, make the per-tick delta negative
479 	 * if we want time to run slower; then hardclock can simply compute
480 	 * tick + tickdelta, and subtract tickdelta from timedelta.
481 	 */
482 	if (ndelta < 0)
483 		ntickdelta = -ntickdelta;
484 	s = splclock();
485 	odelta = timedelta;
486 	timedelta = ndelta;
487 	tickdelta = ntickdelta;
488 	splx(s);
489 
490 	if (SCARG(uap, olddelta)) {
491 		atv.tv_sec = odelta / 1000000;
492 		atv.tv_usec = odelta % 1000000;
493 		(void) copyout(&atv,
494 		    (caddr_t)NETBSD32PTR64(SCARG(uap, olddelta)), sizeof(atv));
495 	}
496 	return (0);
497 }
498 
499 int
500 netbsd32_clock_gettime(p, v, retval)
501 	struct proc *p;
502 	void *v;
503 	register_t *retval;
504 {
505 	struct netbsd32_clock_gettime_args /* {
506 		syscallarg(netbsd32_clockid_t) clock_id;
507 		syscallarg(netbsd32_timespecp_t) tp;
508 	} */ *uap = v;
509 	clockid_t clock_id;
510 	struct timeval atv;
511 	struct timespec ats;
512 	struct netbsd32_timespec ts32;
513 
514 	clock_id = SCARG(uap, clock_id);
515 	if (clock_id != CLOCK_REALTIME)
516 		return (EINVAL);
517 
518 	microtime(&atv);
519 	TIMEVAL_TO_TIMESPEC(&atv,&ats);
520 	netbsd32_from_timespec(&ats, &ts32);
521 
522 	return copyout(&ts32, (caddr_t)NETBSD32PTR64(SCARG(uap, tp)),
523 	    sizeof(ts32));
524 }
525 
526 int
527 netbsd32_clock_settime(p, v, retval)
528 	struct proc *p;
529 	void *v;
530 	register_t *retval;
531 {
532 	struct netbsd32_clock_settime_args /* {
533 		syscallarg(netbsd32_clockid_t) clock_id;
534 		syscallarg(const netbsd32_timespecp_t) tp;
535 	} */ *uap = v;
536 	struct netbsd32_timespec ts32;
537 	clockid_t clock_id;
538 	struct timeval atv;
539 	struct timespec ats;
540 	int error;
541 
542 	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
543 		return (error);
544 
545 	clock_id = SCARG(uap, clock_id);
546 	if (clock_id != CLOCK_REALTIME)
547 		return (EINVAL);
548 
549 	if ((error = copyin((caddr_t)NETBSD32PTR64(SCARG(uap, tp)), &ts32,
550 	    sizeof(ts32))) != 0)
551 		return (error);
552 
553 	netbsd32_to_timespec(&ts32, &ats);
554 	TIMESPEC_TO_TIMEVAL(&atv,&ats);
555 	if ((error = settime(&atv)))
556 		return (error);
557 
558 	return 0;
559 }
560 
561 int
562 netbsd32_clock_getres(p, v, retval)
563 	struct proc *p;
564 	void *v;
565 	register_t *retval;
566 {
567 	struct netbsd32_clock_getres_args /* {
568 		syscallarg(netbsd32_clockid_t) clock_id;
569 		syscallarg(netbsd32_timespecp_t) tp;
570 	} */ *uap = v;
571 	struct netbsd32_timespec ts32;
572 	clockid_t clock_id;
573 	struct timespec ts;
574 	int error = 0;
575 
576 	clock_id = SCARG(uap, clock_id);
577 	if (clock_id != CLOCK_REALTIME)
578 		return (EINVAL);
579 
580 	if (SCARG(uap, tp)) {
581 		ts.tv_sec = 0;
582 		ts.tv_nsec = 1000000000 / hz;
583 
584 		netbsd32_from_timespec(&ts, &ts32);
585 		error = copyout(&ts, (caddr_t)NETBSD32PTR64(SCARG(uap, tp)),
586 		    sizeof(ts));
587 	}
588 
589 	return error;
590 }
591 
592 int
593 netbsd32_nanosleep(p, v, retval)
594 	struct proc *p;
595 	void *v;
596 	register_t *retval;
597 {
598 	struct netbsd32_nanosleep_args /* {
599 		syscallarg(const netbsd32_timespecp_t) rqtp;
600 		syscallarg(netbsd32_timespecp_t) rmtp;
601 	} */ *uap = v;
602 	static int nanowait;
603 	struct netbsd32_timespec ts32;
604 	struct timespec rqt;
605 	struct timespec rmt;
606 	struct timeval atv, utv;
607 	int error, s, timo;
608 
609 	error = copyin((caddr_t)NETBSD32PTR64(SCARG(uap, rqtp)), (caddr_t)&ts32,
610 	    sizeof(ts32));
611 	if (error)
612 		return (error);
613 
614 	netbsd32_to_timespec(&ts32, &rqt);
615 	TIMESPEC_TO_TIMEVAL(&atv,&rqt)
616 	if (itimerfix(&atv))
617 		return (EINVAL);
618 
619 	s = splclock();
620 	timeradd(&atv,&time,&atv);
621 	timo = hzto(&atv);
622 	/*
623 	 * Avoid inadvertantly sleeping forever
624 	 */
625 	if (timo == 0)
626 		timo = 1;
627 	splx(s);
628 
629 	error = tsleep(&nanowait, PWAIT | PCATCH, "nanosleep", timo);
630 	if (error == ERESTART)
631 		error = EINTR;
632 	if (error == EWOULDBLOCK)
633 		error = 0;
634 
635 	if (SCARG(uap, rmtp)) {
636 		int error;
637 
638 		s = splclock();
639 		utv = time;
640 		splx(s);
641 
642 		timersub(&atv, &utv, &utv);
643 		if (utv.tv_sec < 0)
644 			timerclear(&utv);
645 
646 		TIMEVAL_TO_TIMESPEC(&utv,&rmt);
647 		netbsd32_from_timespec(&rmt, &ts32);
648 		error = copyout((caddr_t)&ts32,
649 		    (caddr_t)NETBSD32PTR64(SCARG(uap,rmtp)), sizeof(ts32));
650 		if (error)
651 			return (error);
652 	}
653 
654 	return error;
655 }
656