scp的prompt为啥隐藏不掉
把scp的标准输出和标准错误都重定向到一个文件,为什么shell界面还能打出"Enter windows password:"的字符串呢?
scp fromfilename username@x.x.x.x:/topath/tofilename 2>&1 > /tmp/tmp.txt
Enter windows password:
查了openssh的代码,答案很明显了。
char *
readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags)
{
ssize_t nr;
int input, output, save_errno;
char ch, *p, *end;
struct termios term, oterm;
struct sigaction sa, savealrm, saveint, savehup, savequit, saveterm;
struct sigaction savetstp, savettin, savettou, savepipe;
/* I suppose we could alloc on demand in this case (XXX). */
if (bufsiz == 0) {
errno = EINVAL;
return(NULL);
}
restart:
signo = 0;
/*
* Read and write to /dev/tty if available. If not, read from
* stdin and write to stderr unless a tty is required.
*/
if ((flags & RPP_STDIN) ||
(input = output = open(_PATH_TTY, O_RDWR)) == -1) {
if (flags & RPP_REQUIRE_TTY) {
errno = ENOTTY;
return(NULL);
}
input = STDIN_FILENO;
output = STDERR_FILENO;
}
/*
* Catch signals that would otherwise cause the user to end
* up with echo turned off in the shell. Don't worry about
* things like SIGXCPU and SIGVTALRM for now.
*/
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0; /* don't restart system calls */
sa.sa_handler = handler;
(void)sigaction(SIGALRM, &sa, &savealrm);
(void)sigaction(SIGHUP, &sa, &savehup);
(void)sigaction(SIGINT, &sa, &saveint);
(void)sigaction(SIGPIPE, &sa, &savepipe);
(void)sigaction(SIGQUIT, &sa, &savequit);
(void)sigaction(SIGTERM, &sa, &saveterm);
(void)sigaction(SIGTSTP, &sa, &savetstp);
(void)sigaction(SIGTTIN, &sa, &savettin);
(void)sigaction(SIGTTOU, &sa, &savettou);
/* Turn off echo if possible. */
if (input != STDIN_FILENO && tcgetattr(input, &oterm) == 0) {
memcpy(&term, &oterm, sizeof(term));
if (!(flags & RPP_ECHO_ON))
term.c_lflag &= ~(ECHO | ECHONL);
#ifdef VSTATUS
if (term.c_cc[VSTATUS] != _POSIX_VDISABLE)
term.c_cc[VSTATUS] = _POSIX_VDISABLE;
#endif
(void)tcsetattr(input, _T_FLUSH, &term);
} else {
memset(&term, 0, sizeof(term));
term.c_lflag |= ECHO;
memset(&oterm, 0, sizeof(oterm));
oterm.c_lflag |= ECHO;
}
if (!(flags & RPP_STDIN))
(void)write(output, prompt, strlen(prompt));
end = buf + bufsiz - 1;
for (p = buf; (nr = read(input, &ch, 1)) == 1 && ch != '/n' && ch != '/r';) {
if (p < end) {
if ((flags & RPP_SEVENBIT))
ch &= 0x7f;
if (isalpha(ch)) {
if ((flags & RPP_FORCELOWER))
ch = tolower(ch);
if ((flags & RPP_FORCEUPPER))
ch = toupper(ch);
}
*p++ = ch;
}
}
scp会运行一个ssh子进程来完成连接鉴权.
13996 root 0:00 /usr/local/bin/ssh -x -oForwardAgent no -oPermitLocalCommand no -oClearAllForwardings yes -lusername x.x.x.x scp -t /topath/tofilename
root@444444[]:/proc/13996/fd> ls -lrt
total 0
lrwx------ 1 root root 64 Jan 4 04:12 9 -> /tmp/lock/lock9997
lrwx------ 1 root root 64 Jan 4 04:12 6 -> /dev/tty
lrwx------ 1 root root 64 Jan 4 04:12 5 -> socket:[158339]
lrwx------ 1 root root 64 Jan 4 04:12 4 -> socket:[158338]
lrwx------ 1 root root 64 Jan 4 04:12 3 -> socket:[160359]
lrwx------ 1 root root 64 Jan 4 04:12 2 -> /dev/pts/0
l-wx------ 1 root root 64 Jan 4 04:12 1 -> pipe:[160353]
lr-x------ 1 root root 64 Jan 4 04:12 0 -> pipe:[160352]
从此可知,ssh就是通过file descriptor 6直接写/dev/tty来把prompt显示到shell界面的,和标准输出1/标准错误2没有任何关系。
lrwx------ 1 root root 64 Jan 4 04:12 6 -> /dev/tty