1 /* $NetBSD: kern_time_50.c,v 1.25 2013/02/21 01:39:54 pgoyette Exp $ */ 2 3 /*- 4 * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Christos Zoulas. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 #include <sys/cdefs.h> 32 __KERNEL_RCSID(0, "$NetBSD: kern_time_50.c,v 1.25 2013/02/21 01:39:54 pgoyette Exp $"); 33 34 #ifdef _KERNEL_OPT 35 #include "opt_aio.h" 36 #include "opt_ntp.h" 37 #include "opt_mqueue.h" 38 #endif 39 40 #include <sys/param.h> 41 #include <sys/conf.h> 42 #include <sys/systm.h> 43 #include <sys/namei.h> 44 #include <sys/filedesc.h> 45 #include <sys/kernel.h> 46 #include <sys/file.h> 47 #include <sys/stat.h> 48 #include <sys/socketvar.h> 49 #include <sys/vnode.h> 50 #include <sys/proc.h> 51 #include <sys/uio.h> 52 #include <sys/dirent.h> 53 #include <sys/malloc.h> 54 #include <sys/kauth.h> 55 #include <sys/time.h> 56 #include <sys/timex.h> 57 #include <sys/clockctl.h> 58 #include <sys/aio.h> 59 #include <sys/poll.h> 60 #include <sys/syscallargs.h> 61 #include <sys/sysctl.h> 62 #include <sys/resource.h> 63 64 #include <compat/common/compat_util.h> 65 #include <compat/common/compat_mod.h> 66 #include <compat/sys/time.h> 67 #include <compat/sys/timex.h> 68 #include <compat/sys/resource.h> 69 #include <compat/sys/clockctl.h> 70 71 struct timeval50 boottime50; 72 73 int 74 compat_50_sys_clock_gettime(struct lwp *l, 75 const struct compat_50_sys_clock_gettime_args *uap, register_t *retval) 76 { 77 /* { 78 syscallarg(clockid_t) clock_id; 79 syscallarg(struct timespec50 *) tp; 80 } */ 81 int error; 82 struct timespec ats; 83 struct timespec50 ats50; 84 85 error = clock_gettime1(SCARG(uap, clock_id), &ats); 86 if (error != 0) 87 return error; 88 89 timespec_to_timespec50(&ats, &ats50); 90 91 return copyout(&ats50, SCARG(uap, tp), sizeof(ats50)); 92 } 93 94 /* ARGSUSED */ 95 int 96 compat_50_sys_clock_settime(struct lwp *l, 97 const struct compat_50_sys_clock_settime_args *uap, register_t *retval) 98 { 99 /* { 100 syscallarg(clockid_t) clock_id; 101 syscallarg(const struct timespec50 *) tp; 102 } */ 103 int error; 104 struct timespec ats; 105 struct timespec50 ats50; 106 107 error = copyin(SCARG(uap, tp), &ats50, sizeof(ats50)); 108 if (error) 109 return error; 110 timespec50_to_timespec(&ats50, &ats); 111 112 return clock_settime1(l->l_proc, SCARG(uap, clock_id), &ats, 113 true); 114 } 115 116 117 int 118 compat_50_sys_clock_getres(struct lwp *l, 119 const struct compat_50_sys_clock_getres_args *uap, register_t *retval) 120 { 121 /* { 122 syscallarg(clockid_t) clock_id; 123 syscallarg(struct timespec50 *) tp; 124 } */ 125 struct timespec50 ats50; 126 struct timespec ats; 127 int error = 0; 128 129 error = clock_getres1(SCARG(uap, clock_id), &ats); 130 if (error != 0) 131 return error; 132 133 if (SCARG(uap, tp)) { 134 timespec_to_timespec50(&ats, &ats50); 135 error = copyout(&ats50, SCARG(uap, tp), sizeof(ats50)); 136 } 137 138 return error; 139 } 140 141 /* ARGSUSED */ 142 int 143 compat_50_sys_nanosleep(struct lwp *l, 144 const struct compat_50_sys_nanosleep_args *uap, register_t *retval) 145 { 146 /* { 147 syscallarg(struct timespec50 *) rqtp; 148 syscallarg(struct timespec50 *) rmtp; 149 } */ 150 struct timespec rmt, rqt; 151 struct timespec50 rmt50, rqt50; 152 int error, error1; 153 154 error = copyin(SCARG(uap, rqtp), &rqt50, sizeof(rqt50)); 155 if (error) 156 return error; 157 timespec50_to_timespec(&rqt50, &rqt); 158 159 error = nanosleep1(l, CLOCK_MONOTONIC, 0, &rqt, 160 SCARG(uap, rmtp) ? &rmt : NULL); 161 if (SCARG(uap, rmtp) == NULL || (error != 0 && error != EINTR)) 162 return error; 163 164 timespec_to_timespec50(&rmt, &rmt50); 165 error1 = copyout(&rmt50, SCARG(uap, rmtp), sizeof(*SCARG(uap, rmtp))); 166 return error1 ? error1 : error; 167 } 168 169 /* ARGSUSED */ 170 int 171 compat_50_sys_gettimeofday(struct lwp *l, 172 const struct compat_50_sys_gettimeofday_args *uap, register_t *retval) 173 { 174 /* { 175 syscallarg(struct timeval50 *) tp; 176 syscallarg(void *) tzp; really "struct timezone *"; 177 } */ 178 struct timeval atv; 179 struct timeval50 atv50; 180 int error = 0; 181 struct timezone tzfake; 182 183 if (SCARG(uap, tp)) { 184 microtime(&atv); 185 timeval_to_timeval50(&atv, &atv50); 186 error = copyout(&atv50, SCARG(uap, tp), sizeof(*SCARG(uap, tp))); 187 if (error) 188 return error; 189 } 190 if (SCARG(uap, tzp)) { 191 /* 192 * NetBSD has no kernel notion of time zone, so we just 193 * fake up a timezone struct and return it if demanded. 194 */ 195 tzfake.tz_minuteswest = 0; 196 tzfake.tz_dsttime = 0; 197 error = copyout(&tzfake, SCARG(uap, tzp), sizeof(tzfake)); 198 } 199 return error; 200 } 201 202 /* ARGSUSED */ 203 int 204 compat_50_sys_settimeofday(struct lwp *l, 205 const struct compat_50_sys_settimeofday_args *uap, register_t *retval) 206 { 207 /* { 208 syscallarg(const struct timeval50 *) tv; 209 syscallarg(const void *) tzp; really "const struct timezone *"; 210 } */ 211 struct timeval50 atv50; 212 struct timeval atv; 213 int error = copyin(SCARG(uap, tv), &atv50, sizeof(atv50)); 214 if (error) 215 return error; 216 timeval50_to_timeval(&atv50, &atv); 217 return settimeofday1(&atv, false, SCARG(uap, tzp), l, true); 218 } 219 220 /* ARGSUSED */ 221 int 222 compat_50_sys_adjtime(struct lwp *l, 223 const struct compat_50_sys_adjtime_args *uap, register_t *retval) 224 { 225 /* { 226 syscallarg(const struct timeval50 *) delta; 227 syscallarg(struct timeval50 *) olddelta; 228 } */ 229 int error; 230 struct timeval50 delta50, olddelta50; 231 struct timeval delta, olddelta; 232 233 if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_TIME, 234 KAUTH_REQ_SYSTEM_TIME_ADJTIME, NULL, NULL, NULL)) != 0) 235 return error; 236 237 if (SCARG(uap, delta)) { 238 error = copyin(SCARG(uap, delta), &delta50, 239 sizeof(*SCARG(uap, delta))); 240 if (error) 241 return (error); 242 timeval50_to_timeval(&delta50, &delta); 243 } 244 adjtime1(SCARG(uap, delta) ? &delta : NULL, 245 SCARG(uap, olddelta) ? &olddelta : NULL, l->l_proc); 246 if (SCARG(uap, olddelta)) { 247 timeval_to_timeval50(&olddelta, &olddelta50); 248 error = copyout(&olddelta50, SCARG(uap, olddelta), 249 sizeof(*SCARG(uap, olddelta))); 250 } 251 return error; 252 } 253 254 /* BSD routine to set/arm an interval timer. */ 255 /* ARGSUSED */ 256 int 257 compat_50_sys_getitimer(struct lwp *l, 258 const struct compat_50_sys_getitimer_args *uap, register_t *retval) 259 { 260 /* { 261 syscallarg(int) which; 262 syscallarg(struct itimerval50 *) itv; 263 } */ 264 struct proc *p = l->l_proc; 265 struct itimerval aitv; 266 struct itimerval50 aitv50; 267 int error; 268 269 error = dogetitimer(p, SCARG(uap, which), &aitv); 270 if (error) 271 return error; 272 itimerval_to_itimerval50(&aitv, &aitv50); 273 return copyout(&aitv50, SCARG(uap, itv), sizeof(*SCARG(uap, itv))); 274 } 275 276 int 277 compat_50_sys_setitimer(struct lwp *l, 278 const struct compat_50_sys_setitimer_args *uap, register_t *retval) 279 { 280 /* { 281 syscallarg(int) which; 282 syscallarg(const struct itimerval50 *) itv; 283 syscallarg(struct itimerval50 *) oitv; 284 } */ 285 struct proc *p = l->l_proc; 286 int which = SCARG(uap, which); 287 struct compat_50_sys_getitimer_args getargs; 288 const struct itimerval50 *itvp; 289 struct itimerval50 aitv50; 290 struct itimerval aitv; 291 int error; 292 293 if ((u_int)which > ITIMER_PROF) 294 return (EINVAL); 295 itvp = SCARG(uap, itv); 296 if (itvp && 297 (error = copyin(itvp, &aitv50, sizeof(aitv50)) != 0)) 298 return (error); 299 itimerval50_to_itimerval(&aitv50, &aitv); 300 if (SCARG(uap, oitv) != NULL) { 301 SCARG(&getargs, which) = which; 302 SCARG(&getargs, itv) = SCARG(uap, oitv); 303 if ((error = compat_50_sys_getitimer(l, &getargs, retval)) != 0) 304 return (error); 305 } 306 if (itvp == 0) 307 return (0); 308 309 return dosetitimer(p, which, &aitv); 310 } 311 312 int 313 compat_50_sys_aio_suspend(struct lwp *l, 314 const struct compat_50_sys_aio_suspend_args *uap, register_t *retval) 315 { 316 /* { 317 syscallarg(const struct aiocb *const[]) list; 318 syscallarg(int) nent; 319 syscallarg(const struct timespec50 *) timeout; 320 } */ 321 #ifdef AIO 322 struct aiocb **list; 323 struct timespec ts; 324 struct timespec50 ts50; 325 int error, nent; 326 327 nent = SCARG(uap, nent); 328 if (nent <= 0 || nent > aio_listio_max) 329 return EAGAIN; 330 331 if (SCARG(uap, timeout)) { 332 /* Convert timespec to ticks */ 333 error = copyin(SCARG(uap, timeout), &ts50, 334 sizeof(*SCARG(uap, timeout))); 335 if (error) 336 return error; 337 timespec50_to_timespec(&ts50, &ts); 338 } 339 list = kmem_alloc(nent * sizeof(*list), KM_SLEEP); 340 error = copyin(SCARG(uap, list), list, nent * sizeof(*list)); 341 if (error) 342 goto out; 343 error = aio_suspend1(l, list, nent, SCARG(uap, timeout) ? &ts : NULL); 344 out: 345 kmem_free(list, nent * sizeof(*list)); 346 return error; 347 #else 348 return ENOSYS; 349 #endif 350 } 351 352 int 353 compat_50_sys__lwp_park(struct lwp *l, 354 const struct compat_50_sys__lwp_park_args *uap, register_t *retval) 355 { 356 /* { 357 syscallarg(const struct timespec50 *) ts; 358 syscallarg(lwpid_t) unpark; 359 syscallarg(const void *) hint; 360 syscallarg(const void *) unparkhint; 361 } */ 362 struct timespec ts, *tsp; 363 struct timespec50 ts50; 364 int error; 365 366 if (SCARG(uap, ts) == NULL) 367 tsp = NULL; 368 else { 369 error = copyin(SCARG(uap, ts), &ts50, sizeof(ts50)); 370 if (error != 0) 371 return error; 372 timespec50_to_timespec(&ts50, &ts); 373 tsp = &ts; 374 } 375 376 if (SCARG(uap, unpark) != 0) { 377 error = lwp_unpark(SCARG(uap, unpark), SCARG(uap, unparkhint)); 378 if (error != 0) 379 return error; 380 } 381 382 return lwp_park(tsp, SCARG(uap, hint)); 383 } 384 385 int 386 compat_50_sys_mq_timedsend(struct lwp *l, 387 const struct compat_50_sys_mq_timedsend_args *uap, register_t *retval) 388 { 389 /* { 390 syscallarg(mqd_t) mqdes; 391 syscallarg(const char *) msg_ptr; 392 syscallarg(size_t) msg_len; 393 syscallarg(unsigned) msg_prio; 394 syscallarg(const struct timespec50 *) abs_timeout; 395 } */ 396 #ifdef MQUEUE 397 struct timespec50 ts50; 398 struct timespec ts, *tsp; 399 int error; 400 401 /* Get and convert time value */ 402 if (SCARG(uap, abs_timeout)) { 403 error = copyin(SCARG(uap, abs_timeout), &ts50, sizeof(ts50)); 404 if (error) 405 return error; 406 timespec50_to_timespec(&ts50, &ts); 407 tsp = &ts; 408 } else { 409 tsp = NULL; 410 } 411 412 return mq_send1(SCARG(uap, mqdes), SCARG(uap, msg_ptr), 413 SCARG(uap, msg_len), SCARG(uap, msg_prio), tsp); 414 #else 415 return ENOSYS; 416 #endif 417 } 418 419 int 420 compat_50_sys_mq_timedreceive(struct lwp *l, 421 const struct compat_50_sys_mq_timedreceive_args *uap, register_t *retval) 422 { 423 /* { 424 syscallarg(mqd_t) mqdes; 425 syscallarg(char *) msg_ptr; 426 syscallarg(size_t) msg_len; 427 syscallarg(unsigned *) msg_prio; 428 syscallarg(const struct timespec50 *) abs_timeout; 429 } */ 430 #ifdef MQUEUE 431 struct timespec ts, *tsp; 432 struct timespec50 ts50; 433 ssize_t mlen; 434 int error; 435 436 /* Get and convert time value */ 437 if (SCARG(uap, abs_timeout)) { 438 error = copyin(SCARG(uap, abs_timeout), &ts50, sizeof(ts50)); 439 if (error) 440 return error; 441 442 timespec50_to_timespec(&ts50, &ts); 443 tsp = &ts; 444 } else { 445 tsp = NULL; 446 } 447 448 error = mq_recv1(SCARG(uap, mqdes), SCARG(uap, msg_ptr), 449 SCARG(uap, msg_len), SCARG(uap, msg_prio), tsp, &mlen); 450 if (error == 0) 451 *retval = mlen; 452 453 return error; 454 #else 455 return ENOSYS; 456 #endif 457 } 458 459 static int 460 tscopyin(const void *u, void *s, size_t len) 461 { 462 struct timespec50 ts50; 463 int error; 464 465 KASSERT(len == sizeof(struct timespec)); 466 error = copyin(u, &ts50, sizeof(ts50)); 467 if (error) 468 return error; 469 timespec50_to_timespec(&ts50, s); 470 return 0; 471 } 472 473 static int 474 tscopyout(const void *s, void *u, size_t len) 475 { 476 struct timespec50 ts50; 477 478 KASSERT(len == sizeof(struct timespec)); 479 timespec_to_timespec50(s, &ts50); 480 return copyout(&ts50, u, sizeof(ts50)); 481 } 482 483 int 484 compat_50_sys___sigtimedwait(struct lwp *l, 485 const struct compat_50_sys___sigtimedwait_args *uap, register_t *retval) 486 { 487 int res; 488 489 res = sigtimedwait1(l, 490 (const struct sys_____sigtimedwait50_args *)uap, retval, copyin, 491 copyout, tscopyin, tscopyout); 492 if (!res) 493 *retval = 0; /* XXX NetBSD<=5 was not POSIX compliant */ 494 return res; 495 } 496 497 void 498 rusage_to_rusage50(const struct rusage *ru, struct rusage50 *ru50) 499 { 500 (void)memcpy(&ru50->ru_first, &ru->ru_first, 501 (char *)&ru50->ru_last - (char *)&ru50->ru_first + 502 sizeof(ru50->ru_last)); 503 ru50->ru_maxrss = ru->ru_maxrss; 504 timeval_to_timeval50(&ru->ru_utime, &ru50->ru_utime); 505 timeval_to_timeval50(&ru->ru_stime, &ru50->ru_stime); 506 } 507 508 int 509 compat_50_sys_getrusage(struct lwp *l, 510 const struct compat_50_sys_getrusage_args *uap, register_t *retval) 511 { 512 /* { 513 syscallarg(int) who; 514 syscallarg(struct rusage50 *) rusage; 515 } */ 516 int error; 517 struct rusage ru; 518 struct rusage50 ru50; 519 struct proc *p = l->l_proc; 520 521 error = getrusage1(p, SCARG(uap, who), &ru); 522 if (error != 0) 523 return error; 524 525 rusage_to_rusage50(&ru, &ru50); 526 return copyout(&ru50, SCARG(uap, rusage), sizeof(ru50)); 527 } 528 529 530 /* Return the time remaining until a POSIX timer fires. */ 531 int 532 compat_50_sys_timer_gettime(struct lwp *l, 533 const struct compat_50_sys_timer_gettime_args *uap, register_t *retval) 534 { 535 /* { 536 syscallarg(timer_t) timerid; 537 syscallarg(struct itimerspec50 *) value; 538 } */ 539 struct itimerspec its; 540 struct itimerspec50 its50; 541 int error; 542 543 if ((error = dotimer_gettime(SCARG(uap, timerid), l->l_proc, 544 &its)) != 0) 545 return error; 546 itimerspec_to_itimerspec50(&its, &its50); 547 548 return copyout(&its50, SCARG(uap, value), sizeof(its50)); 549 } 550 551 /* Set and arm a POSIX realtime timer */ 552 int 553 compat_50_sys_timer_settime(struct lwp *l, 554 const struct compat_50_sys_timer_settime_args *uap, register_t *retval) 555 { 556 /* { 557 syscallarg(timer_t) timerid; 558 syscallarg(int) flags; 559 syscallarg(const struct itimerspec50 *) value; 560 syscallarg(struct itimerspec50 *) ovalue; 561 } */ 562 int error; 563 struct itimerspec value, ovalue, *ovp = NULL; 564 struct itimerspec50 value50, ovalue50; 565 566 if ((error = copyin(SCARG(uap, value), &value50, sizeof(value50))) != 0) 567 return error; 568 569 itimerspec50_to_itimerspec(&value50, &value); 570 if (SCARG(uap, ovalue)) 571 ovp = &ovalue; 572 573 if ((error = dotimer_settime(SCARG(uap, timerid), &value, ovp, 574 SCARG(uap, flags), l->l_proc)) != 0) 575 return error; 576 577 if (ovp) { 578 itimerspec_to_itimerspec50(&ovalue, &ovalue50); 579 return copyout(&ovalue50, SCARG(uap, ovalue), sizeof(ovalue50)); 580 } 581 return 0; 582 } 583 584 /* 585 * ntp_gettime() - NTP user application interface 586 */ 587 int 588 compat_50_sys___ntp_gettime30(struct lwp *l, 589 const struct compat_50_sys___ntp_gettime30_args *uap, register_t *retval) 590 { 591 #ifdef NTP 592 /* { 593 syscallarg(struct ntptimeval *) ntvp; 594 } */ 595 struct ntptimeval ntv; 596 struct ntptimeval50 ntv50; 597 int error; 598 599 if (SCARG(uap, ntvp)) { 600 ntp_gettime(&ntv); 601 timespec_to_timespec50(&ntv.time, &ntv50.time); 602 ntv50.maxerror = ntv.maxerror; 603 ntv50.esterror = ntv.esterror; 604 ntv50.tai = ntv.tai; 605 ntv50.time_state = ntv.time_state; 606 607 error = copyout(&ntv50, SCARG(uap, ntvp), sizeof(ntv50)); 608 if (error) 609 return error; 610 } 611 *retval = ntp_timestatus(); 612 return 0; 613 #else 614 return ENOSYS; 615 #endif 616 } 617 int 618 compat50_clockctlioctl(dev_t dev, u_long cmd, void *data, int flags, 619 struct lwp *l) 620 { 621 int error = 0; 622 const struct cdevsw *cd = cdevsw_lookup(dev); 623 624 if (cd == NULL || cd->d_ioctl == NULL) 625 return ENXIO; 626 627 switch (cmd) { 628 case CLOCKCTL_OSETTIMEOFDAY: { 629 struct timeval50 tv50; 630 struct timeval tv; 631 struct clockctl50_settimeofday *args = data; 632 633 error = copyin(args->tv, &tv50, sizeof(tv50)); 634 if (error) 635 return (error); 636 timeval50_to_timeval(&tv50, &tv); 637 error = settimeofday1(&tv, false, args->tzp, l, false); 638 break; 639 } 640 case CLOCKCTL_OADJTIME: { 641 struct timeval atv, oldatv; 642 struct timeval50 atv50; 643 struct clockctl50_adjtime *args = data; 644 645 if (args->delta) { 646 error = copyin(args->delta, &atv50, sizeof(atv50)); 647 if (error) 648 return (error); 649 timeval50_to_timeval(&atv50, &atv); 650 } 651 adjtime1(args->delta ? &atv : NULL, 652 args->olddelta ? &oldatv : NULL, l->l_proc); 653 if (args->olddelta) { 654 timeval_to_timeval50(&oldatv, &atv50); 655 error = copyout(&atv50, args->olddelta, sizeof(atv50)); 656 } 657 break; 658 } 659 case CLOCKCTL_OCLOCK_SETTIME: { 660 struct timespec50 tp50; 661 struct timespec tp; 662 struct clockctl50_clock_settime *args = data; 663 664 error = copyin(args->tp, &tp50, sizeof(tp50)); 665 if (error) 666 return (error); 667 timespec50_to_timespec(&tp50, &tp); 668 error = clock_settime1(l->l_proc, args->clock_id, &tp, true); 669 break; 670 } 671 case CLOCKCTL_ONTP_ADJTIME: 672 /* The ioctl number changed but the data did not change. */ 673 error = (cd->d_ioctl)(dev, CLOCKCTL_NTP_ADJTIME, 674 data, flags, l); 675 break; 676 default: 677 error = EINVAL; 678 } 679 680 return (error); 681 } 682 int 683 compat_50_sys_wait4(struct lwp *l, const struct compat_50_sys_wait4_args *uap, 684 register_t *retval) 685 { 686 /* { 687 syscallarg(int) pid; 688 syscallarg(int *) status; 689 syscallarg(int) options; 690 syscallarg(struct rusage50 *) rusage; 691 } */ 692 int status, error, pid = SCARG(uap, pid); 693 struct rusage50 ru50; 694 struct rusage ru; 695 696 error = do_sys_wait(&pid, &status, SCARG(uap, options), 697 SCARG(uap, rusage) != NULL ? &ru : NULL); 698 699 retval[0] = pid; 700 if (pid == 0) 701 return error; 702 703 if (SCARG(uap, rusage)) { 704 rusage_to_rusage50(&ru, &ru50); 705 error = copyout(&ru50, SCARG(uap, rusage), sizeof(ru50)); 706 } 707 708 if (error == 0 && SCARG(uap, status)) 709 error = copyout(&status, SCARG(uap, status), sizeof(status)); 710 711 return error; 712 } 713 714 void 715 compat_sysctl_time(struct sysctllog **clog) 716 { 717 struct timeval tv; 718 719 TIMESPEC_TO_TIMEVAL(&tv, &boottime); 720 timeval_to_timeval50(&tv, &boottime50); 721 722 sysctl_createv(clog, 0, NULL, NULL, 723 CTLFLAG_PERMANENT, 724 CTLTYPE_STRUCT, "oboottime", 725 SYSCTL_DESCR("System boot time"), 726 NULL, 0, &boottime50, sizeof(boottime50), 727 CTL_KERN, KERN_OBOOTTIME, CTL_EOL); 728 } 729