Я пишу небольшую программу с системными вызовами, которая анализирует входной файл, содержащий команды и их параметры в каждой строке, сравнивает их, выводя истекшее время, и ждет, пока они запустятся один за другим, или выполняет их параллельно (в основном, независимо от того, ждать() порожденных детей или не в цикле)
Проблема в том, что я должен использовать gets()
, который, как я понимаю, устарел и чрезвычайно опасен, но все же будет обязательным требованием для моих экзаменов CS (вздох).
Я делаю это, анализируя каждую строку с gets()
и strtok()
с файлом, перенаправленным на stdin
.
Кажется, это работает нормально, если последним параметром является p
, то есть если дочерние элементы должны запускаться параллельно, не выполняя wait()
в каждом цикле анализа новой строки и создания дочерних элементов.
НО, если последним параметром является s
(или любой другой), gets()
кажется странным образом считывает повторяющиеся строки из файла и порождает в два раза больше дочерних элементов. Я совершенно не понимаю, почему и как это происходит.
Например, если входной файл содержит данные ниже, а последний параметр равен p
:
Input file:
ls -l
ps
ps -lu user
Output file:
Comm 1: ls
Elapsed time: 0000.001824
Comm 2: ps
Elapsed time: 0000.014160
Comm 3: ps
Elapsed time: 0000.015795
Но, если входной файл содержит то же самое и последним параметром является s
:
Input file:
ls -l
ps
ps -lu user
Output file:
Comm 1: ls
Elapsed time: 0000.001612
Comm 2: ps
Elapsed time: 0000.008564
Comm 3: ps
Elapsed time: 0000.009006
Comm 4: ps
Elapsed time: 0000.007379
Comm 5: ps
Elapsed time: 0000.008407
Comm 6: ps
Elapsed time: 0000.008975
// ./prog inputFile logFile p
// inputFile: file with a series of lines of max. 200 chars which consist of:
// command p1 p2 ... pn (between 0 and 30 parameters)
// logFile: where the times are going to be logged
// For each command parsed and executed:
// command <i>: <name of the program executed>
// Elapsed time: xxxx.yyyyyy
// p is either "s" or "p"
// If it's "s", the commands must be executed in series
// If it's "p", the commands must be executed in parallel
#include <unistd.h> // exec, read
#include <fcntl.h> // open
#include <stdio.h> // printf
#include <stdlib.h> // exit
#include <string.h> // strtok
#include <time.h> // timeval
#include <sys/wait.h>
int main(int argc, char *argv[]) {
if (argc < 4) {
printf("Usage: ./prog inputFile logFile p\n"); exit(0);
}
int fdCom = open(argv[1], O_RDONLY); // opens the input file with the instructions in it
int fdLog = creat(argv[2], 0600); // creates the logFile
int fd[2]; pipe(fd); // pipe son->father
close(0);dup(fdCom); // place the inputFile into stdin in order to use gets() on it
close(fdCom);
int lineNumber = 0;
char buf[200]; // max length of a line
char *com[21]; // command + max number of parameter
while (gets(buf) != NULL) { // While there's still lines left in the input file...
lineNumber++;
int i = 0;
com[i++] = strtok(buf, " "); // Parse the command
while ((com[i] = strtok(NULL, " ")) != NULL) { // And its parameters
i++;
}
printf("Leftover buf is: %s\n", buf);
printf("The first three parsed parts are:%s %s %s\n", com[0], com[1], com[2]);
if (fork() == 0) { // child
if (fork() == 0) { // create another child in charge of running the current command
close(fd[0]);close(fd[1]);
execvp(com[0], com);
} else { // wait for it to finish
close(1); dup(fd[1]); // stdout to pipe output
close(fd[0]);close(fd[1]);
struct timeval initialTime, elapsedTime;
gettimeofday(&initialTime, NULL);
wait(NULL);
gettimeofday(&elapsedTime, NULL);
elapsedTime.tv_sec = elapsedTime.tv_sec - initialTime.tv_sec;
elapsedTime.tv_usec = elapsedTime.tv_usec - initialTime.tv_usec ;
if(elapsedTime.tv_usec < 0){
elapsedTime.tv_usec = elapsedTime.tv_usec + 100000;
elapsedTime.tv_sec--;
}
printf("Comm %d: %s\nElapsed time: %04d.%06d\n",lineNumber, com[0], elapsedTime.tv_sec, elapsedTime.tv_usec); // Va por pipe a padre
fprintf(stderr, "Comm %d: %s\nElapsed time: %04d.%06d\n",lineNumber, com[0], elapsedTime.tv_sec, elapsedTime.tv_usec); // Va por pipe a padre
exit(0);
}
} else { // Father
if (argv[3][0] == 's') { // If they indicated "s" as the last parameter, we have to wait for the current program until we execute another command
printf("Waiting...\n");
wait(NULL);
} // Else, continue launching new ones
}
}
close(fd[1]); // Close the pipe's output
int readBytes;
while((readBytes = read(fd[0], buf, sizeof(buf))) > 0) { // Writes everything that comes from the pipe into the logFile
write(fdLog, buf, readBytes);
}
close(fd[0]); // Close the pipe's output
// once everything is fixed, handle waiting for children here in case it was a parallel run
exit(0);
}