Gpg

抑制 GPG“從文件描述符 0 讀取密碼”消息

  • March 26, 2012

簡單地說,我怎樣才能讓 GPG 不列印該消息?以下是我正在使用的命令:

echo "test input" > test.in
echo "test" | gpg -q -c --passphrase-fd 0 --output test.enc --yes --force-mdc test.in
echo "test" | gpg -q -d --passphrase-fd 0 test.enc > test.out

並執行它:

$ echo "test input" > test.in 
$ echo "test" | gpg -q -c --passphrase-fd 0 --output test.enc --yes --force-mdc test.in
Reading passphrase from file descriptor 0    
$ echo "test" | gpg -q -d --passphrase-fd 0 test.enc > test.out
Reading passphrase from file descriptor 0

**編輯:**重定向標準錯誤似乎不起作用

$ echo "test" | gpg -q -c --passphrase-fd 0 --output test.enc --yes --force-mdc test.in 2> /dev/null
Reading passphrase from file descriptor 0    

查看正在發生的事情的一種方法是跟踪所涉及的系統呼叫。執行此操作的實用程序因平台而異。在 Solaris 上,您將使用truss。在 Linux 上(如我的範例中),您將使用strace


為了跟踪,我們將使用的命令更改為:

echo "test" | gpg -q -c --passphrase-fd 0 --output test.enc --yes --force-mdc test.in 2> /dev/null

到:

echo "test" | strace gpg -q -c --passphrase-fd 0 --output test.enc --yes --force-mdc test.in 2>trace_output.txt.


有趣的第一件事(如果有點無關的話)是 gpg 在從標準輸入獲取輸入密碼時重複單字節讀取。這有時是程式碼效率低下的標誌——但在這種情況下,這可能沒什麼大不了的:

read(0, "t", 1)                         = 1
read(0, "e", 1)                         = 1
read(0, "s", 1)                         = 1
read(0, "t", 1)                         = 1
read(0, "\n", 1)                        = 1

關於日誌消息輸出的更相關的東西都在這裡:

open("/dev/tty", O_RDWR)                = 3
fstat(3, {st_mode=S_IFCHR|0666, st_rdev=makedev(5, 0), ...}) = 0
ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, {B9600 opost isig icanon echo ...}) = 0
write(3, "Reading passphrase from file des"..., 45) = 45
write(3, "\10\10\10   \n", 7)           = 7

這就是我們在退出之前聽到的關於文件描述符 3 的全部資訊(它沒有明確關閉)。

依次查看其中的每一個:

  • open("/dev/tty", O_RDWR) = 3

這將打開文件 /dev/tty,用於讀取和寫入。返回值(一個新的文件描述符供以後使用)是 3。

/dev/tty 是目前控制終端的同義詞。您可以通過執行查看此特殊文件有效引用的設備$ tty

  • fstat(3, {st_mode=S_IFCHR|0666, st_rdev=makedev(5, 0), ...}) = 0

gpg 使用它來查找剛剛使用文件描述符 3 打開的文件。大括號中的內容是返回的內容(填充的 struct stat,其中 5, 0 表示這是一個特別特殊的文件)。

  • ioctl(3, SNDCTL_TMR_TIMEBASE or TCGETS, {B9600 opost isig icanon echo ...}) = 0

這是在輸出之前操縱控制終端的屬性。

  • write(3, "Reading passphrase from file des"..., 45) = 45

write(3, "\10\10\10 \n", 7) = 7

這些更直接。gpg 成功地將該文本(其中一些在 strace 輸出中縮寫)寫入終端。


所以 - 這就是你的答案.. gpg 正在將此日誌消息直接寫入 /dev/tty(控制終端的同義詞),因此您將無法以與 stdout 或 stderr 相同的方式重定向它。

辦法解決這個問題。您可以在執行 gpg 之前斷開控制終端。

這是一個簡短的程序,它就是這樣做的:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>

int main(int argc, char* argv[])
{
 int rc, fd;
 if (argc != 2)
 {
   fprintf(stderr, 
    "Provide command line arg to execute after TIOCNOTTY\n");
   return EXIT_FAILURE;
 }
 fd = open("/dev/tty", O_RDWR);
 if (fd < 0)
 {
   fprintf(stderr, 
    "Failed to open controlling terminal: %s\n",
    strerror(errno));
   return EXIT_FAILURE;
 }
 rc = ioctl(fd, TIOCNOTTY);
 if (rc == -1)
 {
   fprintf(stderr,
    "Failed TIOCNOTTY ioctrl: %s\b",
    strerror(errno));
   return EXIT_FAILURE;
 }
 return system(argv[1]);
}

應該有一個現有的實用程序來執行上述操作,但我找不到。

如果您要編譯該程式碼,呼叫生成的執行檔notty,那麼您可以這樣做:

echo "test" | notty "gpg -q -c --passphrase-fd 0 --output test.enc --yes --force-mdc test.in"

這應該抑制消息,但保持您的 stdout 和 stderr 完好無損。目前還不清楚還有什麼會被抑制(你需要查看 gpg 源以查看以這種方式輸出的其他內容)。

引用自:https://serverfault.com/questions/98994