抑制 GPG“從文件描述符 0 讀取密碼”消息
簡單地說,我怎樣才能讓 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 源以查看以這種方式輸出的其他內容)。