1 /* $NetBSD: kern_time_50.c,v 1.24 2012/11/03 23:22:21 njoly 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.24 2012/11/03 23:22:21 njoly 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/resource.h> 62 63 #include <compat/common/compat_util.h> 64 #include <compat/sys/time.h> 65 #include <compat/sys/timex.h> 66 #include <compat/sys/resource.h> 67 #include <compat/sys/clockctl.h> 68 69 int 70 compat_50_sys_clock_gettime(struct lwp *l, 71 const struct compat_50_sys_clock_gettime_args *uap, register_t *retval) 72 { 73 /* { 74 syscallarg(clockid_t) clock_id; 75 syscallarg(struct timespec50 *) tp; 76 } */ 77 int error; 78 struct timespec ats; 79 struct timespec50 ats50; 80 81 error = clock_gettime1(SCARG(uap, clock_id), &ats); 82 if (error != 0) 83 return error; 84 85 timespec_to_timespec50(&ats, &ats50); 86 87 return copyout(&ats50, SCARG(uap, tp), sizeof(ats50)); 88 } 89 90 /* ARGSUSED */ 91 int 92 compat_50_sys_clock_settime(struct lwp *l, 93 const struct compat_50_sys_clock_settime_args *uap, register_t *retval) 94 { 95 /* { 96 syscallarg(clockid_t) clock_id; 97 syscallarg(const struct timespec50 *) tp; 98 } */ 99 int error; 100 struct timespec ats; 101 struct timespec50 ats50; 102 103 error = copyin(SCARG(uap, tp), &ats50, sizeof(ats50)); 104 if (error) 105 return error; 106 timespec50_to_timespec(&ats50, &ats); 107 108 return clock_settime1(l->l_proc, SCARG(uap, clock_id), &ats, 109 true); 110 } 111 112 113 int 114 compat_50_sys_clock_getres(struct lwp *l, 115 const struct compat_50_sys_clock_getres_args *uap, register_t *retval) 116 { 117 /* { 118 syscallarg(clockid_t) clock_id; 119 syscallarg(struct timespec50 *) tp; 120 } */ 121 struct timespec50 ats50; 122 struct timespec ats; 123 int error = 0; 124 125 error = clock_getres1(SCARG(uap, clock_id), &ats); 126 if (error != 0) 127 return error; 128 129 if (SCARG(uap, tp)) { 130 timespec_to_timespec50(&ats, &ats50); 131 error = copyout(&ats50, SCARG(uap, tp), sizeof(ats50)); 132 } 133 134 return error; 135 } 136 137 /* ARGSUSED */ 138 int 139 compat_50_sys_nanosleep(struct lwp *l, 140 const struct compat_50_sys_nanosleep_args *uap, register_t *retval) 141 { 142 /* { 143 syscallarg(struct timespec50 *) rqtp; 144 syscallarg(struct timespec50 *) rmtp; 145 } */ 146 struct timespec rmt, rqt; 147 struct timespec50 rmt50, rqt50; 148 int error, error1; 149 150 error = copyin(SCARG(uap, rqtp), &rqt50, sizeof(rqt50)); 151 if (error) 152 return error; 153 timespec50_to_timespec(&rqt50, &rqt); 154 155 error = nanosleep1(l, CLOCK_MONOTONIC, 0, &rqt, 156 SCARG(uap, rmtp) ? &rmt : NULL); 157 if (SCARG(uap, rmtp) == NULL || (error != 0 && error != EINTR)) 158 return error; 159 160 timespec_to_timespec50(&rmt, &rmt50); 161 error1 = copyout(&rmt50, SCARG(uap, rmtp), sizeof(*SCARG(uap, rmtp))); 162 return error1 ? error1 : error; 163 } 164 165 /* ARGSUSED */ 166 int 167 compat_50_sys_gettimeofday(struct lwp *l, 168 const struct compat_50_sys_gettimeofday_args *uap, register_t *retval) 169 { 170 /* { 171 syscallarg(struct timeval50 *) tp; 172 syscallarg(void *) tzp; really "struct timezone *"; 173 } */ 174 struct timeval atv; 175 struct timeval50 atv50; 176 int error = 0; 177 struct timezone tzfake; 178 179 if (SCARG(uap, tp)) { 180 microtime(&atv); 181 timeval_to_timeval50(&atv, &atv50); 182 error = copyout(&atv50, SCARG(uap, tp), sizeof(*SCARG(uap, tp))); 183 if (error) 184 return error; 185 } 186 if (SCARG(uap, tzp)) { 187 /* 188 * NetBSD has no kernel notion of time zone, so we just 189 * fake up a timezone struct and return it if demanded. 190 */ 191 tzfake.tz_minuteswest = 0; 192 tzfake.tz_dsttime = 0; 193 error = copyout(&tzfake, SCARG(uap, tzp), sizeof(tzfake)); 194 } 195 return error; 196 } 197 198 /* ARGSUSED */ 199 int 200 compat_50_sys_settimeofday(struct lwp *l, 201 const struct compat_50_sys_settimeofday_args *uap, register_t *retval) 202 { 203 /* { 204 syscallarg(const struct timeval50 *) tv; 205 syscallarg(const void *) tzp; really "const struct timezone *"; 206 } */ 207 struct timeval50 atv50; 208 struct timeval atv; 209 int error = copyin(SCARG(uap, tv), &atv50, sizeof(atv50)); 210 if (error) 211 return error; 212 timeval50_to_timeval(&atv50, &atv); 213 return settimeofday1(&atv, false, SCARG(uap, tzp), l, true); 214 } 215 216 /* ARGSUSED */ 217 int 218 compat_50_sys_adjtime(struct lwp *l, 219 const struct compat_50_sys_adjtime_args *uap, register_t *retval) 220 { 221 /* { 222 syscallarg(const struct timeval50 *) delta; 223 syscallarg(struct timeval50 *) olddelta; 224 } */ 225 int error; 226 struct timeval50 delta50, olddelta50; 227 struct timeval delta, olddelta; 228 229 if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_TIME, 230 KAUTH_REQ_SYSTEM_TIME_ADJTIME, NULL, NULL, NULL)) != 0) 231 return error; 232 233 if (SCARG(uap, delta)) { 234 error = copyin(SCARG(uap, delta), &delta50, 235 sizeof(*SCARG(uap, delta))); 236 if (error) 237 return (error); 238 timeval50_to_timeval(&delta50, &delta); 239 } 240 adjtime1(SCARG(uap, delta) ? &delta : NULL, 241 SCARG(uap, olddelta) ? &olddelta : NULL, l->l_proc); 242 if (SCARG(uap, olddelta)) { 243 timeval_to_timeval50(&olddelta, &olddelta50); 244 error = copyout(&olddelta50, SCARG(uap, olddelta), 245 sizeof(*SCARG(uap, olddelta))); 246 } 247 return error; 248 } 249 250 /* BSD routine to set/arm an interval timer. */ 251 /* ARGSUSED */ 252 int 253 compat_50_sys_getitimer(struct lwp *l, 254 const struct compat_50_sys_getitimer_args *uap, register_t *retval) 255 { 256 /* { 257 syscallarg(int) which; 258 syscallarg(struct itimerval50 *) itv; 259 } */ 260 struct proc *p = l->l_proc; 261 struct itimerval aitv; 262 struct itimerval50 aitv50; 263 int error; 264 265 error = dogetitimer(p, SCARG(uap, which), &aitv); 266 if (error) 267 return error; 268 itimerval_to_itimerval50(&aitv, &aitv50); 269 return copyout(&aitv50, SCARG(uap, itv), sizeof(*SCARG(uap, itv))); 270 } 271 272 int 273 compat_50_sys_setitimer(struct lwp *l, 274 const struct compat_50_sys_setitimer_args *uap, register_t *retval) 275 { 276 /* { 277 syscallarg(int) which; 278 syscallarg(const struct itimerval50 *) itv; 279 syscallarg(struct itimerval50 *) oitv; 280 } */ 281 struct proc *p = l->l_proc; 282 int which = SCARG(uap, which); 283 struct compat_50_sys_getitimer_args getargs; 284 const struct itimerval50 *itvp; 285 struct itimerval50 aitv50; 286 struct itimerval aitv; 287 int error; 288 289 if ((u_int)which > ITIMER_PROF) 290 return (EINVAL); 291 itvp = SCARG(uap, itv); 292 if (itvp && 293 (error = copyin(itvp, &aitv50, sizeof(aitv50)) != 0)) 294 return (error); 295 itimerval50_to_itimerval(&aitv50, &aitv); 296 if (SCARG(uap, oitv) != NULL) { 297 SCARG(&getargs, which) = which; 298 SCARG(&getargs, itv) = SCARG(uap, oitv); 299 if ((error = compat_50_sys_getitimer(l, &getargs, retval)) != 0) 300 return (error); 301 } 302 if (itvp == 0) 303 return (0); 304 305 return dosetitimer(p, which, &aitv); 306 } 307 308 int 309 compat_50_sys_aio_suspend(struct lwp *l, 310 const struct compat_50_sys_aio_suspend_args *uap, register_t *retval) 311 { 312 /* { 313 syscallarg(const struct aiocb *const[]) list; 314 syscallarg(int) nent; 315 syscallarg(const struct timespec50 *) timeout; 316 } */ 317 #ifdef AIO 318 struct aiocb **list; 319 struct timespec ts; 320 struct timespec50 ts50; 321 int error, nent; 322 323 nent = SCARG(uap, nent); 324 if (nent <= 0 || nent > aio_listio_max) 325 return EAGAIN; 326 327 if (SCARG(uap, timeout)) { 328 /* Convert timespec to ticks */ 329 error = copyin(SCARG(uap, timeout), &ts50, 330 sizeof(*SCARG(uap, timeout))); 331 if (error) 332 return error; 333 timespec50_to_timespec(&ts50, &ts); 334 } 335 list = kmem_alloc(nent * sizeof(*list), KM_SLEEP); 336 error = copyin(SCARG(uap, list), list, nent * sizeof(*list)); 337 if (error) 338 goto out; 339 error = aio_suspend1(l, list, nent, SCARG(uap, timeout) ? &ts : NULL); 340 out: 341 kmem_free(list, nent * sizeof(*list)); 342 return error; 343 #else 344 return ENOSYS; 345 #endif 346 } 347 348 int 349 compat_50_sys__lwp_park(struct lwp *l, 350 const struct compat_50_sys__lwp_park_args *uap, register_t *retval) 351 { 352 /* { 353 syscallarg(const struct timespec50 *) ts; 354 syscallarg(lwpid_t) unpark; 355 syscallarg(const void *) hint; 356 syscallarg(const void *) unparkhint; 357 } */ 358 struct timespec ts, *tsp; 359 struct timespec50 ts50; 360 int error; 361 362 if (SCARG(uap, ts) == NULL) 363 tsp = NULL; 364 else { 365 error = copyin(SCARG(uap, ts), &ts50, sizeof(ts50)); 366 if (error != 0) 367 return error; 368 timespec50_to_timespec(&ts50, &ts); 369 tsp = &ts; 370 } 371 372 if (SCARG(uap, unpark) != 0) { 373 error = lwp_unpark(SCARG(uap, unpark), SCARG(uap, unparkhint)); 374 if (error != 0) 375 return error; 376 } 377 378 return lwp_park(tsp, SCARG(uap, hint)); 379 } 380 381 int 382 compat_50_sys_mq_timedsend(struct lwp *l, 383 const struct compat_50_sys_mq_timedsend_args *uap, register_t *retval) 384 { 385 /* { 386 syscallarg(mqd_t) mqdes; 387 syscallarg(const char *) msg_ptr; 388 syscallarg(size_t) msg_len; 389 syscallarg(unsigned) msg_prio; 390 syscallarg(const struct timespec50 *) abs_timeout; 391 } */ 392 #ifdef MQUEUE 393 struct timespec50 ts50; 394 struct timespec ts, *tsp; 395 int error; 396 397 /* Get and convert time value */ 398 if (SCARG(uap, abs_timeout)) { 399 error = copyin(SCARG(uap, abs_timeout), &ts50, sizeof(ts50)); 400 if (error) 401 return error; 402 timespec50_to_timespec(&ts50, &ts); 403 tsp = &ts; 404 } else { 405 tsp = NULL; 406 } 407 408 return mq_send1(SCARG(uap, mqdes), SCARG(uap, msg_ptr), 409 SCARG(uap, msg_len), SCARG(uap, msg_prio), tsp); 410 #else 411 return ENOSYS; 412 #endif 413 } 414 415 int 416 compat_50_sys_mq_timedreceive(struct lwp *l, 417 const struct compat_50_sys_mq_timedreceive_args *uap, register_t *retval) 418 { 419 /* { 420 syscallarg(mqd_t) mqdes; 421 syscallarg(char *) msg_ptr; 422 syscallarg(size_t) msg_len; 423 syscallarg(unsigned *) msg_prio; 424 syscallarg(const struct timespec50 *) abs_timeout; 425 } */ 426 #ifdef MQUEUE 427 struct timespec ts, *tsp; 428 struct timespec50 ts50; 429 ssize_t mlen; 430 int error; 431 432 /* Get and convert time value */ 433 if (SCARG(uap, abs_timeout)) { 434 error = copyin(SCARG(uap, abs_timeout), &ts50, sizeof(ts50)); 435 if (error) 436 return error; 437 438 timespec50_to_timespec(&ts50, &ts); 439 tsp = &ts; 440 } else { 441 tsp = NULL; 442 } 443 444 error = mq_recv1(SCARG(uap, mqdes), SCARG(uap, msg_ptr), 445 SCARG(uap, msg_len), SCARG(uap, msg_prio), tsp, &mlen); 446 if (error == 0) 447 *retval = mlen; 448 449 return error; 450 #else 451 return ENOSYS; 452 #endif 453 } 454 455 static int 456 tscopyin(const void *u, void *s, size_t len) 457 { 458 struct timespec50 ts50; 459 int error; 460 461 KASSERT(len == sizeof(struct timespec)); 462 error = copyin(u, &ts50, sizeof(ts50)); 463 if (error) 464 return error; 465 timespec50_to_timespec(&ts50, s); 466 return 0; 467 } 468 469 static int 470 tscopyout(const void *s, void *u, size_t len) 471 { 472 struct timespec50 ts50; 473 474 KASSERT(len == sizeof(struct timespec)); 475 timespec_to_timespec50(s, &ts50); 476 return copyout(&ts50, u, sizeof(ts50)); 477 } 478 479 int 480 compat_50_sys___sigtimedwait(struct lwp *l, 481 const struct compat_50_sys___sigtimedwait_args *uap, register_t *retval) 482 { 483 int res; 484 485 res = sigtimedwait1(l, 486 (const struct sys_____sigtimedwait50_args *)uap, retval, copyin, 487 copyout, tscopyin, tscopyout); 488 if (!res) 489 *retval = 0; /* XXX NetBSD<=5 was not POSIX compliant */ 490 return res; 491 } 492 493 void 494 rusage_to_rusage50(const struct rusage *ru, struct rusage50 *ru50) 495 { 496 (void)memcpy(&ru50->ru_first, &ru->ru_first, 497 (char *)&ru50->ru_last - (char *)&ru50->ru_first + 498 sizeof(ru50->ru_last)); 499 ru50->ru_maxrss = ru->ru_maxrss; 500 timeval_to_timeval50(&ru->ru_utime, &ru50->ru_utime); 501 timeval_to_timeval50(&ru->ru_stime, &ru50->ru_stime); 502 } 503 504 int 505 compat_50_sys_getrusage(struct lwp *l, 506 const struct compat_50_sys_getrusage_args *uap, register_t *retval) 507 { 508 /* { 509 syscallarg(int) who; 510 syscallarg(struct rusage50 *) rusage; 511 } */ 512 int error; 513 struct rusage ru; 514 struct rusage50 ru50; 515 struct proc *p = l->l_proc; 516 517 error = getrusage1(p, SCARG(uap, who), &ru); 518 if (error != 0) 519 return error; 520 521 rusage_to_rusage50(&ru, &ru50); 522 return copyout(&ru50, SCARG(uap, rusage), sizeof(ru50)); 523 } 524 525 526 /* Return the time remaining until a POSIX timer fires. */ 527 int 528 compat_50_sys_timer_gettime(struct lwp *l, 529 const struct compat_50_sys_timer_gettime_args *uap, register_t *retval) 530 { 531 /* { 532 syscallarg(timer_t) timerid; 533 syscallarg(struct itimerspec50 *) value; 534 } */ 535 struct itimerspec its; 536 struct itimerspec50 its50; 537 int error; 538 539 if ((error = dotimer_gettime(SCARG(uap, timerid), l->l_proc, 540 &its)) != 0) 541 return error; 542 itimerspec_to_itimerspec50(&its, &its50); 543 544 return copyout(&its50, SCARG(uap, value), sizeof(its50)); 545 } 546 547 /* Set and arm a POSIX realtime timer */ 548 int 549 compat_50_sys_timer_settime(struct lwp *l, 550 const struct compat_50_sys_timer_settime_args *uap, register_t *retval) 551 { 552 /* { 553 syscallarg(timer_t) timerid; 554 syscallarg(int) flags; 555 syscallarg(const struct itimerspec50 *) value; 556 syscallarg(struct itimerspec50 *) ovalue; 557 } */ 558 int error; 559 struct itimerspec value, ovalue, *ovp = NULL; 560 struct itimerspec50 value50, ovalue50; 561 562 if ((error = copyin(SCARG(uap, value), &value50, sizeof(value50))) != 0) 563 return error; 564 565 itimerspec50_to_itimerspec(&value50, &value); 566 if (SCARG(uap, ovalue)) 567 ovp = &ovalue; 568 569 if ((error = dotimer_settime(SCARG(uap, timerid), &value, ovp, 570 SCARG(uap, flags), l->l_proc)) != 0) 571 return error; 572 573 if (ovp) { 574 itimerspec_to_itimerspec50(&ovalue, &ovalue50); 575 return copyout(&ovalue50, SCARG(uap, ovalue), sizeof(ovalue50)); 576 } 577 return 0; 578 } 579 580 /* 581 * ntp_gettime() - NTP user application interface 582 */ 583 int 584 compat_50_sys___ntp_gettime30(struct lwp *l, 585 const struct compat_50_sys___ntp_gettime30_args *uap, register_t *retval) 586 { 587 #ifdef NTP 588 /* { 589 syscallarg(struct ntptimeval *) ntvp; 590 } */ 591 struct ntptimeval ntv; 592 struct ntptimeval50 ntv50; 593 int error; 594 595 if (SCARG(uap, ntvp)) { 596 ntp_gettime(&ntv); 597 timespec_to_timespec50(&ntv.time, &ntv50.time); 598 ntv50.maxerror = ntv.maxerror; 599 ntv50.esterror = ntv.esterror; 600 ntv50.tai = ntv.tai; 601 ntv50.time_state = ntv.time_state; 602 603 error = copyout(&ntv50, SCARG(uap, ntvp), sizeof(ntv50)); 604 if (error) 605 return error; 606 } 607 *retval = ntp_timestatus(); 608 return 0; 609 #else 610 return ENOSYS; 611 #endif 612 } 613 int 614 compat50_clockctlioctl(dev_t dev, u_long cmd, void *data, int flags, 615 struct lwp *l) 616 { 617 int error = 0; 618 const struct cdevsw *cd = cdevsw_lookup(dev); 619 620 if (cd == NULL || cd->d_ioctl == NULL) 621 return ENXIO; 622 623 switch (cmd) { 624 case CLOCKCTL_OSETTIMEOFDAY: { 625 struct timeval50 tv50; 626 struct timeval tv; 627 struct clockctl50_settimeofday *args = data; 628 629 error = copyin(args->tv, &tv50, sizeof(tv50)); 630 if (error) 631 return (error); 632 timeval50_to_timeval(&tv50, &tv); 633 error = settimeofday1(&tv, false, args->tzp, l, false); 634 break; 635 } 636 case CLOCKCTL_OADJTIME: { 637 struct timeval atv, oldatv; 638 struct timeval50 atv50; 639 struct clockctl50_adjtime *args = data; 640 641 if (args->delta) { 642 error = copyin(args->delta, &atv50, sizeof(atv50)); 643 if (error) 644 return (error); 645 timeval50_to_timeval(&atv50, &atv); 646 } 647 adjtime1(args->delta ? &atv : NULL, 648 args->olddelta ? &oldatv : NULL, l->l_proc); 649 if (args->olddelta) { 650 timeval_to_timeval50(&oldatv, &atv50); 651 error = copyout(&atv50, args->olddelta, sizeof(atv50)); 652 } 653 break; 654 } 655 case CLOCKCTL_OCLOCK_SETTIME: { 656 struct timespec50 tp50; 657 struct timespec tp; 658 struct clockctl50_clock_settime *args = data; 659 660 error = copyin(args->tp, &tp50, sizeof(tp50)); 661 if (error) 662 return (error); 663 timespec50_to_timespec(&tp50, &tp); 664 error = clock_settime1(l->l_proc, args->clock_id, &tp, true); 665 break; 666 } 667 case CLOCKCTL_ONTP_ADJTIME: 668 /* The ioctl number changed but the data did not change. */ 669 error = (cd->d_ioctl)(dev, CLOCKCTL_NTP_ADJTIME, 670 data, flags, l); 671 break; 672 default: 673 error = EINVAL; 674 } 675 676 return (error); 677 } 678 int 679 compat_50_sys_wait4(struct lwp *l, const struct compat_50_sys_wait4_args *uap, 680 register_t *retval) 681 { 682 /* { 683 syscallarg(int) pid; 684 syscallarg(int *) status; 685 syscallarg(int) options; 686 syscallarg(struct rusage50 *) rusage; 687 } */ 688 int status, error, pid = SCARG(uap, pid); 689 struct rusage50 ru50; 690 struct rusage ru; 691 692 error = do_sys_wait(&pid, &status, SCARG(uap, options), 693 SCARG(uap, rusage) != NULL ? &ru : NULL); 694 695 retval[0] = pid; 696 if (pid == 0) 697 return error; 698 699 if (SCARG(uap, rusage)) { 700 rusage_to_rusage50(&ru, &ru50); 701 error = copyout(&ru50, SCARG(uap, rusage), sizeof(ru50)); 702 } 703 704 if (error == 0 && SCARG(uap, status)) 705 error = copyout(&status, SCARG(uap, status), sizeof(status)); 706 707 return error; 708 } 709