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