Мне нужно изменить простую оболочку, которую я написал для предыдущего домашнего задания, для обработки перенаправления ввода / вывода, и у меня возникают проблемы с работой каналов.Кажется, что когда я пишу и читаю в stdout и из stdin после дублирования файловых дескрипторов в отдельных процессах, конвейер работает, но если я использую что-то вроде printf, fprintf, gets, fgets и т. Д., Чтобы попытаться увидеть, является ли выводОбнаруженный в канале, он отправляется на консоль, хотя файловый дескриптор для stdin и stdout явно является копией канала (я не знаю, правильно ли это сформулировать, но, думаю, смысл ясен).
Я на 99,9% уверен, что я делаю все, как и должно быть, по крайней мере, в простом C - например, закрытие всех файловых дескрипторов соответствующим образом после dup () - и файловый ввод / вывод работает нормальнотак что это похоже на проблему детали, о которой я не знаю и не могу найти никакой информации.Я провел большую часть дня, пробуя разные вещи, и последние несколько часов гуглил, пытаясь выяснить, могу ли я перенаправить cin и cout на канал, чтобы посмотреть, исправит ли это это, но кажется, что это больше проблем, чем стоитэтот пункт.
Должно ли это работать путем простого перенаправления stdin и stdout, поскольку cin и cout должны синхронизироваться со stdio?Я подумал, что это должно произойти, тем более что команды, вероятно, написаны на C, поэтому они будут использовать stdio, я думаю.Однако, если я попробую команду типа «cat [file1] [file2] | sort», она выведет результат команды cat [file1] [file2] в командную строку, и сортировка не получит никакого ввода, поэтому она не имеетвыход.Понятно также, что dup () также не влияет на cout и cin, поэтому я соединил два и два вместе и пришел к такому выводу. Вот несколько укороченная версия моего кода, исключая все проверки на ошибки и тому подобное, которые яЯ уверен, что справляюсь хорошо.Я могу опубликовать полный код, если он дойдет до него, но это много, поэтому я начну с этого.
Я переписал функцию так, чтобы родительский элемент раздваивал дочерний элемент для каждой команды и связывал их с помощью каналов.по мере необходимости, а затем ждет, чтобы дочерние процессы умерли.Опять же, запись и чтение файловых дескрипторов 0 и 1 работают (то есть запись и чтение из канала), stdio в указателях FILE stdin и stdout не работают (не запись в pipe).
Спасибово многом это меня убивает ...
ОБНОВЛЕНИЕ: я не менял строковый cmd для каждой из разных команд, поэтому он не работал, потому что канал просто перешел к одной и той же командеитоговый результат был таким же ... Извините за глупость, но спасибо, потому что я нашел проблему с strace.
int call_execv( string cmd, vector<string> &argv, int argc,
vector<int> &redirect)
{
int result = 0, pid, /* some other declarations */;
bool file_in, file_out, pipe_in, pipe_out;
queue<int*> pipes; // never has more than 2 pipes
// parse, fork, exec, & loop if there's a pipe until no more pipes
do
{
/* some declarations for variables used in parsing */
file_in = file_out = pipe_in = pipe_out = false;
// parse the next command and set some flags
while( /* there's more redirection */ )
{
string symbol = /* next redirection symbol */
if( symbol == ">" )
{
/* set flags, get filename, etc */
}
else if( symbol == "<" )
{
/* set flags, get filename, etc */
}
else if( pipe_out = (symbol == "|") )
{
/* set flags, and... */
int tempPipes[2];
pipes.push( pipe(tempPipes) );
break;
}
}
/* ... set some more flags ... */
// fork child
pid = fork();
if( pid == 0 ) // child
{
/* if pipe_in and pipe_out set, there are two pipes in queue.
the old pipes read is dup'd to stdin, and the new pipes
write is dup'd to stdout, other two FD's are closed */
/* if only pipe_in or pipe_out, there is one pipe in queue.
the unused end is closed in whichever if statement evaluates */
/* if neither pipe_in or pipe_out is set, no pipe in queue */
// redirect stdout
if( pipe_out ){
// close newest pipes read end
close( pipes.back()[P_READ] );
// dup the newest pipes write end
dup2( pipes.back()[P_WRITE], STDOUT_FILENO );
// close newest pipes write end
close( pipes.back()[P_WRITE] );
}
else if( file_out )
freopen(outfile.c_str(), "w", stdout);
// redirect stdin
if( pipe_in ){
close( pipes.front()[P_WRITE] );
dup2( pipes.front()[P_READ], STDIN_FILENO );
close( pipes.front()[P_READ] );
}
else if ( file_in )
freopen(infile.c_str(), "r", stdin);
// create argument list and exec
char **arglist = make_arglist( argv, start, end );
execv( cmd.c_str(), arglist );
cout << "Execution failed." << endl;
exit(-1); // this only executes is execv fails
} // end child
/* close the newest pipes write end because child is writing to it.
the older pipes write end is closed already */
if( pipe_out )
close( pipes.back()[P_WRITE] );
// remove pipes that have been read from front of queue
if( init_count > 0 )
{
close( pipes.front()[P_READ] ); // close FD first
pipes.pop(); // pop from queue
}
} while ( pipe_out );
// wait for each child process to die
return result;
}