0 前言
有需求需要在 openeuler 的操作系统上测试一个 C 程序,做了一个简化版的程序,程序很简单,循环读取一个文件并打印文件内容,在程序执行过程中使用 echo 手动向文件中追加内容,程序要能读取到,效果如下:
测试程序代码如下:
#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
int main(int argc, char **argv)
{
FILE *f = fopen("./Syslog.log", "rb");
if (f == NULL) return 1;
char buffer[1024] = {0};
size_t len = 0;
while(1)
{
len = fread(buffer, 1, sizeof(buffer), f);
if (len > 0)
{
buffer[len] = '\0';
printf("read:%s\n",buffer);
}
else
{
printf("noread\n");
}
sleep(2);
}
return 0;
}
在 Rhel-7.5 上测试一切正常,开始在 openeuler 上进行测试,结果发现后续追加的内容没有输出:
1 故障排查
考虑到影响程序执行结果的几个因素:程序本身,内核版本,gcc 版本,glibc 版本。
程序本身应该是没问题的,内核版本一般对 C 语言程序的影响也不会很大,还是优先看 gcc 版本和 glibc 版本。
按照思路进行了一些测试,测试结果:
- 可行:
- centos7.5(gcc-4.8.5,kernel-3.10,glibc<=2.28)
- centos7.5(gcc-7.3.0,kernel-3.10,glibc<=2.28)
- centos7.5(gcc-7.3.0,kernel-5.12,glibc<=2.28)
- 不可行:
- isoft-server-6.0(gcc-7.3.0,4.19.90,glibc>=2.28)
- centos8(gcc-8.4.0,kernel-4.18.0,glibc>=2.28)
- openeuler-20.03-LTS-SP1(gcc-7.3.0,kernel-4.19.90,glibc>=2.28)
按照测试结果,似乎 gcc 版本和内核版本对程序没什么影响,大概率应该是 glibc 版本导致的。由于程序很简单,只是以 rb 方式 fopen 打开文件循环读取文件内容,求证 (google) 起来也比较轻松,很快就找到了问题在哪:glibc 2.28 修复了 fread 的行为
这个 glibc 的 bug 是 05 年提的,到 18 年才修复,也是担心 break 之前大量的代码。https://sourceware.org/bugzilla/show_bug.cgi?id=1190
现在再修改一下代码:
#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
int main(int argc, char **argv)
{
FILE *f = fopen("./Syslog.log", "rb");
if (f == NULL) return 1;
char buffer[1024] = {0};
size_t len = 0;
while(1)
{
len = fread(buffer, 1, sizeof(buffer), f);
if (len > 0)
{
buffer[len] = '\0';
printf("read:%s\n",buffer);
}
else
{
if (feof (f)) {
printf("Read error, clear error flag to retry...\n");
clearerr (f);
}
}
sleep(2);
}
return 0;
}
添加了一块清除标记的片段,在 glibc>=2.28 的系统上程序也可以正常运行了
以上