我有一个嵌入式Linux,对所有系统文件夹(包括/etc)都有写锁,并且只有一个文件夹是可自由写入的,称为
/writable
。 /etc/localtime
是指向 /writable/localtime
的符号链接。
我的(测试)应用程序通过将不同的时区文件复制到
/writable/localtime
的位置来更改时区,然后调用 tzset()
并尝试读取 tzname
。
但是,无论我复制时区信息还是将文件转换为指向其他地方的符号链接,
tzset
都不会更改tzname
,也不会更新偏移量(意味着使用localtime
会产生相同的结果)。
只有重新启动应用程序后,新时区才会生效。
为什么?
结合使用
setenv
、unsetenv
和 tzset
来强制其完成其工作。
(最小)示例代码:
#include <time.h>
int main(int, const char **)
{
//Install new timezone file
setenv("TZ", "UTC", 1);
tzset();
unsetenv("TZ");
tzset();
//Format time to check it worked.
}
这个问题让我困惑了很长一段时间,这就是为什么我想与社区分享我的发现。
在 glibc 的源代码中,我发现
tzset
在执行实际工作之前执行两项检查。TZ
)。strcmp
),tzset 就会中止。
但这里的情况并非如此,因为根本没有设置环境变量。
第二次检查,在确保上次调用期间未设置
TZ
后,通过评估其元数据(inode 编号、修改日期等)来比较时区文件 (/etc/localtime
) 是否已更改。
这就是上述场景中的问题所在:您不更新
/etc/localtime
,而是更新它指向的位置,而 tzset
看起来并不那么远。
因此,通过使用上述逻辑,tzset
推断,没有什么可做的。
通过设置环境变量并调用
tzset
,您可以更新其内部缓冲区。tzset
现在知道您正在使用自定义时区字符串而不是文件。UTC
) 与当前时区值 (NULL
) 不同,第二次检查也返回 false,因为 the environment variable had been used before
,使其完全跳过文件检查。
所有这些仅适用于您无法直接操作
/etc/localtime
,但需要操作它指向的位置。否则 tzset
将检测到“文件已更改”,如上所述。