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