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