Home | History | Annotate | Line # | Download | only in netbsd32
netbsd32_time.c revision 1.3
      1 /*	$NetBSD: netbsd32_time.c,v 1.3 2001/11/13 02:09:10 lukem 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.3 2001/11/13 02:09:10 lukem 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, (caddr_t)(u_long)SCARG(uap, ntvp),
    101 		    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)(u_long)SCARG(uap, tp), (caddr_t)&ntv32,
    168 			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)(u_long)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 *)(u_long)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)(u_long)SCARG(uap, itv), sizeof(s32it)));
    364 }
    365 
    366 int
    367 netbsd32_gettimeofday(p, v, retval)
    368 	struct proc *p;
    369 	void *v;
    370 	register_t *retval;
    371 {
    372 	struct netbsd32_gettimeofday_args /* {
    373 		syscallarg(netbsd32_timevalp_t) tp;
    374 		syscallarg(netbsd32_timezonep_t) tzp;
    375 	} */ *uap = v;
    376 	struct timeval atv;
    377 	struct netbsd32_timeval tv32;
    378 	int error = 0;
    379 	struct netbsd32_timezone tzfake;
    380 
    381 	if (SCARG(uap, tp)) {
    382 		microtime(&atv);
    383 		netbsd32_from_timeval(&atv, &tv32);
    384 		error = copyout(&tv32, (caddr_t)(u_long)SCARG(uap, tp), sizeof(tv32));
    385 		if (error)
    386 			return (error);
    387 	}
    388 	if (SCARG(uap, tzp)) {
    389 		/*
    390 		 * NetBSD has no kernel notion of time zone, so we just
    391 		 * fake up a timezone struct and return it if demanded.
    392 		 */
    393 		tzfake.tz_minuteswest = 0;
    394 		tzfake.tz_dsttime = 0;
    395 		error = copyout(&tzfake, (caddr_t)(u_long)SCARG(uap, tzp), sizeof(tzfake));
    396 	}
    397 	return (error);
    398 }
    399 
    400 int
    401 netbsd32_settimeofday(p, v, retval)
    402 	struct proc *p;
    403 	void *v;
    404 	register_t *retval;
    405 {
    406 	struct netbsd32_settimeofday_args /* {
    407 		syscallarg(const netbsd32_timevalp_t) tv;
    408 		syscallarg(const netbsd32_timezonep_t) tzp;
    409 	} */ *uap = v;
    410 	struct netbsd32_timeval atv32;
    411 	struct timeval atv;
    412 	int error;
    413 
    414 	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
    415 		return (error);
    416 	/* Verify all parameters before changing time. */
    417 	if (SCARG(uap, tv) && (error = copyin((caddr_t)(u_long)SCARG(uap, tv),
    418 	    &atv32, sizeof(atv32))))
    419 		return (error);
    420 	netbsd32_to_timeval(&atv32, &atv);
    421 	if (SCARG(uap, tv))
    422 		if ((error = settime(&atv)))
    423 			return (error);
    424 	/* don't bother copying the tz in, we don't use it. */
    425 	/*
    426 	 * NetBSD has no kernel notion of time zone, and only an
    427 	 * obsolete program would try to set it, so we log a warning.
    428 	 */
    429 	if (SCARG(uap, tzp))
    430 		printf("pid %d attempted to set the "
    431 		    "(obsolete) kernel time zone\n", p->p_pid);
    432 	return (0);
    433 }
    434 
    435 int
    436 netbsd32_adjtime(p, v, retval)
    437 	struct proc *p;
    438 	void *v;
    439 	register_t *retval;
    440 {
    441 	struct netbsd32_adjtime_args /* {
    442 		syscallarg(const netbsd32_timevalp_t) delta;
    443 		syscallarg(netbsd32_timevalp_t) olddelta;
    444 	} */ *uap = v;
    445 	struct netbsd32_timeval atv;
    446 	int32_t ndelta, ntickdelta, odelta;
    447 	int s, error;
    448 	extern long bigadj, timedelta;
    449 	extern int tickdelta;
    450 
    451 	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
    452 		return (error);
    453 
    454 	error = copyin((caddr_t)(u_long)SCARG(uap, delta), &atv, sizeof(struct timeval));
    455 	if (error)
    456 		return (error);
    457 	/*
    458 	 * Compute the total correction and the rate at which to apply it.
    459 	 * Round the adjustment down to a whole multiple of the per-tick
    460 	 * delta, so that after some number of incremental changes in
    461 	 * hardclock(), tickdelta will become zero, lest the correction
    462 	 * overshoot and start taking us away from the desired final time.
    463 	 */
    464 	ndelta = atv.tv_sec * 1000000 + atv.tv_usec;
    465 	if (ndelta > bigadj)
    466 		ntickdelta = 10 * tickadj;
    467 	else
    468 		ntickdelta = tickadj;
    469 	if (ndelta % ntickdelta)
    470 		ndelta = ndelta / ntickdelta * ntickdelta;
    471 
    472 	/*
    473 	 * To make hardclock()'s job easier, make the per-tick delta negative
    474 	 * if we want time to run slower; then hardclock can simply compute
    475 	 * tick + tickdelta, and subtract tickdelta from timedelta.
    476 	 */
    477 	if (ndelta < 0)
    478 		ntickdelta = -ntickdelta;
    479 	s = splclock();
    480 	odelta = timedelta;
    481 	timedelta = ndelta;
    482 	tickdelta = ntickdelta;
    483 	splx(s);
    484 
    485 	if (SCARG(uap, olddelta)) {
    486 		atv.tv_sec = odelta / 1000000;
    487 		atv.tv_usec = odelta % 1000000;
    488 		(void) copyout(&atv, (caddr_t)(u_long)SCARG(uap, olddelta),
    489 		    sizeof(atv));
    490 	}
    491 	return (0);
    492 }
    493 
    494 int
    495 netbsd32_clock_gettime(p, v, retval)
    496 	struct proc *p;
    497 	void *v;
    498 	register_t *retval;
    499 {
    500 	struct netbsd32_clock_gettime_args /* {
    501 		syscallarg(netbsd32_clockid_t) clock_id;
    502 		syscallarg(netbsd32_timespecp_t) tp;
    503 	} */ *uap = v;
    504 	clockid_t clock_id;
    505 	struct timeval atv;
    506 	struct timespec ats;
    507 	struct netbsd32_timespec ts32;
    508 
    509 	clock_id = SCARG(uap, clock_id);
    510 	if (clock_id != CLOCK_REALTIME)
    511 		return (EINVAL);
    512 
    513 	microtime(&atv);
    514 	TIMEVAL_TO_TIMESPEC(&atv,&ats);
    515 	netbsd32_from_timespec(&ats, &ts32);
    516 
    517 	return copyout(&ts32, (caddr_t)(u_long)SCARG(uap, tp), sizeof(ts32));
    518 }
    519 
    520 int
    521 netbsd32_clock_settime(p, v, retval)
    522 	struct proc *p;
    523 	void *v;
    524 	register_t *retval;
    525 {
    526 	struct netbsd32_clock_settime_args /* {
    527 		syscallarg(netbsd32_clockid_t) clock_id;
    528 		syscallarg(const netbsd32_timespecp_t) tp;
    529 	} */ *uap = v;
    530 	struct netbsd32_timespec ts32;
    531 	clockid_t clock_id;
    532 	struct timeval atv;
    533 	struct timespec ats;
    534 	int error;
    535 
    536 	if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
    537 		return (error);
    538 
    539 	clock_id = SCARG(uap, clock_id);
    540 	if (clock_id != CLOCK_REALTIME)
    541 		return (EINVAL);
    542 
    543 	if ((error = copyin((caddr_t)(u_long)SCARG(uap, tp), &ts32, sizeof(ts32))) != 0)
    544 		return (error);
    545 
    546 	netbsd32_to_timespec(&ts32, &ats);
    547 	TIMESPEC_TO_TIMEVAL(&atv,&ats);
    548 	if ((error = settime(&atv)))
    549 		return (error);
    550 
    551 	return 0;
    552 }
    553 
    554 int
    555 netbsd32_clock_getres(p, v, retval)
    556 	struct proc *p;
    557 	void *v;
    558 	register_t *retval;
    559 {
    560 	struct netbsd32_clock_getres_args /* {
    561 		syscallarg(netbsd32_clockid_t) clock_id;
    562 		syscallarg(netbsd32_timespecp_t) tp;
    563 	} */ *uap = v;
    564 	struct netbsd32_timespec ts32;
    565 	clockid_t clock_id;
    566 	struct timespec ts;
    567 	int error = 0;
    568 
    569 	clock_id = SCARG(uap, clock_id);
    570 	if (clock_id != CLOCK_REALTIME)
    571 		return (EINVAL);
    572 
    573 	if (SCARG(uap, tp)) {
    574 		ts.tv_sec = 0;
    575 		ts.tv_nsec = 1000000000 / hz;
    576 
    577 		netbsd32_from_timespec(&ts, &ts32);
    578 		error = copyout(&ts, (caddr_t)(u_long)SCARG(uap, tp), sizeof(ts));
    579 	}
    580 
    581 	return error;
    582 }
    583 
    584 int
    585 netbsd32_nanosleep(p, v, retval)
    586 	struct proc *p;
    587 	void *v;
    588 	register_t *retval;
    589 {
    590 	struct netbsd32_nanosleep_args /* {
    591 		syscallarg(const netbsd32_timespecp_t) rqtp;
    592 		syscallarg(netbsd32_timespecp_t) rmtp;
    593 	} */ *uap = v;
    594 	static int nanowait;
    595 	struct netbsd32_timespec ts32;
    596 	struct timespec rqt;
    597 	struct timespec rmt;
    598 	struct timeval atv, utv;
    599 	int error, s, timo;
    600 
    601 	error = copyin((caddr_t)(u_long)SCARG(uap, rqtp), (caddr_t)&ts32,
    602 		       sizeof(ts32));
    603 	if (error)
    604 		return (error);
    605 
    606 	netbsd32_to_timespec(&ts32, &rqt);
    607 	TIMESPEC_TO_TIMEVAL(&atv,&rqt)
    608 	if (itimerfix(&atv))
    609 		return (EINVAL);
    610 
    611 	s = splclock();
    612 	timeradd(&atv,&time,&atv);
    613 	timo = hzto(&atv);
    614 	/*
    615 	 * Avoid inadvertantly sleeping forever
    616 	 */
    617 	if (timo == 0)
    618 		timo = 1;
    619 	splx(s);
    620 
    621 	error = tsleep(&nanowait, PWAIT | PCATCH, "nanosleep", timo);
    622 	if (error == ERESTART)
    623 		error = EINTR;
    624 	if (error == EWOULDBLOCK)
    625 		error = 0;
    626 
    627 	if (SCARG(uap, rmtp)) {
    628 		int error;
    629 
    630 		s = splclock();
    631 		utv = time;
    632 		splx(s);
    633 
    634 		timersub(&atv, &utv, &utv);
    635 		if (utv.tv_sec < 0)
    636 			timerclear(&utv);
    637 
    638 		TIMEVAL_TO_TIMESPEC(&utv,&rmt);
    639 		netbsd32_from_timespec(&rmt, &ts32);
    640 		error = copyout((caddr_t)&ts32, (caddr_t)(u_long)SCARG(uap,rmtp),
    641 			sizeof(ts32));
    642 		if (error)
    643 			return (error);
    644 	}
    645 
    646 	return error;
    647 }
    648