linux-user: respect timezone for settimeofday

The settimeofday syscall accepts a tz argument indicating the desired
timezone to the kernel. QEMU previously ignored any argument provided
by the target program & always passed NULL to the kernel. Instead,
translate the argument & pass along the data userland provided.

Although this argument is described by the settimeofday man page as
obsolete, it is used by systemd as of version 213.

Signed-off-by: Paul Burton <paul@archlinuxmips.org>
Signed-off-by: Riku Voipio <riku.voipio@linaro.org>
This commit is contained in:
Paul Burton 2014-06-22 11:25:40 +01:00 committed by Riku Voipio
parent fd76783243
commit ef4467e911
2 changed files with 33 additions and 1 deletions

View File

@ -935,6 +935,23 @@ static inline abi_long copy_to_user_timeval(abi_ulong target_tv_addr,
return 0; return 0;
} }
static inline abi_long copy_from_user_timezone(struct timezone *tz,
abi_ulong target_tz_addr)
{
struct target_timezone *target_tz;
if (!lock_user_struct(VERIFY_READ, target_tz, target_tz_addr, 1)) {
return -TARGET_EFAULT;
}
__get_user(tz->tz_minuteswest, &target_tz->tz_minuteswest);
__get_user(tz->tz_dsttime, &target_tz->tz_dsttime);
unlock_user_struct(target_tz, target_tz_addr, 0);
return 0;
}
#if defined(TARGET_NR_mq_open) && defined(__NR_mq_open) #if defined(TARGET_NR_mq_open) && defined(__NR_mq_open)
#include <mqueue.h> #include <mqueue.h>
@ -6385,9 +6402,19 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
case TARGET_NR_settimeofday: case TARGET_NR_settimeofday:
{ {
struct timeval tv; struct timeval tv;
struct timezone tz, *ptz = NULL;
if (copy_from_user_timeval(&tv, arg1)) if (copy_from_user_timeval(&tv, arg1))
goto efault; goto efault;
ret = get_errno(settimeofday(&tv, NULL));
if (arg2) {
if (copy_from_user_timezone(&tz, arg2)) {
goto efault;
}
ptz = &tz;
}
ret = get_errno(settimeofday(&tv, ptz));
} }
break; break;
#if defined(TARGET_NR_select) #if defined(TARGET_NR_select)

View File

@ -165,6 +165,11 @@ struct target_timespec {
abi_long tv_nsec; abi_long tv_nsec;
}; };
struct target_timezone {
abi_int tz_minuteswest;
abi_int tz_dsttime;
};
struct target_itimerval { struct target_itimerval {
struct target_timeval it_interval; struct target_timeval it_interval;
struct target_timeval it_value; struct target_timeval it_value;