一次Linux开发机Debug的记录

近期在鹅厂实习做后端,使用的是公司自研的C++框架,开发自测属于常说的“远程开发”,需要部署到开发机上测试。也就是说,每次改完代码想要调试,需要同步代码到开发机上编译部署,这样有一个好处就是迫使自己在运行代码之前做更充分的考虑,争取一次完成,在这样的情况下,感觉自己在Linux系统上定位和分析问题的能力有了一些提高,这次选出一个与配置和系统函数相关的Bug,在记录一下分析问题的思路(完全没有泄露任何业务)。

背景

因为一些原因,需要大范围重写项目CGI框架所用的配置文件。每个CGI运行时都会加载所需要的配置,观察log会发现,接口运行时会首先检查硬盘上的配置文件是否有更新,如果有则从文件加载配置,如果没有就直接从缓存中取配置,毕竟缓存读取比文件IO快多了。改完配置文件后,发现怎么跑都跑不同,一直挂在Log上,这种不出现在业务代码上的bug一直都是我觉得最难缠的。

看日志,走源码

image-20180809205750517

报的错误信息一头雾水,执行的还是框架的运行基础代码,那就进入报错的代码部分看一下

image-20180809205847442

可以看到报错部分的代码执行的正是上面所说的检查文件是否更新,可以看到这里调用了是一个Linux系统C函数stat,那就再往下一层,看一下这个函数的具体信息,尤其是错误码,在Linux下执行man 2 stat查看Linux手册说明,下面是错误码部分:

image-20180809205952636

梳理需要的关键信息:

  • 对于stat()lstat(),需要获得指向目标文件整个路径的执行权限
  • 获取的文件信息保存在结构体stat中,其中有errorlog中的获取失败的mtime,就是指文件修改时间
  • 错误返回中,我们看到了几种情况,但是居然没有和具体的errno对应起来,看来需要排除一下了

通过排除做选择

首先文件权限没开执行权限的可能性很大,检查了一下,开得是777,不是权限的问题。

再阅读一下几个错误的描述,文件描述符错误、文件有符号链接问题,存取被拒绝,好像都不是我们会遇到的问题。

相对的其中ENOTDIR的描述就很有趣:文件前缀的路径存在但不是一个真正的路径。这个时候去配置文件夹目录前执行ll,发现配置文件路径是个软链接,会不会就是因为这个函数需要执行在真实路径上的文件而非软链接呢?

image-20180809210014889

尝试修改配置文件路径为真实路径,配置文件正常加载,Debug完成~

总结

  • 通过这种自测方式,改掉了之前没有目的性的尝试的解决Bug的方式,能更加主动去思考
  • 要做errorlog刨根问底,即使最终指向的代码不是业务代码
  • 要对项目运行加载和环境了解更多,确保地底层知识的充足。

补充

之前对于Linux的软硬链接就有点疑问,这次就记录清楚。

Linux通过ln命令来创建软/硬链接,也就是为一个文件在另外一个位置建立一个同步的链接,通常的用法是

1
ln -s 源文件 目标文件(即链接)

-s是最常用的参数,它是指软链接,它只会在指定的目标位置上生成一个同步的镜像,并不会占用磁盘空间。硬链接就是不带s参数,它在目标位置生成一个与源文件大小相同的文件。不过硬链接有限制,不能给目录建立硬链接,且只有root才有简历硬链接的权限。

软链接:也叫做“符号链接”,软链接文件有类似于Windows的快捷方式。它实际上是一个特殊的文件。在符号连接中,文件实际上是一个文本文件,其中包含的有另一文件的位置信息。

硬链接:硬连接指通过索引节点来进行连接。在Linux的文件系统中,保存在磁盘分区中的文件不管是什么类型都给它分配一个编号,称为索引节点号(Inode Index)。在Linux中,多个文件名指向同一索引节点是存在的。一般这种连接就是硬连接。硬连接的作用是允许一个文件拥有多个有效路径名,这样用户就可以建立硬连接到重要文件,以防止“误删”的功能。其原因如上所述,因为对应该目录的索引节点有一个以上的连接。只删除一个连接并不影响索引节点本身和其它的连接,只有当最后一个连接被删除后,文件的数据块及目录的连接才会被释放。也就是说,文件真正删除的条件是与之相关的所有硬连接文件均被删除。