1 /* $NetBSD: kern_time_50.c,v 1.39 2026/09/20 13:45:00 riastradh 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.39 2026/09/20 13:45:00 riastradh Exp $"); 33 34 #ifdef _KERNEL_OPT 35 #include "opt_compat_netbsd.h" 36 #include "opt_aio.h" 37 #include "opt_ntp.h" 38 #include "opt_mqueue.h" 39 #endif 40 41 #include <sys/param.h> 42 #include <sys/conf.h> 43 #include <sys/systm.h> 44 #include <sys/namei.h> 45 #include <sys/filedesc.h> 46 #include <sys/kernel.h> 47 #include <sys/file.h> 48 #include <sys/stat.h> 49 #include <sys/socketvar.h> 50 #include <sys/vnode.h> 51 #include <sys/proc.h> 52 #include <sys/uio.h> 53 #include <sys/dirent.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/syscall.h> 61 #include <sys/syscallargs.h> 62 #include <sys/syscallvar.h> 63 #include <sys/sysctl.h> 64 #include <sys/resource.h> 65 #include <sys/compat_stub.h> 66 67 #include <compat/common/compat_util.h> 68 #include <compat/common/compat_mod.h> 69 #include <compat/sys/time.h> 70 #include <compat/sys/timex.h> 71 #include <compat/sys/resource.h> 72 #include <compat/sys/clockctl.h> 73 74 struct timeval50 boottime50; 75 76 static const struct syscall_package kern_time_50_syscalls[] = { 77 { SYS_compat_50_clock_gettime, 0, 78 (sy_call_t *)compat_50_sys_clock_gettime }, 79 { SYS_compat_50_clock_settime, 0, 80 (sy_call_t *)compat_50_sys_clock_settime }, 81 { SYS_compat_50_clock_getres, 0, 82 (sy_call_t *)compat_50_sys_clock_getres}, 83 { SYS_compat_50_nanosleep, 0, (sy_call_t *)compat_50_sys_nanosleep }, 84 { SYS_compat_50_gettimeofday, 0, 85 (sy_call_t *)compat_50_sys_gettimeofday }, 86 { SYS_compat_50_settimeofday, 0, 87 (sy_call_t *)compat_50_sys_settimeofday }, 88 { SYS_compat_50_adjtime, 0, (sy_call_t *)compat_50_sys_adjtime }, 89 { SYS_compat_50_setitimer, 0, (sy_call_t *)compat_50_sys_setitimer }, 90 { SYS_compat_50_getitimer, 0, (sy_call_t *)compat_50_sys_getitimer }, 91 { SYS_compat_50_aio_suspend, 0, 92 (sy_call_t *)compat_50_sys_aio_suspend }, 93 { SYS_compat_50_mq_timedsend, 0, 94 (sy_call_t *)compat_50_sys_mq_timedsend }, 95 { SYS_compat_50_mq_timedreceive, 0, 96 (sy_call_t *)compat_50_sys_mq_timedreceive }, 97 { SYS_compat_50_getrusage, 0, (sy_call_t *)compat_50_sys_getrusage }, 98 { SYS_compat_50_timer_settime, 0, 99 (sy_call_t *)compat_50_sys_timer_settime }, 100 { SYS_compat_50_timer_gettime, 0, 101 (sy_call_t *)compat_50_sys_timer_gettime }, 102 { SYS_compat_50___ntp_gettime30, 0, 103 (sy_call_t *)compat_50_sys___ntp_gettime30 }, 104 { 0, 0, NULL } 105 }; 106 107 int 108 compat_50_sys_clock_gettime(struct lwp *l, 109 const struct compat_50_sys_clock_gettime_args *uap, register_t *retval) 110 { 111 /* { 112 syscallarg(clockid_t) clock_id; 113 syscallarg(struct timespec50 *) tp; 114 } */ 115 int error; 116 struct timespec ats; 117 struct timespec50 ats50; 118 119 error = clock_gettime1(SCARG(uap, clock_id), &ats); 120 if (error != 0) 121 return error; 122 123 timespec_to_timespec50(&ats, &ats50); 124 125 return copyout(&ats50, SCARG(uap, tp), sizeof(ats50)); 126 } 127 128 /* ARGSUSED */ 129 int 130 compat_50_sys_clock_settime(struct lwp *l, 131 const struct compat_50_sys_clock_settime_args *uap, register_t *retval) 132 { 133 /* { 134 syscallarg(clockid_t) clock_id; 135 syscallarg(const struct timespec50 *) tp; 136 } */ 137 int error; 138 struct timespec ats; 139 struct timespec50 ats50; 140 141 error = copyin(SCARG(uap, tp), &ats50, sizeof(ats50)); 142 if (error) 143 return error; 144 timespec50_to_timespec(&ats50, &ats); 145 146 return clock_settime1(l->l_proc, SCARG(uap, clock_id), &ats, 147 true); 148 } 149 150 151 int 152 compat_50_sys_clock_getres(struct lwp *l, 153 const struct compat_50_sys_clock_getres_args *uap, register_t *retval) 154 { 155 /* { 156 syscallarg(clockid_t) clock_id; 157 syscallarg(struct timespec50 *) tp; 158 } */ 159 struct timespec50 ats50; 160 struct timespec ats; 161 int error; 162 163 error = clock_getres1(SCARG(uap, clock_id), &ats); 164 if (error != 0) 165 return error; 166 167 if (SCARG(uap, tp)) { 168 timespec_to_timespec50(&ats, &ats50); 169 error = copyout(&ats50, SCARG(uap, tp), sizeof(ats50)); 170 } 171 172 return error; 173 } 174 175 /* ARGSUSED */ 176 int 177 compat_50_sys_nanosleep(struct lwp *l, 178 const struct compat_50_sys_nanosleep_args *uap, register_t *retval) 179 { 180 /* { 181 syscallarg(struct timespec50 *) rqtp; 182 syscallarg(struct timespec50 *) rmtp; 183 } */ 184 struct timespec rmt, rqt; 185 struct timespec50 rmt50, rqt50; 186 int error, error1; 187 188 error = copyin(SCARG(uap, rqtp), &rqt50, sizeof(rqt50)); 189 if (error) 190 return error; 191 timespec50_to_timespec(&rqt50, &rqt); 192 193 error = nanosleep1(l, CLOCK_MONOTONIC, 0, &rqt, 194 SCARG(uap, rmtp) ? &rmt : NULL); 195 if (SCARG(uap, rmtp) == NULL || (error != 0 && error != EINTR)) 196 return error; 197 198 timespec_to_timespec50(&rmt, &rmt50); 199 error1 = copyout(&rmt50, SCARG(uap, rmtp), sizeof(*SCARG(uap, rmtp))); 200 return error1 ? error1 : error; 201 } 202 203 /* ARGSUSED */ 204 int 205 compat_50_sys_gettimeofday(struct lwp *l, 206 const struct compat_50_sys_gettimeofday_args *uap, register_t *retval) 207 { 208 /* { 209 syscallarg(struct timeval50 *) tp; 210 syscallarg(void *) tzp; really "struct timezone *"; 211 } */ 212 struct timeval atv; 213 struct timeval50 atv50; 214 int error = 0; 215 struct timezone tzfake; 216 217 if (SCARG(uap, tp)) { 218 microtime(&atv); 219 timeval_to_timeval50(&atv, &atv50); 220 error = copyout(&atv50, SCARG(uap, tp), sizeof(*SCARG(uap, tp))); 221 if (error) 222 return error; 223 } 224 if (SCARG(uap, tzp)) { 225 /* 226 * NetBSD has no kernel notion of time zone, so we just 227 * fake up a timezone struct and return it if demanded. 228 */ 229 memset(&tzfake, 0, sizeof(tzfake)); 230 tzfake.tz_minuteswest = 0; 231 tzfake.tz_dsttime = 0; 232 error = copyout(&tzfake, SCARG(uap, tzp), sizeof(tzfake)); 233 } 234 return error; 235 } 236 237 /* ARGSUSED */ 238 int 239 compat_50_sys_settimeofday(struct lwp *l, 240 const struct compat_50_sys_settimeofday_args *uap, register_t *retval) 241 { 242 /* { 243 syscallarg(const struct timeval50 *) tv; 244 syscallarg(const void *) tzp; really "const struct timezone *"; 245 } */ 246 struct timeval50 atv50; 247 struct timeval atv; 248 int error = copyin(SCARG(uap, tv), &atv50, sizeof(atv50)); 249 if (error) 250 return error; 251 timeval50_to_timeval(&atv50, &atv); 252 return settimeofday1(&atv, false, SCARG(uap, tzp), l, true); 253 } 254 255 /* ARGSUSED */ 256 int 257 compat_50_sys_adjtime(struct lwp *l, 258 const struct compat_50_sys_adjtime_args *uap, register_t *retval) 259 { 260 /* { 261 syscallarg(const struct timeval50 *) delta; 262 syscallarg(struct timeval50 *) olddelta; 263 } */ 264 int error; 265 struct timeval50 delta50, olddelta50; 266 struct timeval delta, olddelta; 267 268 if ((error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_TIME, 269 KAUTH_REQ_SYSTEM_TIME_ADJTIME, NULL, NULL, NULL)) != 0) 270 return error; 271 272 if (SCARG(uap, delta)) { 273 error = copyin(SCARG(uap, delta), &delta50, 274 sizeof(*SCARG(uap, delta))); 275 if (error) 276 return (error); 277 timeval50_to_timeval(&delta50, &delta); 278 } 279 adjtime1(SCARG(uap, delta) ? &delta : NULL, 280 SCARG(uap, olddelta) ? &olddelta : NULL, l->l_proc); 281 if (SCARG(uap, olddelta)) { 282 timeval_to_timeval50(&olddelta, &olddelta50); 283 error = copyout(&olddelta50, SCARG(uap, olddelta), 284 sizeof(*SCARG(uap, olddelta))); 285 } 286 return error; 287 } 288 289 /* BSD routine to set/arm an interval timer. */ 290 /* ARGSUSED */ 291 int 292 compat_50_sys_getitimer(struct lwp *l, 293 const struct compat_50_sys_getitimer_args *uap, register_t *retval) 294 { 295 /* { 296 syscallarg(int) which; 297 syscallarg(struct itimerval50 *) itv; 298 } */ 299 struct proc *p = l->l_proc; 300 struct itimerval aitv; 301 struct itimerval50 aitv50; 302 int error; 303 304 error = dogetitimer(p, SCARG(uap, which), &aitv); 305 if (error) 306 return error; 307 itimerval_to_itimerval50(&aitv, &aitv50); 308 return copyout(&aitv50, SCARG(uap, itv), sizeof(*SCARG(uap, itv))); 309 } 310 311 int 312 compat_50_sys_setitimer(struct lwp *l, 313 const struct compat_50_sys_setitimer_args *uap, register_t *retval) 314 { 315 /* { 316 syscallarg(int) which; 317 syscallarg(const struct itimerval50 *) itv; 318 syscallarg(struct itimerval50 *) oitv; 319 } */ 320 struct proc *p = l->l_proc; 321 int which = SCARG(uap, which); 322 struct compat_50_sys_getitimer_args getargs; 323 const struct itimerval50 *itvp; 324 struct itimerval50 aitv50; 325 struct itimerval aitv; 326 int error; 327 328 itvp = SCARG(uap, itv); 329 if (itvp && 330 (error = copyin(itvp, &aitv50, sizeof(aitv50))) != 0) 331 return (error); 332 itimerval50_to_itimerval(&aitv50, &aitv); 333 if (SCARG(uap, oitv) != NULL) { 334 memset(&getargs, 0, sizeof(getargs)); 335 SCARG(&getargs, which) = which; 336 SCARG(&getargs, itv) = SCARG(uap, oitv); 337 if ((error = compat_50_sys_getitimer(l, &getargs, retval)) != 0) 338 return (error); 339 } 340 if (itvp == 0) 341 return (0); 342 343 return dosetitimer(p, which, &aitv); 344 } 345 346 int 347 compat_50_sys_aio_suspend(struct lwp *l, 348 const struct compat_50_sys_aio_suspend_args *uap, register_t *retval) 349 { 350 /* { 351 syscallarg(const struct aiocb *const[]) list; 352 syscallarg(int) nent; 353 syscallarg(const struct timespec50 *) timeout; 354 } */ 355 #ifdef AIO 356 struct aiocb **list; 357 struct timespec ts; 358 struct timespec50 ts50; 359 int error, nent; 360 361 nent = SCARG(uap, nent); 362 if (nent <= 0 || nent > aio_listio_max) 363 return EAGAIN; 364 365 if (SCARG(uap, timeout)) { 366 /* Convert timespec to ticks */ 367 error = copyin(SCARG(uap, timeout), &ts50, 368 sizeof(*SCARG(uap, timeout))); 369 if (error) 370 return error; 371 timespec50_to_timespec(&ts50, &ts); 372 } 373 list = kmem_alloc(nent * sizeof(*list), KM_SLEEP); 374 error = copyin(SCARG(uap, list), list, nent * sizeof(*list)); 375 if (error) 376 goto out; 377 error = aio_suspend1(l, list, nent, SCARG(uap, timeout) ? &ts : NULL); 378 out: 379 kmem_free(list, nent * sizeof(*list)); 380 return error; 381 #else 382 return ENOSYS; 383 #endif 384 } 385 386 int 387 compat_50_sys_mq_timedsend(struct lwp *l, 388 const struct compat_50_sys_mq_timedsend_args *uap, register_t *retval) 389 { 390 /* { 391 syscallarg(mqd_t) mqdes; 392 syscallarg(const 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 timespec50 ts50; 399 struct timespec ts, *tsp; 400 int error; 401 402 /* Get and convert time value */ 403 if (SCARG(uap, abs_timeout)) { 404 error = copyin(SCARG(uap, abs_timeout), &ts50, sizeof(ts50)); 405 if (error) 406 return error; 407 timespec50_to_timespec(&ts50, &ts); 408 tsp = &ts; 409 } else { 410 tsp = NULL; 411 } 412 413 return mq_send1(SCARG(uap, mqdes), SCARG(uap, msg_ptr), 414 SCARG(uap, msg_len), SCARG(uap, msg_prio), tsp); 415 #else 416 return ENOSYS; 417 #endif 418 } 419 420 int 421 compat_50_sys_mq_timedreceive(struct lwp *l, 422 const struct compat_50_sys_mq_timedreceive_args *uap, register_t *retval) 423 { 424 /* { 425 syscallarg(mqd_t) mqdes; 426 syscallarg(char *) msg_ptr; 427 syscallarg(size_t) msg_len; 428 syscallarg(unsigned *) msg_prio; 429 syscallarg(const struct timespec50 *) abs_timeout; 430 } */ 431 #ifdef MQUEUE 432 struct timespec ts, *tsp; 433 struct timespec50 ts50; 434 ssize_t mlen; 435 int error; 436 437 /* Get and convert time value */ 438 if (SCARG(uap, abs_timeout)) { 439 error = copyin(SCARG(uap, abs_timeout), &ts50, sizeof(ts50)); 440 if (error) 441 return error; 442 443 timespec50_to_timespec(&ts50, &ts); 444 tsp = &ts; 445 } else { 446 tsp = NULL; 447 } 448 449 error = mq_recv1(SCARG(uap, mqdes), SCARG(uap, msg_ptr), 450 SCARG(uap, msg_len), SCARG(uap, msg_prio), tsp, &mlen); 451 if (error == 0) 452 *retval = mlen; 453 454 return error; 455 #else 456 return ENOSYS; 457 #endif 458 } 459 460 int 461 compat_50_sys_getrusage(struct lwp *l, 462 const struct compat_50_sys_getrusage_args *uap, register_t *retval) 463 { 464 /* { 465 syscallarg(int) who; 466 syscallarg(struct rusage50 *) rusage; 467 } */ 468 int error; 469 struct rusage ru; 470 struct rusage50 ru50; 471 struct proc *p = l->l_proc; 472 473 error = getrusage1(p, SCARG(uap, who), &ru); 474 if (error != 0) 475 return error; 476 477 rusage_to_rusage50(&ru, &ru50); 478 return copyout(&ru50, SCARG(uap, rusage), sizeof(ru50)); 479 } 480 481 482 /* Return the time remaining until a POSIX timer fires. */ 483 int 484 compat_50_sys_timer_gettime(struct lwp *l, 485 const struct compat_50_sys_timer_gettime_args *uap, register_t *retval) 486 { 487 /* { 488 syscallarg(timer_t) timerid; 489 syscallarg(struct itimerspec50 *) value; 490 } */ 491 struct itimerspec its; 492 struct itimerspec50 its50; 493 int error; 494 495 if ((error = dotimer_gettime(SCARG(uap, timerid), l->l_proc, 496 &its)) != 0) 497 return error; 498 itimerspec_to_itimerspec50(&its, &its50); 499 500 return copyout(&its50, SCARG(uap, value), sizeof(its50)); 501 } 502 503 /* Set and arm a POSIX realtime timer */ 504 int 505 compat_50_sys_timer_settime(struct lwp *l, 506 const struct compat_50_sys_timer_settime_args *uap, register_t *retval) 507 { 508 /* { 509 syscallarg(timer_t) timerid; 510 syscallarg(int) flags; 511 syscallarg(const struct itimerspec50 *) value; 512 syscallarg(struct itimerspec50 *) ovalue; 513 } */ 514 int error; 515 struct itimerspec value, ovalue, *ovp = NULL; 516 struct itimerspec50 value50, ovalue50; 517 518 if ((error = copyin(SCARG(uap, value), &value50, sizeof(value50))) != 0) 519 return error; 520 521 itimerspec50_to_itimerspec(&value50, &value); 522 if (SCARG(uap, ovalue)) 523 ovp = &ovalue; 524 525 if ((error = dotimer_settime(SCARG(uap, timerid), &value, ovp, 526 SCARG(uap, flags), l->l_proc)) != 0) 527 return error; 528 529 if (ovp) { 530 itimerspec_to_itimerspec50(&ovalue, &ovalue50); 531 return copyout(&ovalue50, SCARG(uap, ovalue), sizeof(ovalue50)); 532 } 533 return 0; 534 } 535 536 /* 537 * ntp_gettime() - NTP user application interface 538 */ 539 int 540 compat_50_sys___ntp_gettime30(struct lwp *l, 541 const struct compat_50_sys___ntp_gettime30_args *uap, register_t *retval) 542 { 543 if (vec_ntp_gettime == NULL) 544 return ENOSYS; /* No NTP available in kernel */ 545 546 /* { 547 syscallarg(struct ntptimeval *) ntvp; 548 } */ 549 struct ntptimeval ntv; 550 struct ntptimeval50 ntv50; 551 int error; 552 553 if (SCARG(uap, ntvp)) { 554 (*vec_ntp_gettime)(&ntv); 555 memset(&ntv50, 0, sizeof(ntv50)); 556 timespec_to_timespec50(&ntv.time, &ntv50.time); 557 ntv50.maxerror = ntv.maxerror; 558 ntv50.esterror = ntv.esterror; 559 ntv50.tai = ntv.tai; 560 ntv50.time_state = ntv.time_state; 561 562 error = copyout(&ntv50, SCARG(uap, ntvp), sizeof(ntv50)); 563 if (error) 564 return error; 565 } 566 *retval = (*vec_ntp_timestatus)(); 567 return 0; 568 } 569 570 SYSCTL_SETUP(compat_sysctl_time, "Old system boottime") 571 { 572 struct timeval tv; 573 574 getmicroboottime(&tv); 575 timeval_to_timeval50(&tv, &boottime50); 576 577 sysctl_createv(clog, 0, NULL, NULL, 578 CTLFLAG_PERMANENT, 579 CTLTYPE_STRUCT, "oboottime", 580 SYSCTL_DESCR("System boot time"), 581 NULL, 0, &boottime50, sizeof(boottime50), 582 CTL_KERN, KERN_OBOOTTIME, CTL_EOL); 583 } 584 585 int 586 kern_time_50_init(void) 587 { 588 int error; 589 590 error = syscall_establish(NULL, kern_time_50_syscalls); 591 592 return error; 593 } 594 595 int 596 kern_time_50_fini(void) 597 { 598 int error; 599 600 error = syscall_disestablish(NULL, kern_time_50_syscalls); 601 602 return error; 603 } 604