-
发生时间:2022-10-08
-
问题描述:
- 同事 A 在做功能测试时,发现 IMU 测试失败,设备端返回失败信息:
{"name": "imu_test", "code": 1, "message": "imu calib failed"}。 - 但是 ssh 登录设备后,执行
run.sh imu test,设备端可以返回成功信息:{"name": "imu_test", "code": 0, "message": "imu_test is success"}
- 同事 A 在做功能测试时,发现 IMU 测试失败,设备端返回失败信息:
-
问题类别:软件调试
-
原因分析:
- 设备端能够返回失败信息,说明网络连接是正确的。那为什么 ssh 登录后执行命令可以成功,而上位机执行命令却会失败呢?
- 一番思索过后,同事 A 尝试直接在终端执行上位机代码里的完整命令,得到以下结果:
$ ssh -i id_rsa.pub -o "StrictHostKeyChecking no" root@host "run.sh imu test" ./bin/imu_test: error while loading shared libraries: libdds_api.so: cannot open shared object file: No such file or directory {"name": "imu_test", "code": 1, "message": "imu calib failed"}- 根据报错信息,已经能够确定是嵌入式软件的问题了——执行
imu_test文件时由于无法加载动态链接库而报错。但为什么 ssh 登录后再执行命令就不会报错呢? - 经过网上搜索,在 Stack Exchange 的一个回答 中找到了答案:
- ssh 登录远端设备的 Linux 系统时,会启动 bash 进程,并加载一些初始化脚本,比如
~/.bashrc或/etc/profile等。 - ssh 不登录远端设备,直接连接远端设备执行命令时,不会启动 bash 进程,也不会加载那些初始化脚本。
- 设备系统里的
imu_test程序所依赖的动态链接库libdds_api.so的路径,是在/etc/profile脚本中被添加到环境变量PATH的; 但由于我们不登录设备,所以/etc/profile没有被加载,从而导致imu_test程序找不到动态链接库而报错。
- ssh 登录远端设备的 Linux 系统时,会启动 bash 进程,并加载一些初始化脚本,比如
-
解决方案:
- 根据嵌入式同事 B 的建议,可以将上位机要执行的命令改为
. /etc/profile; run.sh imu test。 - 但这显然对用户并不友好,不是种优雅的解决方案。嵌入式命令本身应该处理好环境变量加载,不应该把这个细节暴露给用户。
- 经过沟通,嵌入式同事同意修改嵌入式软件,在
run.sh脚本中增加初始化环境变量的操作。这样上位机不需进行修改。
- 根据嵌入式同事 B 的建议,可以将上位机要执行的命令改为
-
实施结果:
- 按照嵌入式组的建议临时修改命令后,上位机可以执行成功。
- 最终的解决方案,需要等嵌入式同事发布版本后才能验证。
-
经验总结:
- 目前上位机软件采用 ssh 连接远端主机直接执行命令的方案,因此有必要理解它与 ssh 登录后再执行命令的差异:前者不会加载初始化脚本,后者会。
- 上位机的日志打印需要优化,要能够把关键的报错信息报告出来。(这里上位机将设备端的关键报错信息屏蔽掉了,否则可以更快地定位到问题原因。)