我正在尝试从GPG加密的文件中实现MySQL数据库还原。
以下内容效果很好:
my $status = system(
"gpg --pinentry-mode loopback --passphrase $passphrase --decrypt $my_encrypted_backup_file"
. " | "
. "mysql --host=myhost --user=myuser --password=mysecret mydatabase"
);
假定没有错误情况。
但是,如果在第一个过程中发生错误情况(例如不正确的$ passphrase),则$status == 0
会错误地指示成功。我了解这是因为状态是从第二个进程mysql进程返回的。
是否有一种通用的方法,使用system()
从所有管道连接的进程中获取状态,或者如果任何一个这样的进程失败,以某种方式检测到错误?< / p>
顺便说一句,我自己测试了gpg
(没有将其输出通过管道传递到mysql中),当输入了错误的$ passphrase时,它的确返回了错误代码。
一种解决方法可能是mysql
中的某些选项标志,当它从gpg
接收不到任何内容时返回错误。另一个解决方法是破坏进程并使用某种tmp文件。但是,我希望有一个更通用的解决方案。谢谢!
答案 0 :(得分:3)
如果您需要类似的精细控制,请不要使用外壳程序。
可以使用DBI和DBD::mysql库替换对mysql
的调用。 gpg
可以替换为Crypt::GPG。
如果无法实现,请使用open
and its |-
and -|
modes自己进行管道传输。
open(
my $gpg_out,
"-|",
"gpg --pinentry-mode loopback --passphrase $passphrase --decrypt $my_encrypted_backup_file"
) or die "Can't run gpg: $!";
open(
my $mysql_in,
"|-",
"mysql --host=myhost --user=myuser --password=mysecret mydatabase"
) or die "Can't run mysql: $!";
while(my $line = <$gpg_out>) {
print $mysql_in $line;
}
close $gpg_out;
close $mysql_in;
答案 1 :(得分:2)
感谢@Schwern建议IPC :: Run。这是一个经过测试的有效解决方案:
use IPC::Run qw( run );
my $gpg = [
"gpg",
"--pinentry-mode=loopback",
"--passphrase=$my_passphrase",
"--decrypt",
$my_backupfilepath
];
my $mysql = [
"mysql",
"--host=$mysql_host"
"--user=$mysql_user"
"--password=$mysql_pass"
$mysql_dbname
];
run( $gpg, '|', $mysql ) || die "Error";
我仍然无法捕获详细的错误消息,而且我仍然看到来自gpg和mysql的过多聊天输出。...但是,我已经花了很多时间与Perl和GPG战斗!改进令人欣慰。
与核心问题无关,但对于按原样使用此配方的任何人……要使GPG 2.1+可以通过命令行接受密码短语并且不对其进行缓存,则必须将以下内容添加到gpg-agent.conf
中:
allow-loopback-pinentry
default-cache-ttl 1
max-cache-ttl 1