问题描述
我注意到在 Ubuntu 16 上使用 pyinstaller 编译的子进程的一些奇怪行为,它在 ubuntu 16 上运行良好,但在 SuSe12 SP4 上失败。 想知道是否有人可以透露一些信息并告诉我我错过了哪些微不足道的信息?
import os,sys,subprocess
def get_all_outputs(cmd):
proc = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=True,universal_newlines=True)
std_out,std_err = proc.communicate()
return proc.returncode,std_out,std_err
cmd = raw_input('CMD:')
print get_all_outputs(cmd)
这与 Ubuntu 16 上的普通 python 文件或 pyinstaller 文件一样正常工作...
root@ubuntu16:~/cert/dist# ./retcode
CMD:openssl x509 -in /root/cert_new/mycert.cer
(0,'-----BEGIN CERTIFICATE-----\nMIIFmTCCBIGgAwIBAgITQwAAAGqQd2QfUVAHwQABAAAAajANBgkqhkiG9w0BAQsF\nADBGMRUwEwYKCZImiZPyLGQBGRYFbG9jYWwxFjAUBgoJkiaJk/IsZAEZFgZhdmFt\nYXIxFTATBgNVBAMTDGF2YW1hci1EQy1DQTAeFw0yMDEyMjkxMjAyNDhaFw0yMjEy\nMjkxMjAyNDhaMHYxCzAJBgNVBAYTAkFVMQwwCgYDVQQIEwNOU1cxDzANBgNVBAcT\nBlN5ZG5leTERMA8GA1UEChMIRGVsbCBFTUmxeDAOBgNVBAsTB1N1cHBvcnQxIzAh\nBgNVBAMTGm5lbzEtc3lWwMBMA0GCSqGSIb3DQEBCwUAA4IBAQBjH2ubfVxCC42LVURTZUog/vJZ\nctAEBDUW3VaeRCMWD3dvB0loc0llGaXQVafh0Q2cW8Uy0qMexpcUUwp8OjbtwcBo\n3TkEApBABgX/JC9P+BXCK3NiYze1SAjsgcdeZaS0t3HLlgwc8vZSotXco+mwZM9S\nTtrU1RqU4kkqhR5+wjPT8ffLFyZNBCdDKUOF3wxsr/0uUpfm9Bnt3DahoN4dwHvI\nOvi1DSV6ob84VXKT3ehMqt27ZW5dtLQdpzINADHdhlitTAUAO+CdO3LltqobQbf8\niK8fmnmSWHVF8vA3mmIfANLILZ6XKASgo2D2RU0jPjbkWi3nPY+2aRPGS1wJ\n-----END CERTIFICATE-----\n','')
但是当我将编译后的文件 scp 到 SuSe12SP4 时,我从来没有得到输出,而是不断抛出错误代码 127 以及如下有趣的消息:
neo_suse12sp4:~/pp # ./retcode
CMD:/usr/local/ssl/bin/openssl x509 -in /root/pp/mycert.cer
(127,'','/bin/sh: /tmp/_MEIOqKDWs/libreadline.so.6: no version information available (required by /bin/sh)\n/usr/local/ssl/bin/openssl: relocation error: /usr/local/ssl/bin/openssl: symbol i2d_DHxparams,version OPENSSL_1.0.0 not defined in file libcrypto.so.1.0.0 with link time reference\n')
我什至尝试使用 openssl 和证书的完整路径,但它根本不起作用。
neo_suse12sp4:~/pp # which openssl
/usr/local/ssl/bin/openssl
如果有人可以在这里帮助我,我将不胜感激。我会非常感谢你的。谷歌和现有关于 SO 的文章似乎无法解决这个问题。
解决方法
好吧,看来是我自己找到了出路。这看起来像是在 SuSe 12 SP4 系统上找到的 openssl 可执行文件与从 Ubuntu 16 构建系统收集的 libcrypto.so 库不兼容(并且现在在冻结的应用程序及其子进程中覆盖系统一)。
我们需要修改子进程的 LD_LIBRARY_PATH 以使系统的库优先于捆绑的库。
百万感谢 github 上的 @Rok Mandeljc (rokm) 帮助我解决这个问题。把它张贴在这里以防其他人敲他们的头会很容易地解决这个问题。
解决方案:
###Add the following code to your existing code
env = dict(os.environ) # make a copy of the environment
lp_key = 'LD_LIBRARY_PATH' # for GNU/Linux and *BSD.
lp_orig = env.get(lp_key + '_ORIG')
if lp_orig is not None:
env[lp_key] = lp_orig # restore the original,unmodified value
else:
# This happens when LD_LIBRARY_PATH was not set.
# Remove the env var as a last resort:
env.pop(lp_key,None)
接下来,将 env 变量添加到 subprocess Popen 命令中
def run_command(cmd): #returns the output of a program
proc = subprocess.Popen(cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE,stdin=subprocess.PIPE,shell=True,universal_newlines=True,env=env)
std_out,std_err = proc.communicate()
return std_out