1 /* $NetBSD: kern_time_50.c,v 1.27 2014/04/04 18:17:36 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.27 2014/04/04 18:17:36 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/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_mq_timedsend(struct lwp *l, 354 const struct compat_50_sys_mq_timedsend_args *uap, register_t *retval) 355 { 356 /* { 357 syscallarg(mqd_t) mqdes; 358 syscallarg(const char *) msg_ptr; 359 syscallarg(size_t) msg_len; 360 syscallarg(unsigned) msg_prio; 361 syscallarg(const struct timespec50 *) abs_timeout; 362 } */ 363 #ifdef MQUEUE 364 struct timespec50 ts50; 365 struct timespec ts, *tsp; 366 int error; 367 368 /* Get and convert time value */ 369 if (SCARG(uap, abs_timeout)) { 370 error = copyin(SCARG(uap, abs_timeout), &ts50, sizeof(ts50)); 371 if (error) 372 return error; 373 timespec50_to_timespec(&ts50, &ts); 374 tsp = &ts; 375 } else { 376 tsp = NULL; 377 } 378 379 return mq_send1(SCARG(uap, mqdes), SCARG(uap, msg_ptr), 380 SCARG(uap, msg_len), SCARG(uap, msg_prio), tsp); 381 #else 382 return ENOSYS; 383 #endif 384 } 385 386 int 387 compat_50_sys_mq_timedreceive(struct lwp *l, 388 const struct compat_50_sys_mq_timedreceive_args *uap, register_t *retval) 389 { 390 /* { 391 syscallarg(mqd_t) mqdes; 392 syscallarg(char *) msg_ptr; 393 syscallarg(size_t) msg_len; 394 syscallarg(unsigned *) msg_prio; 395 syscallarg(const struct timespec50 *) abs_timeout; 396 } */ 397 #ifdef MQUEUE 398 struct timespec ts, *tsp; 399 struct timespec50 ts50; 400 ssize_t mlen; 401 int error; 402 403 /* Get and convert time value */ 404 if (SCARG(uap, abs_timeout)) { 405 error = copyin(SCARG(uap, abs_timeout), &ts50, sizeof(ts50)); 406 if (error) 407 return error; 408 409 timespec50_to_timespec(&ts50, &ts); 410 tsp = &ts; 411 } else { 412 tsp = NULL; 413 } 414 415 error = mq_recv1(SCARG(uap, mqdes), SCARG(uap, msg_ptr), 416 SCARG(uap, msg_len), SCARG(uap, msg_prio), tsp, &mlen); 417 if (error == 0) 418 *retval = mlen; 419 420 return error; 421 #else 422 return ENOSYS; 423 #endif 424 } 425 426 void 427 rusage_to_rusage50(const struct rusage *ru, struct rusage50 *ru50) 428 { 429 (void)memcpy(&ru50->ru_first, &ru->ru_first, 430 (char *)&ru50->ru_last - (char *)&ru50->ru_first + 431 sizeof(ru50->ru_last)); 432 ru50->ru_maxrss = ru->ru_maxrss; 433 timeval_to_timeval50(&ru->ru_utime, &ru50->ru_utime); 434 timeval_to_timeval50(&ru->ru_stime, &ru50->ru_stime); 435 } 436 437 int 438 compat_50_sys_getrusage(struct lwp *l, 439 const struct compat_50_sys_getrusage_args *uap, register_t *retval) 440 { 441 /* { 442 syscallarg(int) who; 443 syscallarg(struct rusage50 *) rusage; 444 } */ 445 int error; 446 struct rusage ru; 447 struct rusage50 ru50; 448 struct proc *p = l->l_proc; 449 450 error = getrusage1(p, SCARG(uap, who), &ru); 451 if (error != 0) 452 return error; 453 454 rusage_to_rusage50(&ru, &ru50); 455 return copyout(&ru50, SCARG(uap, rusage), sizeof(ru50)); 456 } 457 458 459 /* Return the time remaining until a POSIX timer fires. */ 460 int 461 compat_50_sys_timer_gettime(struct lwp *l, 462 const struct compat_50_sys_timer_gettime_args *uap, register_t *retval) 463 { 464 /* { 465 syscallarg(timer_t) timerid; 466 syscallarg(struct itimerspec50 *) value; 467 } */ 468 struct itimerspec its; 469 struct itimerspec50 its50; 470 int error; 471 472 if ((error = dotimer_gettime(SCARG(uap, timerid), l->l_proc, 473 &its)) != 0) 474 return error; 475 itimerspec_to_itimerspec50(&its, &its50); 476 477 return copyout(&its50, SCARG(uap, value), sizeof(its50)); 478 } 479 480 /* Set and arm a POSIX realtime timer */ 481 int 482 compat_50_sys_timer_settime(struct lwp *l, 483 const struct compat_50_sys_timer_settime_args *uap, register_t *retval) 484 { 485 /* { 486 syscallarg(timer_t) timerid; 487 syscallarg(int) flags; 488 syscallarg(const struct itimerspec50 *) value; 489 syscallarg(struct itimerspec50 *) ovalue; 490 } */ 491 int error; 492 struct itimerspec value, ovalue, *ovp = NULL; 493 struct itimerspec50 value50, ovalue50; 494 495 if ((error = copyin(SCARG(uap, value), &value50, sizeof(value50))) != 0) 496 return error; 497 498 itimerspec50_to_itimerspec(&value50, &value); 499 if (SCARG(uap, ovalue)) 500 ovp = &ovalue; 501 502 if ((error = dotimer_settime(SCARG(uap, timerid), &value, ovp, 503 SCARG(uap, flags), l->l_proc)) != 0) 504 return error; 505 506 if (ovp) { 507 itimerspec_to_itimerspec50(&ovalue, &ovalue50); 508 return copyout(&ovalue50, SCARG(uap, ovalue), sizeof(ovalue50)); 509 } 510 return 0; 511 } 512 513 /* 514 * ntp_gettime() - NTP user application interface 515 */ 516 int 517 compat_50_sys___ntp_gettime30(struct lwp *l, 518 const struct compat_50_sys___ntp_gettime30_args *uap, register_t *retval) 519 { 520 #ifdef NTP 521 /* { 522 syscallarg(struct ntptimeval *) ntvp; 523 } */ 524 struct ntptimeval ntv; 525 struct ntptimeval50 ntv50; 526 int error; 527 528 if (SCARG(uap, ntvp)) { 529 ntp_gettime(&ntv); 530 timespec_to_timespec50(&ntv.time, &ntv50.time); 531 ntv50.maxerror = ntv.maxerror; 532 ntv50.esterror = ntv.esterror; 533 ntv50.tai = ntv.tai; 534 ntv50.time_state = ntv.time_state; 535 536 error = copyout(&ntv50, SCARG(uap, ntvp), sizeof(ntv50)); 537 if (error) 538 return error; 539 } 540 *retval = ntp_timestatus(); 541 return 0; 542 #else 543 return ENOSYS; 544 #endif 545 } 546 int 547 compat50_clockctlioctl(dev_t dev, u_long cmd, void *data, int flags, 548 struct lwp *l) 549 { 550 int error = 0; 551 const struct cdevsw *cd = cdevsw_lookup(dev); 552 553 if (cd == NULL || cd->d_ioctl == NULL) 554 return ENXIO; 555 556 switch (cmd) { 557 case CLOCKCTL_OSETTIMEOFDAY: { 558 struct timeval50 tv50; 559 struct timeval tv; 560 struct clockctl50_settimeofday *args = data; 561 562 error = copyin(args->tv, &tv50, sizeof(tv50)); 563 if (error) 564 return (error); 565 timeval50_to_timeval(&tv50, &tv); 566 error = settimeofday1(&tv, false, args->tzp, l, false); 567 break; 568 } 569 case CLOCKCTL_OADJTIME: { 570 struct timeval atv, oldatv; 571 struct timeval50 atv50; 572 struct clockctl50_adjtime *args = data; 573 574 if (args->delta) { 575 error = copyin(args->delta, &atv50, sizeof(atv50)); 576 if (error) 577 return (error); 578 timeval50_to_timeval(&atv50, &atv); 579 } 580 adjtime1(args->delta ? &atv : NULL, 581 args->olddelta ? &oldatv : NULL, l->l_proc); 582 if (args->olddelta) { 583 timeval_to_timeval50(&oldatv, &atv50); 584 error = copyout(&atv50, args->olddelta, sizeof(atv50)); 585 } 586 break; 587 } 588 case CLOCKCTL_OCLOCK_SETTIME: { 589 struct timespec50 tp50; 590 struct timespec tp; 591 struct clockctl50_clock_settime *args = data; 592 593 error = copyin(args->tp, &tp50, sizeof(tp50)); 594 if (error) 595 return (error); 596 timespec50_to_timespec(&tp50, &tp); 597 error = clock_settime1(l->l_proc, args->clock_id, &tp, true); 598 break; 599 } 600 case CLOCKCTL_ONTP_ADJTIME: 601 /* The ioctl number changed but the data did not change. */ 602 error = (cd->d_ioctl)(dev, CLOCKCTL_NTP_ADJTIME, 603 data, flags, l); 604 break; 605 default: 606 error = EINVAL; 607 } 608 609 return (error); 610 } 611 612 void 613 compat_sysctl_time(struct sysctllog **clog) 614 { 615 struct timeval tv; 616 617 TIMESPEC_TO_TIMEVAL(&tv, &boottime); 618 timeval_to_timeval50(&tv, &boottime50); 619 620 sysctl_createv(clog, 0, NULL, NULL, 621 CTLFLAG_PERMANENT, 622 CTLTYPE_STRUCT, "oboottime", 623 SYSCTL_DESCR("System boot time"), 624 NULL, 0, &boottime50, sizeof(boottime50), 625 CTL_KERN, KERN_OBOOTTIME, CTL_EOL); 626 } 627