On 5/18/2026 2:27 PM, Warner Losh wrote:
> Add time-related system call shims: utimes, lutimes, futimes,
> futimesat, ktimer_create, ktimer_delete, ktimer_settime, and
> ktimer_gettime.
>
> Signed-off-by: Stacey Son <[email protected]>
> Signed-off-by: Mikaƫl Urankar <[email protected]>
> Signed-off-by: Kyle Evans <[email protected]>
> Signed-off-by: Warner Losh <[email protected]>
> Assisted-by: Claude Opus 4.6 (1M context)
> ---
> bsd-user/freebsd/os-time.h | 210
> +++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 210 insertions(+)
>
> diff --git a/bsd-user/freebsd/os-time.h b/bsd-user/freebsd/os-time.h
> index 16b71e6234..05fa043442 100644
> --- a/bsd-user/freebsd/os-time.h
> +++ b/bsd-user/freebsd/os-time.h
> @@ -217,5 +217,215 @@ static inline abi_long do_freebsd_ntp_gettime(abi_ulong
> target_ntv_addr)
> }
>
>
> +/* utimes(2) */
> +static inline abi_long do_freebsd_utimes(abi_long arg1, abi_long arg2)
> +{
> + abi_long ret;
> + void *p;
> + struct timeval *tvp, tv[2];
> +
> + if (arg2 != 0) {
> + if (t2h_freebsd_timeval(&tv[0], arg2) ||
> + t2h_freebsd_timeval(&tv[1], arg2 +
> + sizeof(struct target_freebsd_timeval))) {
> + return -TARGET_EFAULT;
> + }
> + tvp = tv;
> + } else {
> + tvp = NULL;
> + }
> + p = lock_user_string(arg1);
> + if (p == NULL) {
> + return -TARGET_EFAULT;
> + }
> + ret = get_errno(utimes(p, tvp));
> + unlock_user(p, arg1, 0);
> +
> + return ret;
> +}
> +
> +/* lutimes(2) */
> +static inline abi_long do_freebsd_lutimes(abi_long arg1, abi_long arg2)
> +{
> + abi_long ret;
> + void *p;
> + struct timeval *tvp, tv[2];
> +
> + if (arg2 != 0) {
> + if (t2h_freebsd_timeval(&tv[0], arg2) ||
> + t2h_freebsd_timeval(&tv[1], arg2 +
> + sizeof(struct target_freebsd_timeval))) {
> + return -TARGET_EFAULT;
> + }
> + tvp = tv;
> + } else {
> + tvp = NULL;
> + }
> + p = lock_user_string(arg1);
> + if (p == NULL) {
> + return -TARGET_EFAULT;
> + }
> + ret = get_errno(lutimes(p, tvp));
> + unlock_user(p, arg1, 0);
> +
> + return ret;
> +}
> +
> +/* futimes(2) */
> +static inline abi_long do_freebsd_futimes(abi_long arg1, abi_long arg2)
> +{
> + struct timeval *tvp, tv[2];
> +
> + if (arg2 != 0) {
> + if (t2h_freebsd_timeval(&tv[0], arg2) ||
> + t2h_freebsd_timeval(&tv[1], arg2 +
> + sizeof(struct target_freebsd_timeval))) {
> + return -TARGET_EFAULT;
> + }
> + tvp = tv;
> + } else {
> + tvp = NULL;
> + }
> +
> + return get_errno(futimes(arg1, tvp));
> +}
> +
> +/* futimesat(2) */
> +static inline abi_long do_freebsd_futimesat(abi_long arg1, abi_long arg2,
> + abi_long arg3)
> +{
> + abi_long ret;
> + void *p;
> + struct timeval *tvp, tv[2];
> +
> + if (arg3 != 0) {
> + if (t2h_freebsd_timeval(&tv[0], arg3) ||
> + t2h_freebsd_timeval(&tv[1], arg3 +
> + sizeof(struct target_freebsd_timeval))) {
> + return -TARGET_EFAULT;
> + }
> + tvp = tv;
> + } else {
> + tvp = NULL;
> + }
> +
> + p = lock_user_string(arg2);
> + if (p == NULL) {
> + return -TARGET_EFAULT;
> + }
> + ret = get_errno(futimesat(arg1, p, tvp));
> + unlock_user(p, arg2, 0);
> +
> + return ret;
> +}
> +
The functions above are quite duplicated.
We could factor the first part at least, setting tvp.
The lock_user_string part can be replaced with LOCK_PATH.
> +/* timer_create(2) */
> +static inline abi_long do_freebsd_ktimer_create(abi_long arg1, abi_long arg2,
> + abi_long arg3)
> +{
> + /* args: clockid_t clockid, struct sigevent *sevp, int *timerid */
> + abi_long ret;
> +
> + struct sigevent host_sevp = { 0 }, *phost_sevp = NULL;
> +
> + int clkid = arg1;
> + int timer_index = next_free_host_timer();
> +
> + if (timer_index < 0) {
> + ret = -TARGET_EAGAIN;
> + } else {
> + int *phtimer = g_posix_timers + timer_index;
> +
> + if (arg2) {
> + phost_sevp = &host_sevp;
> + ret = target_to_host_sigevent(phost_sevp, arg2);
> + if (ret != 0) {
> + return -TARGET_EFAULT;
> + }
> + }
> +
> + ret = get_errno(__sys_ktimer_create(clkid, phost_sevp, phtimer));
> + if (ret) {
> + phtimer = NULL;
> + } else {
> + if (put_user(TIMER_MAGIC | timer_index, arg3, int)) {
> + ret = -TARGET_EFAULT;
> + }
> + }
> + }
> + return ret;
> +}
> +
> +/* timer_delete(2) */
> +static inline abi_long do_freebsd_ktimer_delete(abi_long arg1)
> +{
> + /* args: int timerid */
> + abi_long ret;
> + int timerid = get_timer_id(arg1);
> +
> + if (timerid < 0) {
> + ret = timerid;
> + } else {
> + int htimer = g_posix_timers[timerid];
> + ret = get_errno(__sys_ktimer_delete(htimer));
> + g_posix_timers[timerid] = 0;
> + }
> + return ret;
> +}
> +
> +/* timer_settime(2) */
> +static inline abi_long do_freebsd_ktimer_settime(abi_long arg1, abi_long
> arg2,
> + abi_long arg3, abi_long arg4)
> +{
> + /*
> + * args: int timerid, int flags, const struct itimerspec *new_value,
> + * struct itimerspec * old_value
> + */
> + abi_long ret;
> + int timerid = get_timer_id(arg1);
> +
> + if (timerid < 0) {
> + ret = timerid;
> + } else if (arg3 == 0) {
> + ret = -TARGET_EINVAL;
> + } else {
> + int htimer = g_posix_timers[timerid];
> + struct itimerspec hspec_new = {{0},}, hspec_old = {{0},};
> +
> + if (target_to_host_itimerspec(&hspec_new, arg3)) {
> + return -TARGET_EFAULT;
> + }
> + ret = get_errno(
> + __sys_ktimer_settime(htimer, arg2, &hspec_new, &hspec_old));
> + if (arg4 && host_to_target_itimerspec(arg4, &hspec_old)) {
> + return -TARGET_EFAULT;
> + }
> + }
> + return ret;
> +}
> +
> +/* timer_gettime(2) */
> +static inline abi_long do_freebsd_ktimer_gettime(abi_long arg1, abi_long
> arg2)
> +{
> + /* args: int timerid, struct itimerspec *curr_value */
> + abi_long ret;
> + int timerid = get_timer_id(arg1);
> +
> + if (timerid < 0) {
> + ret = timerid;
> + } else if (!arg2) {
> + ret = -TARGET_EFAULT;
> + } else {
> + int htimer = g_posix_timers[timerid];
> + struct itimerspec hspec;
> + ret = get_errno(__sys_ktimer_gettime(htimer, &hspec));
> +
> + if (host_to_target_itimerspec(arg2, &hspec)) {
> + ret = -TARGET_EFAULT;
> + }
> + }
> + return ret;
> +}
> +
>
> #endif /* FREEBSD_OS_TIME_H */
>