| Ar Fai Ve 2004-02-28, 9:33 pm |
|
Is there a mechanism similar to pipe() which can transparently
pipe terminal file descriptors? Since any file descriptors
established by pipe() are stream file descriptors, they will
not support term-relevant ioctl commands such as TCGETA. I
would like to create a pipe in which I can catch termios
commands such as tcgetattr() and pass them to the other end
of the pipe where the controlling terminal is connected.
Basically I am interested in a pipe mechanism which allows
me to filter the data going to the output end of the
terminal, while still allowing for control commands to
pass transparently. Shown below is a small code which
illustrates the problem. It's easy to filter the data,
but I have no idea how to catch certain control commands
and pass them along the pipe. For instance, if the child
process were to exec() to ``top'' instead of simply dumping
a string, then top would assume that the new STDOUT (now
one end of a pipe) is a not a terminal because its
checks for terminal smartness (via requests through
tcgetattr or ioctl) would fail.
Thanks.
% g++ main.C
% ./a.out
tcgettattr() on real STDOUT returns 0
tcgettattr() on pipe returns -1
THIS WAS LOWERCASE
//////// main.C ////////
#include <sys/types.h>
#include <unistd.h>
#include <termios.h>
#include <iostream.h>
int main()
{
int outPipe[2];
pipe(outPipe);
pid_t child = fork();
if (child != 0) {
struct termios settings;
cerr << "tcgettattr() on real STDOUT returns "
<< tcgetattr(STDOUT_FILENO, &settings) << endl;
close(STDIN_FILENO);
close(outPipe[1]);
//
// Trivial filter which converts data arriving through pipe
// from lower case to upper
//
while (1) {
static char buf[1024];
int inCount = read(outPipe[0], buf, 1024);
if (inCount < 0)
break;
else if (inCount > 0) {
for (int i=0; i<inCount; i++) {
if (buf[i] >= 'a' && buf[i] <= 'z')
buf[i] -= 32;
}
write(STDOUT_FILENO, buf, inCount);
break;
}
}
}
else {
sleep(1);
//
// Replace stdout with one end of the pipe
//
dup2(outPipe[1], STDOUT_FILENO);
close(outPipe[0]);
close(outPipe[1]);
char *msg = "this was lowercase\n";
write(STDOUT_FILENO, msg, strlen(msg));
//
// Even though the data are connected through the pipe in the
// parent process, terminal related control commands cannot
// be handled and return an error value.
//
struct termios settings;
cerr << "tcgettattr() on pipe returns "
<< tcgetattr(outPipe[1], &settings) << endl;
}
return 0;
}
|