1 /* $NetBSD: linux32_time.c,v 1.41 2026/09/20 13:43:52 riastradh Exp $ */ 2 3 /*- 4 * Copyright (c) 2006 Emmanuel Dreyfus, all rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Emmanuel Dreyfus 17 * 4. The name of the author may not be used to endorse or promote 18 * products derived from this software without specific prior written 19 * permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE THE AUTHOR AND CONTRIBUTORS ``AS IS'' 22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 23 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <sys/cdefs.h> 35 36 __KERNEL_RCSID(0, "$NetBSD: linux32_time.c,v 1.41 2026/09/20 13:43:52 riastradh Exp $"); 37 38 #include <sys/types.h> 39 #include <sys/param.h> 40 #include <sys/fstypes.h> 41 #include <sys/signal.h> 42 #include <sys/dirent.h> 43 #include <sys/kauth.h> 44 #include <sys/kernel.h> 45 #include <sys/fcntl.h> 46 #include <sys/namei.h> 47 #include <sys/select.h> 48 #include <sys/timerfd.h> 49 #include <sys/proc.h> 50 #include <sys/resourcevar.h> 51 #include <sys/ucred.h> 52 #include <sys/swap.h> 53 #include <sys/vfs_syscalls.h> 54 55 #include <machine/types.h> 56 57 #include <sys/syscallargs.h> 58 59 #include <compat/netbsd32/netbsd32.h> 60 #include <compat/netbsd32/netbsd32_conv.h> 61 #include <compat/netbsd32/netbsd32_syscallargs.h> 62 63 #include <compat/linux/common/linux_types.h> 64 #include <compat/linux/common/linux_signal.h> 65 #include <compat/linux/common/linux_machdep.h> 66 #include <compat/linux/common/linux_misc.h> 67 #include <compat/linux/common/linux_oldolduname.h> 68 #include <compat/linux/common/linux_sched.h> 69 #include <compat/linux/common/linux_ipc.h> 70 #include <compat/linux/common/linux_sem.h> 71 #include <compat/linux/linux_syscallargs.h> 72 73 #include <compat/linux32/common/linux32_types.h> 74 #include <compat/linux32/common/linux32_signal.h> 75 #include <compat/linux32/common/linux32_machdep.h> 76 #include <compat/linux32/common/linux32_sysctl.h> 77 #include <compat/linux32/common/linux32_socketcall.h> 78 #include <compat/linux32/common/linux32_sched.h> 79 #include <compat/linux32/linux32_syscallargs.h> 80 81 CTASSERT(LINUX_TIMER_ABSTIME == TIMER_ABSTIME); 82 83 extern struct timezone linux_sys_tz; 84 85 int 86 linux32_sys_gettimeofday(struct lwp *l, const struct linux32_sys_gettimeofday_args *uap, register_t *retval) 87 { 88 /* { 89 syscallarg(netbsd32_timeval50p_t) tp; 90 syscallarg(netbsd32_timezonep_t) tzp; 91 } */ 92 struct timeval tv; 93 struct netbsd32_timeval50 tv32; 94 int error; 95 96 if (SCARG_P32(uap, tp) != NULL) { 97 microtime(&tv); 98 netbsd32_from_timeval50(&tv, &tv32); 99 if ((error = copyout(&tv32, SCARG_P32(uap, tp), 100 sizeof(tv32))) != 0) 101 return error; 102 } 103 104 /* timezone size does not change */ 105 if (SCARG_P32(uap, tzp) != NULL) { 106 if ((error = copyout(&linux_sys_tz, SCARG_P32(uap, tzp), 107 sizeof(linux_sys_tz))) != 0) 108 return error; 109 } 110 111 return 0; 112 } 113 114 int 115 linux32_sys_settimeofday(struct lwp *l, const struct linux32_sys_settimeofday_args *uap, register_t *retval) 116 { 117 /* { 118 syscallarg(netbsd32_timeval50p_t) tp; 119 syscallarg(netbsd32_timezonep_t) tzp; 120 } */ 121 struct linux_sys_settimeofday_args ua; 122 123 memset(&ua, 0, sizeof(ua)); 124 NETBSD32TOP_UAP(tp, struct timeval50); 125 NETBSD32TOP_UAP(tzp, struct timezone); 126 127 return linux_sys_settimeofday(l, &ua, retval); 128 } 129 130 int 131 linux32_sys_time(struct lwp *l, const struct linux32_sys_time_args *uap, register_t *retval) 132 { 133 /* { 134 syscallarg(linux32_timep_t) t; 135 } */ 136 struct timeval atv; 137 linux32_time_t tt; 138 int error; 139 140 microtime(&atv); 141 142 tt = (linux32_time_t)atv.tv_sec; 143 144 if (SCARG_P32(uap, t) && (error = copyout(&tt, 145 SCARG_P32(uap, t), sizeof(tt)))) 146 return error; 147 148 retval[0] = tt; 149 150 return 0; 151 } 152 153 154 #define CONVTCK(r) (r.tv_sec * hz + r.tv_usec / (1000000 / hz)) 155 156 int 157 linux32_sys_times(struct lwp *l, const struct linux32_sys_times_args *uap, register_t *retval) 158 { 159 /* { 160 syscallarg(linux32_tmsp_t) tms; 161 } */ 162 struct proc *p = l->l_proc; 163 struct timeval t; 164 int error; 165 166 if (SCARG_P32(uap, tms)) { 167 struct linux32_tms ltms32; 168 struct rusage ru; 169 170 memset(<ms32, 0, sizeof(ltms32)); 171 172 mutex_enter(p->p_lock); 173 calcru(p, &ru.ru_utime, &ru.ru_stime, NULL, NULL); 174 ltms32.ltms32_utime = CONVTCK(ru.ru_utime); 175 ltms32.ltms32_stime = CONVTCK(ru.ru_stime); 176 ltms32.ltms32_cutime = CONVTCK(p->p_stats->p_cru.ru_utime); 177 ltms32.ltms32_cstime = CONVTCK(p->p_stats->p_cru.ru_stime); 178 mutex_exit(p->p_lock); 179 180 error = copyout(<ms32, SCARG_P32(uap, tms), sizeof(ltms32)); 181 if (error) 182 return error; 183 } 184 185 getmicrouptime(&t); 186 187 retval[0] = ((linux32_clock_t)(CONVTCK(t))); 188 return 0; 189 } 190 191 #undef CONVTCK 192 193 int 194 linux32_sys_stime(struct lwp *l, const struct linux32_sys_stime_args *uap, register_t *retval) 195 { 196 /* { 197 syscallarg(linux32_timep_t) t; 198 } */ 199 struct timespec ts; 200 linux32_time_t tt32; 201 int error; 202 203 if ((error = copyin(SCARG_P32(uap, t), &tt32, sizeof tt32)) != 0) 204 return error; 205 206 ts.tv_sec = (long)tt32; 207 ts.tv_nsec = 0; 208 209 return settime(l->l_proc, &ts); 210 } 211 212 int 213 linux32_sys_utime(struct lwp *l, const struct linux32_sys_utime_args *uap, register_t *retval) 214 { 215 /* { 216 syscallarg(const netbsd32_charp) path; 217 syscallarg(linux32_utimbufp_t) times; 218 } */ 219 struct timeval tv[2], *tvp; 220 struct linux32_utimbuf lut; 221 int error; 222 223 if (SCARG_P32(uap, times) != NULL) { 224 if ((error = copyin(SCARG_P32(uap, times), &lut, sizeof lut))) 225 return error; 226 227 tv[0].tv_sec = (long)lut.l_actime; 228 tv[0].tv_usec = 0; 229 tv[1].tv_sec = (long)lut.l_modtime; 230 tv[1].tv_usec = 0; 231 tvp = tv; 232 } else { 233 tvp = NULL; 234 } 235 236 return do_sys_utimes(l, NULL, SCARG_P32(uap, path), FOLLOW, 237 tvp, UIO_SYSSPACE); 238 } 239 240 void 241 native_to_linux32_timespec(struct linux32_timespec *ltp, 242 const struct timespec *ntp) 243 { 244 245 memset(ltp, 0, sizeof(*ltp)); 246 ltp->tv_sec = ntp->tv_sec; 247 ltp->tv_nsec = ntp->tv_nsec; 248 } 249 250 void 251 linux32_to_native_timespec(struct timespec *ntp, 252 const struct linux32_timespec *ltp) 253 { 254 255 memset(ntp, 0, sizeof(*ntp)); 256 ntp->tv_sec = ltp->tv_sec; 257 ntp->tv_nsec = ltp->tv_nsec; 258 } 259 260 void 261 native_to_linux32_itimerspec(struct linux32_itimerspec *litp, 262 const struct itimerspec *nitp) 263 { 264 memset(litp, 0, sizeof(*litp)); 265 native_to_linux32_timespec(&litp->it_interval, &nitp->it_interval); 266 native_to_linux32_timespec(&litp->it_value, &nitp->it_value); 267 } 268 269 void 270 linux32_to_native_itimerspec(struct itimerspec *nitp, 271 const struct linux32_itimerspec *litp) 272 { 273 memset(nitp, 0, sizeof(*nitp)); 274 linux32_to_native_timespec(&nitp->it_interval, &litp->it_interval); 275 linux32_to_native_timespec(&nitp->it_value, &litp->it_value); 276 } 277 278 int 279 linux32_sys_nanosleep(struct lwp *l, 280 const struct linux32_sys_nanosleep_args *uap, register_t *retval) 281 { 282 /* { 283 syscallarg(linux32_timespecp_t) rqtp; 284 syscallarg(linux32_timespecp_t) rmtp; 285 } */ 286 struct timespec rqts, rmts; 287 struct linux32_timespec lrqts, lrmts; 288 int error, error1; 289 290 error = copyin(SCARG_P32(uap, rqtp), &lrqts, sizeof(lrqts)); 291 if (error != 0) 292 return error; 293 linux32_to_native_timespec(&rqts, &lrqts); 294 295 error = nanosleep1(l, CLOCK_MONOTONIC, 0, &rqts, 296 SCARG_P32(uap, rmtp) ? &rmts : NULL); 297 if (SCARG_P32(uap, rmtp) == NULL || (error != 0 && error != EINTR)) 298 return error; 299 300 native_to_linux32_timespec(&lrmts, &rmts); 301 error1 = copyout(&lrmts, SCARG_P32(uap, rmtp), sizeof(lrmts)); 302 return error1 ? error1 : error; 303 } 304 305 int 306 linux32_sys_clock_settime(struct lwp *l, 307 const struct linux32_sys_clock_settime_args *uap, register_t *retval) 308 { 309 /* { 310 syscallarg(clockid_t) which; 311 syscallarg(linux32_timespecp_t) tp; 312 } */ 313 int error; 314 struct timespec ts; 315 struct linux32_timespec lts; 316 clockid_t id; 317 318 error = linux_to_native_clockid(&id, SCARG(uap, which)); 319 if (error != 0) 320 return error; 321 322 if ((error = copyin(SCARG_P32(uap, tp), <s, sizeof lts))) 323 return error; 324 325 linux32_to_native_timespec(&ts, <s); 326 return clock_settime1(l->l_proc, id, &ts, true); 327 } 328 329 int 330 linux32_sys_clock_gettime(struct lwp *l, 331 const struct linux32_sys_clock_gettime_args *uap, register_t *retval) 332 { 333 /* { 334 syscallarg(clockid_t) which; 335 syscallarg(linux32_timespecp_t) tp; 336 } */ 337 int error; 338 clockid_t id; 339 struct timespec ts; 340 struct linux32_timespec lts; 341 342 error = linux_to_native_clockid(&id, SCARG(uap, which)); 343 if (error != 0) 344 return error; 345 346 error = clock_gettime1(id, &ts); 347 if (error != 0) 348 return error; 349 350 native_to_linux32_timespec(<s, &ts); 351 return copyout(<s, SCARG_P32(uap, tp), sizeof lts); 352 } 353 354 int 355 linux32_sys_clock_getres(struct lwp *l, 356 const struct linux32_sys_clock_getres_args *uap, register_t *retval) 357 { 358 /* { 359 syscallarg(clockid_t) which; 360 syscallarg(linux32_timespecp_t) tp; 361 } */ 362 int error; 363 clockid_t id; 364 struct timespec ts; 365 struct linux32_timespec lts; 366 367 error = linux_to_native_clockid(&id, SCARG(uap, which)); 368 if (error != 0 || SCARG_P32(uap, tp) == NULL) 369 return error; 370 371 error = clock_getres1(id, &ts); 372 if (error != 0) 373 return error; 374 375 native_to_linux32_timespec(<s, &ts); 376 return copyout(<s, SCARG_P32(uap, tp), sizeof lts); 377 } 378 379 int 380 linux32_sys_clock_nanosleep(struct lwp *l, 381 const struct linux32_sys_clock_nanosleep_args *uap, register_t *retval) 382 { 383 /* { 384 syscallarg(clockid_t) which; 385 syscallarg(int) flags; 386 syscallarg(linux32_timespecp_t) rqtp; 387 syscallarg(linux32_timespecp_t) rmtp; 388 } */ 389 struct linux32_timespec lrqts, lrmts; 390 struct timespec rqts, rmts; 391 int error, error1, flags; 392 clockid_t id; 393 394 flags = SCARG(uap, flags) != 0 ? TIMER_ABSTIME : 0; 395 396 error = linux_to_native_clockid(&id, SCARG(uap, which)); 397 if (error != 0) 398 return error; 399 400 error = copyin(SCARG_P32(uap, rqtp), &lrqts, sizeof lrqts); 401 if (error != 0) 402 return error; 403 linux32_to_native_timespec(&rqts, &lrqts); 404 405 error = nanosleep1(l, id, flags, &rqts, 406 SCARG_P32(uap, rmtp) ? &rmts : NULL); 407 if (SCARG_P32(uap, rmtp) == NULL || (error != 0 && error != EINTR)) 408 return error; 409 410 native_to_linux32_timespec(&lrmts, &rmts); 411 error1 = copyout(&lrmts, SCARG_P32(uap, rmtp), sizeof lrmts); 412 return error1 ? error1 : error; 413 } 414 415 int 416 linux32_sys_timer_create(struct lwp *l, 417 const struct linux32_sys_timer_create_args *uap, register_t *retval) 418 { 419 /* { 420 syscallarg(clockid_t) clockid; 421 syscallarg(struct linux32_sigevent *) evp; 422 syscallarg(timer_t *) timerid; 423 } */ 424 clockid_t id; 425 int error; 426 427 error = linux_to_native_timer_create_clockid(&id, SCARG(uap, clockid)); 428 if (error == 0) { 429 error = timer_create1(SCARG(uap, timerid), id, 430 (void *)SCARG(uap, evp), linux32_sigevent_copyin, l); 431 } 432 433 return error; 434 } 435 436 int 437 linux32_sys_timer_settime(struct lwp *l, 438 const struct linux32_sys_timer_settime_args *uap, register_t *retval) 439 { 440 /* { 441 syscallarg(timer_t) timerid; 442 syscallarg(int) flags; 443 syscallarg(const struct linux32_itimerspec *) tim; 444 syscallarg(struct linux32_itimerspec *) otim; 445 } */ 446 struct itimerspec value, ovalue, *ovp = NULL; 447 struct linux32_itimerspec tim, otim; 448 int error; 449 450 error = copyin(SCARG(uap, tim), &tim, sizeof(tim)); 451 if (error) { 452 return error; 453 } 454 linux32_to_native_itimerspec(&value, &tim); 455 456 if (SCARG(uap, otim)) { 457 ovp = &ovalue; 458 } 459 460 if (SCARG(uap, flags) & ~TIMER_ABSTIME) { 461 return EINVAL; 462 } 463 464 error = dotimer_settime(SCARG(uap, timerid), &value, ovp, 465 SCARG(uap, flags), l->l_proc); 466 if (error) { 467 return error; 468 } 469 470 if (ovp) { 471 native_to_linux32_itimerspec(&otim, ovp); 472 error = copyout(&otim, SCARG(uap, otim), sizeof(otim)); 473 } 474 475 return error; 476 } 477 478 int 479 linux32_sys_timer_gettime(struct lwp *l, 480 const struct linux32_sys_timer_gettime_args *uap, register_t *retval) 481 { 482 /* { 483 syscallarg(timer_t) timerid; 484 syscallarg(struct linux32_itimerspec *) tim; 485 } */ 486 struct itimerspec its; 487 struct linux32_itimerspec lits; 488 int error; 489 490 error = dotimer_gettime(SCARG(uap, timerid), l->l_proc, &its); 491 if (error == 0) { 492 native_to_linux32_itimerspec(&lits, &its); 493 error = copyout(&lits, SCARG(uap, tim), sizeof(lits)); 494 } 495 496 return error; 497 } 498 499 /* 500 * timer_gettoverrun(2) and timer_delete(2) are handled directly 501 * by the native calls. 502 */ 503 504 /* 505 * timerfd_create() is handled by the standard COMPAT_LINUX call. 506 */ 507 508 int 509 linux32_sys_timerfd_gettime(struct lwp *l, 510 const struct linux32_sys_timerfd_gettime_args *uap, register_t *retval) 511 { 512 /* { 513 syscallarg(int) fd; 514 syscallarg(struct linux32_itimerspec *) tim; 515 } */ 516 struct itimerspec its; 517 struct linux32_itimerspec lits; 518 int error; 519 520 error = do_timerfd_gettime(l, SCARG(uap, fd), &its, retval); 521 if (error == 0) { 522 native_to_linux32_itimerspec(&lits, &its); 523 error = copyout(&lits, SCARG(uap, tim), sizeof(lits)); 524 } 525 526 return error; 527 } 528 529 int 530 linux32_sys_timerfd_settime(struct lwp *l, 531 const struct linux32_sys_timerfd_settime_args *uap, register_t *retval) 532 { 533 /* { 534 syscallarg(int) fd; 535 syscallarg(int) flags; 536 syscallarg(const struct linux32_itimerspec *) tim; 537 syscallarg(struct linux32_itimerspec *) otim; 538 } */ 539 struct itimerspec nits, oits, *oitsp = NULL; 540 struct linux32_itimerspec lits; 541 int nflags; 542 int error; 543 544 error = copyin(SCARG(uap, tim), &lits, sizeof(lits)); 545 if (error) { 546 return error; 547 } 548 linux32_to_native_itimerspec(&nits, &lits); 549 550 error = linux_to_native_timerfd_settime_flags(&nflags, 551 SCARG(uap, flags)); 552 if (error) { 553 return error; 554 } 555 556 if (SCARG(uap, otim)) { 557 oitsp = &oits; 558 } 559 560 error = do_timerfd_settime(l, SCARG(uap, fd), nflags, 561 &nits, oitsp, retval); 562 if (error == 0 && oitsp != NULL) { 563 native_to_linux32_itimerspec(&lits, oitsp); 564 error = copyout(&lits, SCARG(uap, otim), sizeof(lits)); 565 } 566 567 return error; 568 } 569