I've an input file whose content is abcefghz
. I want to use a pipe so that a child process p1 sends 1-letter per time to his parent process which will converts this string using the ASCII code+1 (abcefghz
will become cdfghi{
). This new string will be send through another pipe to another child process which will print the result on an output file.
This is the code:
int main (int argc, char **argv)
{
pid_t pid1, pid2;
int inputFile, outputFile;
char stringaDalFile[256];
char successivo;
char stringaRisultato[256];
int fd1[2], fd2[2]; // Pipe
inputFile = open(argv[1], O_RDONLY);
outputFile = open(argv[2], O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
pipe(fd1);
pipe(fd2);
pid1 = fork();
if (pid1 == 0) {
while ( (nread=read(inputFile, stringaDalFile, 1)) > 0) {
close(fd1[0]);
write(fd1[1], stringaDalFile, 1);
}
close(inputFile);
}
else {
close(fd1[1]);
while ( read(fd1[0], stringaDalFile, 1) > 0 ) {
successivo = converti(stringaDalFile[0]);
write(fd2[1], &successivo, 1);
}
}
pid2 = fork();
if (pid2 == 0) {
close(fd2[1]);
if (read(fd2[0], stringaRisultato, 1) == -1) {
perror("Errore");
exit(1);
}
else {
while ( read(fd2[0], stringaRisultato, 1) > 0 ) {
write(STDOUT_FILENO, stringaRisultato, strlen(stringaRisultato)); //dbg
write(outputFile, stringaRisultato, strlen(stringaRisultato));
}
}
close(outputFile);
exit(0);
}
return 0;
}
char converti (char carattere)
{
return carattere+1;
}
Unfortunately, this seems to not work at 100%, the string is converted but the program enters what seems an infinite loop:
If I CTRL-C
and gedit file2.txt
, this is its content:
.
How do I fix this?
There are a few problems in your code:
The real problem, here:
write(outputFile, stringaRisultato, strlen(stringaRisultato));
you're using strlen(stringaRisultato)
when stringaRisultato
only has one valid character at the beginning and no NUL-terminator after it. Just use 1
instead.
You are only reading one character at a time, you don't need a string of 256 characters. Change stringaDalFile
and stringaRisultato
into two single char
variables: carattereDalFile
and carattereRisultante
.
In the first child (inside if (pid1 == 0)
) you are doing close(fd1[0])
in a loop. You should move it out of the while
.
Again in the first child, you're not doing exit(0)
. This is what causes your program to keep running.
This line inside the second child:
if (read(fd2[0], stringaRisultato, 1) == -1) {
is only useful if you want to skip the first character. Is that intended? If not, remove that if
and only use the while (read(...) > 0)
.
You are writing everything to the pipe fd2[1]
before starting the second child (that will read from it). If the input file is too large (some KB) this will result in filling the pipe internal buffer and will block your program on the next write()
that it tries to perform, making it never end. To fix this, you should start the two child processes together. This would require changing the structure and logic of the code, but it's doable.
Since I don't think that's the real problem here and this program is most probably written for educational purposes I'll leave that to you and fix the rest of the above points.
Working code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
char converti (char carattere);
int main (int argc, char **argv)
{
pid_t pid1, pid2;
int inputFile, outputFile;
char carattereDalFile, carattereRisultante, successivo; // renamed
int fd1[2], fd2[2];
inputFile = open(argv[1], O_RDONLY);
outputFile = open(argv[2], O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
pipe(fd1);
pipe(fd2);
pid1 = fork();
if (pid1 == 0) {
close(fd1[0]); // <== moved out of the while loop
while (read(inputFile, &carattereDalFile, 1) > 0) {
write(fd1[1], &carattereDalFile, 1);
}
close(inputFile);
exit(0); // <== added
} else {
close(fd1[1]);
while (read(fd1[0], &carattereDalFile, 1) > 0) {
successivo = converti(carattereDalFile);
write(fd2[1], &successivo, 1);
}
}
pid2 = fork();
if (pid2 == 0) {
close(fd2[1]);
if (read(fd2[0], &carattereRisultante, 1) == -1) {
perror("Errore");
exit(1);
} else {
while (read(fd2[0], &carattereRisultante, 1) > 0) {
write(outputFile, &carattereRisultante, 1);
}
}
close(outputFile);
exit(0);
}
return 0;
}
char converti (char carattere)
{
return carattere+1;
}