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