Это мой первый вопрос, поэтому я приношу свои извинения, если я опускаю что-то важное. Поэтому я работал над заданием, которое обрабатывает трубопроводы с помощью форкирования. Мой код довольно грязный, усеянный заявлениями printf, поэтому я вижу, что происходит.C - dup2() не исполняется
Я огляделся в Интернете, и я думаю, что получаю представление о том, как обрабатывать трубопроводы, но проблема, с которой я сталкиваюсь, заключается в том, что мой код пропускает dup2() для любого файлового дескриптора, кроме inFD и outFD.
Вот код моей функции. Кроме того, из того, что я понимаю, мой учитель сделал макрос CHK, который проверяет наличие ошибок. Если есть ошибка (например, dup2, возвращающая -1), она завершается печатью stderr.
Мои включает в себя, глобальные переменные и MyHandler() для сигнала
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
#include <strings.h>
#include <math.h>
#include <signal.h>
// Function calls
void parse(char *w, char **ptrArray, char *inArray, char *outArray, int *pipeArray);
int flagHandler(char **ptrArray, char *inArray, char *outArray);
int pipeHandler(char **ptrArray, char *inArray, char *outArray, int *pipeArray);
// Global Variables
const int STORAGE = 254;
const int MAXITEM = 100;
int inFD; // file descriptor for <
int outFD; // file descriptor for >
int complete = 0; // for sighandler
int readDes = 0;
int writeDes = 1;
int numPipes = 0;
int status;
int forCounter = 0;
int fildes[4];
int pipeIndex = 0;
// MetaChar flags
int lessthanSign = 0; // < flag
int greaterthanSign = 0; // > flag
int firstChildFlag = 0;
int lastChildFlag = 0;
void myhandler(int signum)
{
complete = 1;
}
Моя главная функция
int main()
{
char s[STORAGE]; // array of words
char *newargv[MAXITEM];
char inArray[STORAGE]; // for <
char outArray[STORAGE]; // for >
int firstCheck;
int pidBackground; // holds value from fork(), used for background calls
struct stat st; // for stat(), checks if file exists
// dynamic array based on numPipes
// first child doesn't use this array, as it uses newargv[0] and newargv
// only the middle children and last child use this array, hence 10
int *pipeArray = malloc(10 * sizeof(int));
int numLoops = 0;
int i = 0;
signal(SIGTERM, myhandler);
for(;;)
{
// Reset flags here
lessthanSign = 0;
greaterthanSign = 0;
pipeSign = 0;
firstChildFlag = 0;
lastChildFlag = 0;
pipeIndex = 0;
parse(s, newargv, inArray, outArray, pipeArray);
pipeHandler(newargv, inArray, outArray, pipeArray);
wait(NULL);
fflush(NULL);
} // end for
printf("Entering killpg; numLoops = %d\n", numLoops);
killpg(getpid(), SIGTERM);
printf("p2 terminated.\n");
exit(0);
} // end main
Основные вызовы разбора, который заполняет newargv []. Он также заполняет inArray [] и outArray [] строкой сразу после < и> соответственно. При обнаружении знака трубы он помещает нуль в newargv [], а также помещает значение в pipeArray [] для индексации имени исполняемого файла в newargv. Я опустил вызовы parse() и flagHandler(), чтобы сохранить их минимальными.
Мои parseHandler() функция
int pipeHandler(char **ptrArray, char *inArray, char *outArray, int *pipeArray)
{
pid_t firstChild;
pid_t firstChildBackground;
pid_t middleChild;
pid_t lastChild;
pid_t lastChildBackground;
int i = 0; // plain integer for for loops
printf("Initializing pipes\n");
//pipe(fildes);
//pipe(fildes + 2);
for (i = 0; i < (2*numPipes); i+=2)
{
printf("pipe initializing; i is %d\n", i);
if (pipe(fildes + i) < 0)
{
perror("pipe initialization failed");
exit(EXIT_FAILURE);
}
}
fflush(stdout);
if ((firstChild = fork()) < 0)
{
perror("First child's fork failed!");
exit(EXIT_FAILURE);
}
printf("firstChild pid = %d\n", getpid());
if (firstChild == 0)
{
if (firstChildFlag == 1)
{
printf("inFD = open...\n");
inFD = open(inArray, O_RDONLY);
printf("Doing dup2 inFD\n");
if (dup2(inFD, STDIN_FILENO) < 0)
{
perror("First child's < dup2 failed");
exit(EXIT_FAILURE);
}
}
printf("doing dup2 fildes[writeDes]\n");
if (dup2(fildes[writeDes], STDOUT_FILENO) < 0)
{
perror("First child's dup2 failed");
exit(EXIT_FAILURE);
}
printf("*****doing dup2 fildes[writeDes] was a success!\n");
for (i = 0; i < 4; i++)
{
if (close(fildes[i]) < 0)
{
perror("close failed");
exit(EXIT_FAILURE);
}
}
if (firstChildFlag == 1)
{
lessthanSign = 0;
firstChildFlag = 0;
if (close(inFD) < 0)
{
perror("close inFD failed");
exit(EXIT_FAILURE);
}
}
writeDes += 2;
printf("About to execvp first child\n");
if (execvp(ptrArray[0], ptrArray) < 0)
{
perror("execvp failed");
exit(EXIT_FAILURE);
}
}
else
{
fflush(stdout);
if ((middleChild = fork() < 0))
{
perror("Middle child's fork failed");
exit(EXIT_FAILURE);
}
printf("middleChild pid = %d\n", getpid());
if (middleChild == 0)
{
if (dup2(fildes[readDes], STDIN_FILENO) < 0)
{
perror("Middle child's dup2 on reading failed");
exit(EXIT_FAILURE);
}
if (dup2(fildes[writeDes], STDOUT_FILENO) < 0)
{
perror("Middle child's dup2 on writing failed");
exit(EXIT_FAILURE);
}
for (i = 0; i < 4; i++)
{
if (close(fildes[i]) < 0)
{
perror("close failed");
exit(EXIT_FAILURE);
}
}
readDes += 2;
writeDes += 2;
if (execvp(ptrArray[pipeArray[0]], ptrArray + pipeArray[0]) < 0)
{
perror("Middle child's execvp failed");
exit(EXIT_FAILURE);
}
}
else
{
fflush(stdout);
if ((lastChild = fork() < 0))
{
perror("Last child's fork failed");
exit(EXIT_FAILURE);
}
printf("lastChild pid = %d\n", getpid());
if (lastChild == 0)
{
if (dup2(fildes[readDes], STDOUT_FILENO) < 0)
{
perror("Last child's dup2 on reading failed");
exit(EXIT_FAILURE);
}
if (lastChildFlag == 1)
{
outFD = open(outArray, O_CREAT | O_RDWR, 0400 | 0200);
if (dup2(outFD, STDOUT_FILENO) < 0)
{
perror("Last child's > dup2 failed");
exit(EXIT_FAILURE);
}
}
for (i = 0; i < 4; i++)
{
if (close(fildes[i]) < 0)
{
perror("close failed");
exit(EXIT_FAILURE);
}
}
if (lastChildFlag == 1)
{
greaterthanSign = 0;
lastChildFlag = 0;
if (close(outFD) < 0)
{
perror("close on outFD failed");
exit(EXIT_FAILURE);
}
}
printf("Execvp last child\n");
if (execvp(ptrArray[pipeArray[1]], ptrArray + pipeArray[1]) < 0)
{
perror("Last child's execvp failed");
exit(EXIT_FAILURE);
}
printf("Last child execvp finished\n");
}
}
}
// Only the parent gets here
printf("Only the parent should be here\n");
printf("My pid is %d\n", getpid());
for (i = 0; i < 4; i++)
{
if (close(fildes[i]) < 0)
{
perror("close failed");
exit(EXIT_FAILURE);
}
}
for (;;)
{
pid_t pid;
if (pid = wait(NULL) < 0)
{
perror("wait failed");
exit(EXIT_FAILURE);
}
if (pid == lastChild)
{
printf("Parent is waiting for lastChild\n");
break;
}
}
printf("Parent finished waiting. Returning...\n");
return 0;
}
я сделал трубку (Филдс) перед любой вилкой, так что все дети и родителя имеют свою копию. Поэтому я должен закрыть все дескрипторы файлов в каждом дочернем элементе (после dup2, но до execvp) и родителя. Затем родитель будет ждать, пока не получит pid lastChild.
С большим количеством утверждений printf я обнаружил, что ни один из них не выполняет команду dup2() (за исключением dup2 (inFD ...) и dup2 (outFD ...), когда флаги подходят). Также не печатается ошибка.
Я напечатал my (char) newargv [] и my (int) pipeArray [] и содержит правильные значения. Кажется, это всего лишь проблема dup2, и я совершенно не знаю, что с ней происходит.
Я создал простой текстовый файл test2 содержащий ls | сортировать | cat someString Где someString - это просто файл с некоторым текстом. Со всеми операциями печати в функции pipeHandler() мой вывод:
EDIT: Я исправил пару опечаток, которые у меня были. Я забыл зашнуровать дополнительный набор скобок на 3 МФС, если ((FirstChild = вилка() 0 < 0)
теперь у меня есть бесконечный цикл, как родитель ждет ВЗОМТ в LastChild в Вот результат:.
Initializing pipes
numpipes = 2
pipe initializing; i is 0
pipe initializing; i is 2
firstChild pid = 20521
firstChild pid = 20522
doing dup2 fildes[writeDes]
middleChild pid = 20521
middleChild pid = 20523
lastChild pid = 20521
Only the parent should be here
My pid is 20521
lastChild pid = 20524
<infinite loop>
Я все еще невежественны, хотя, как к тому, что происходит или что потенциально останавливая ребенка.
Удалите макрос 'CHK' и проверьте возврат самостоятельно. Распечатайте сообщение об ошибке, если вы обнаружите ошибку. Посмотрите, что будет потом. RIght теперь нам не удастся попробовать ваш код, так как у нас нет определения макроса 'CHK'. – davmac
(также исправить отступы и разместить _complete_, но также пример _minimal verifiable_ - основной метод отсутствует. См. [MCVE]). – davmac
Макрос CHK(), вероятно, более чем один раз оценивает его аргументы. – wildplasser