1 /* $NetBSD: netbsd32_time.c,v 1.7 2004/11/14 03:30:10 atatat 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.7 2004/11/14 03:30:10 atatat 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