Parent gets EOF when child quits after getting an EOF? - c

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
int ch;
pid_t p = fork();
if (p == 0) {
do {
ch = getchar();
} while (ch >= 0);
return 0;
}
int s;
waitpid(p, &s, 0);
printf("A done\n");
p = 0;
do {
ch = getchar();
} while (ch >= 0 && (++p));
printf("chars: %d\n", p);
return 0;
}
Here's a minimal example code. Theoretically it should read some characters until EOF, and print A done, and read some more characters, and show you how many there are after A done.
However, on my Windows Subsystem for Linux (Ubuntu 18.04), when I hit Ctrl-D for the first time, both the child and parent processes quit (receives an EOF). The output I get is something like
asdfghjkl
^DA done
chars: 0
Why is that? And how do I fix this?

In a fork(2), file descriptors are dup(2)ed, so they share the same file pointer, and what one of the process reads, is not read by the other, as a consequence of this.

Related

What is the importance of adding "\n" to stdout when it's redirected to another process?

So, I'm playing with pipes in c, and I have an exercise where I call a program through command line as this: "./self 1" which then calls itself with execlp but with an argument 2: "./self 2" which further on calls itself with argument 3: "./self 3". The point of these processes is this: process1 takes a line from keyboard and puts it in pipe1, then process2 gets the line from pipe1 and puts it in pipe2, then process3 gets it from pipe2 and counts the number of space characters. This code never works if I dont print a newline character on the screen before taking inputs with fprintf(stdout,"\n"); . Why is that?
Here is the code:
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char* argv[]) {
if (strcmp(argv[1], "1") == 0) {
int fdpipe1[2];
if (pipe(fdpipe1)) {
printf("Error pipe1\n");
return 0;
}
pid_t p;
p = fork();
if (p == 0) {
close(fdpipe1[1]);
dup2(fdpipe1[0], 0);
execlp("./self", "./self", "2", NULL);
} else {
close(fdpipe1[0]);
fprintf(stdout, "\n");
dup2(fdpipe1[1], 1);
char input[100];
gets(input);
puts(input);
wait(NULL);
}
}
else if (strcmp(argv[1], "2") == 0) {
int fdpipe2[2];
if (pipe(fdpipe2)) {
printf("Error pipe2\n");
return 0;
}
pid_t p;
p = fork();
if (p == 0) {
close(fdpipe2[1]);
dup2(fdpipe2[0], 0);
execlp("./self", "./self", "3", NULL);
} else {
close(fdpipe2[0]);
fprintf(stdout, "\n");
dup2(fdpipe2[1], 1);
char input[100];
gets(input);
puts(input);
wait(NULL);
}
}
else if (strcmp(argv[1], "3") == 0) {
char input[100];
gets(input);
int i = 0, counter = 0;
while (input[i] != '\0') {
if (input[i++] == ' ') counter++;
}
printf("%d\n", counter);
}
return;
}
In this kind of construct, when you connect stdout from a process to stdin of another process via unnamed pipe, a newline character is added usually to ensure the stream is sent, i.e. the stdout buffer is flushed, as a parallel example, when you use scanf, only when you hit enter (a newline is added to stdin) is the stream read, a similar principle applies here.
I would suggest you use STDIN_FILENO and STDOUT_FILENO
built in macros instead of the hard coded file descriptors, if not for anything else, it makes the code more readable for someone who is unfamiliar with the matter.
Please avoid using gets, this is a dangerous function, it does not check the bounds of the destination buffer, it can cause all kinds of trouble, so much so it was deprecated and later removed from the standard, though it still can be used with some compilers, for legacy reasons I would imagine, check this fantastic answer on a post about this topic:
Why is the gets function so dangerous that it should not be used?
The advice is to use fgets instead.

How to use dup2 to redirect stdin and stdout to pipe file descriptors?

I was trying to fork a process and redirect stdout of the parent to the writing end of the pipe and stdin of the child to the reading end of the pipe. The child is supposed to read integers until the parent prints zero. the parent prints from 1 to 3 and then prints 0. Both the parent and the child prints the time when they start and when they finish. since the parent can't print to stdout it sends it's starting and finishing time to the child and the child prints both its starting time and finishing time and parents starting time and finishing time. I could've used dup and redirected stdout to another file descriptor but I chose to make it simple. The program is very simple but the output that I get doesn't make scene.
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
int main()
{
int fd[2];
int p = pipe(fd);
int ch = fork();
if (ch)
{
// Parent - Counts from 1 to 3
int dp = dup2(fd[1], 1);
printf("Cnt_Started_at_%d\n", time(NULL));
for (int i = 0; i <= 3; i++)
{
printf("Parent %d\n", i);
sleep(1);
}
printf("0\n");
printf("Cnt_Finished_at_%d\n", time(NULL));
}
else
{
// Child - Terminated by 0
int dp = dup2(fd[0], 0);
printf("Trm_Started_at_%d\n", time(NULL));
char buffer[100];
scanf("%s", buffer);
printf("%s\n", buffer);
int i;
while (scanf("Parent %d", &i) && i)
printf("Recieved: %d\n", i);
scanf("%s", buffer);
printf("%s\n", buffer);
printf("Trm_Finished_at_%d\n", time(NULL));
}
}
Output:
Trm_Started_at_1578295974
Cnt_Started_at_1578295974
Parent
Trm_Finished_at_1578295978
The root issue is the usage of 'scanf %s' to read messages. Recall that '%s' will stop reading when it encounter white space, and will put the white space back into the buffer.
The initial message from the parent is 'Cnt_Started_at_1234\n'. This child process will read the token, but will leave the trailing '\n' in the buffer.
Next the parent will send 'Parent 0\n'. The Child will attempt to parse this is scanf("Parent %d", &i) && i). Two issues here:
The 'P' from 'Parent' will not match the left over '\n' from the initial message
When the format is updated to skip of leading spaces, the value of 'i' will be zero, which will cause the while to exit after reading 'Parent 0'.
Possible solution: Allow the scanf to skip of spaces, and eliminate the condition on i
while (scanf(" Parent %d", &i) == 1 )
printf("Recieved: %d\n", i);
The problem here is with your scanf statement. As suggested by #dash-o, change it to treat spaces.
Another problem is that, first i = 0. You need to modify your while to accomodate 0.
Since you are only evaluating i in your while loop, you won't be entering for ``i=0``` case.
Below is the modified program and the output, also, please add various checks for return values of the functions / buffer overflows as you deem right --
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
int main()
{
int fd[2];
int p = pipe(fd);
int ch = fork();
if (ch)
{
// Parent - Counts from 1 to 3
int dp = dup2(fd[1], 1);
printf("Cnt_Started_at_%d\n", time(NULL));
for (int i = 0; i <= 3; i++)
{
printf("Parent %d\n", i);
sleep(1);
}
printf("0\n");
printf("Cnt_Finished_at_%d\n", time(NULL));
}
else
{
// Child - Terminated by 0
int dp = dup2(fd[0], 0);
printf("Trm_Started_at_%d\n", time(NULL));
char buffer[100];
scanf("%s", buffer);
printf("%s\n", buffer);
int i;
while (scanf(" Parent %d", &i) && i >= 0) // notice change here ...
printf("Recieved: %d\n", i);
scanf("%s", buffer);
printf("%s\n", buffer);
printf("Trm_Finished_at_%d\n", time(NULL));
}
}
OUTPUT --
$ ./main.out
Trm_Started_at_1578303662
Cnt_Started_at_1578303662
Recieved: 0
Recieved: 1
Recieved: 2
Recieved: 3
0
Trm_Finished_at_1578303666

can't get input after first time in do while

I am trying to fork a child process put him in sleep and wake him up whenever the user enter a line of text to print number of lines entered.
My code is working fine. But weird thing I found is I have to user two gets(str) statement if I didn't the user will be prompted for 1 time only.
if run the code and comment one gets(str) you will know what I mean.
Your help is appreciated. Thanks
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <wait.h>
#include <unistd.h>
#include <signal.h>
main () {
int n;
char ch;
pid_t child;
int erret;
char str[20];
int c = 0;
if ((child = fork ()) < 0) {
perror ("fork");
exit (0);
}
else {
//waitpid(child,NULL,0);
do {
waitpid (child, NULL, 0);
printf ("Enter a line(s) \n");
//funn();
//fflush(stdin);
//scanf("%d",&n);
gets (str);
gets (str);
erret = kill (child, SIGCHLD);
printf ("Signal %d\n", erret);
if (erret >= 0) {
c++;
printf ("You have entered : %d line(s)\n", c);
//pause();
//waitpid(child,NULL,0);
}
else {
kill (child, SIGKILL);
exit (0);
}
printf ("\nPress 9 to exit :");
fflush (stdin);
scanf ("%d", &n);
fflush (stdin);
} while (n != 9);
kill (child, SIGKILL);
}
}
Your concept is flawed, you're forking with out specifying what the parant and child does. So you have a race conditon on gets. This is because after the fork call two copies of the code is run, one copy by the parent and one copy by the child. So the fix is to add a swich or else if statement to separate your code into sections for the child and parent. BTW as already stated use fgets
switch(fork()):
case -1:
//Error
case 0:
// Child code
default:
// Parant code
There are a number of ways to get repetitive string input as you are trying to do. One of the standard approaches is to gather input until the user signals EOF signifying there is no more data to enter. (On Linux EOF is generated from the terminal with ctrl + d). Without changing your logic and without commenting on your fork, waitpid, etc.. implementation, the following is one way to handle gathering string input for your program until the users sends an EOF by pressing ctrl+d on the keyboard:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <wait.h>
#include <unistd.h>
#include <signal.h>
int main () {
pid_t child;
int erret;
int c = 0;
ssize_t nread = 0; /* number of chars read by getline */
char *lineptr = NULL; /* string read by (NULL forces getline to allocate) */
size_t nbytes = 0; /* number of bytes to read (ignored with lineptr = NULL) */
if ((child = fork ()) < 0) {
perror ("fork");
exit (0);
}
else
{
waitpid (child, NULL, 0);
printf ("\nEnter line(s) of text (ctrl+d to exit):\n\n");
while (printf (" Input: ") && (nread = getline (&lineptr, &nbytes, stdin) != -1))
{
erret = kill (child, SIGCHLD);
printf ("\n Signal %d\n", erret);
if (erret >= 0) {
c++;
printf (" You have entered : %d line(s)\n\n", c);
}
else
{
kill (child, SIGKILL);
exit (0);
}
}
kill (child, SIGKILL);
}
return 0;
}
output:
$ ./bin/ind2
Enter line(s) of text (ctrl+d to exit):
Input: line one
Signal 0
You have entered : 1 line(s)
Input: line 2
Signal 0
You have entered : 2 line(s)
Input: line 3
Signal 0
You have entered : 3 line(s)
Input: Killed

Can't seem to find an EOF character?

I have:
#include <stdio.h>
/* Copy input to output; 2nd version. */
main(void)
{
int c;
while ((c = getchar()) != EOF)
putchar(c);
return 0;
}
I want to terminate the while loop by entering an end-of-line character.
I Have Tried Inputing:
"\t"
"\0"
%d
%f
%c
%x
%n
EOF
"EOF"
\nEOF
int
float
char
long
long long
array
1 => 10
all letters
all symbols on keyboard
.
.
.
Question: What is the magical EOF character that I'm looking for?
*I am Sorry if this is a really easy question for you,but please be nice I'm only a beginner trying to learn something.
On Windows, Ctrl+Z;
on Linux, Ctrl+D.
There is NO EOF character. "EOF" is a logical condition that represents "end of file" has been met.
On Linux machine, you can "signal" the standard input EOF condition by pressing Ctrl+D in the beginning of the line.
Windows systems reserve a character Ctrl+Z, which is 0x1A in hex, to indicate this "end of file" condition. You can input this character by pressing Ctrl+Z. It is still not a real EOF character though. Rather, it is a convention in Windows.
Here ya go #Andy. You just used an int by accident instead of char c.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
char c;
while ((c = getchar()) != '\t') // while input != tab, remember to use single
putchar(c); // quotes for characters '\n' etc.
system("pause");
return 0;
}
If you are curious about the signals in UNIX/LINUX system this code might help, wrote it for one of my OS labs. Essentially, the program keep asking for a user input. However, when you try to quit during in the beginning with ctrl+z or ctrl+c it doesn't allow you to because the signal gets ignored by the parent and gets handled by the signal handlers for the child process. Note, the parent is sleeping in the beginning, but when it wakes up it kills the child process and ends the program.
#include <stdio.h>
#include <signal.h>
#include <malloc.h>
#include <sys/types.h>
#include <sys/wait.h>
#define maxLength 1024
//****************************************
// Signal Handlers For Child Process
//****************************************
void ctrlchandler(){
signal(SIGINT, SIG_IGN); //Ignore ctrl-c
write(1, "Don't even think about it!", 26);
}
void ctrlzhandler(){
signal(SIGTSTP, SIG_IGN); //Ignore ctrl-z
write(1, "Nice Try.", 9);
}
//****************************************
// Main Program
//****************************************
int main(int argc, char* argv[]){
pid_t pid;
int status;
//Dynamically allocate char array for input line
char *inputLine = (char*)malloc(maxLength*sizeof(char));
//Ignore Ctrl-z and Ctrl-c
signal(SIGINT, SIG_IGN);
signal(SIGTSTP, SIG_IGN);
//Fork Process
if((pid = fork())<0){
//If fork fails
printf("Fork Child Process Faild.\n");
}
//Parent Process
else if(pid != 0){
printf("Parent: My child %d has been spawned.\n",pid);
printf("My pid is %d\n",getpid());
sleep(30);
kill(pid, SIGKILL);
if(waitpid(pid, &status, WUNTRACED))
printf("Child %d has terminated abnormally.\n",pid);
}
//Child Process
else{
sleep(1); //Wait for parent to output first
while(1){
signal(SIGTSTP, ctrlzhandler);
signal(SIGINT, ctrlchandler);
printf("Enter Input:");
fgets(inputLine, maxLength, stdin);
}
}
//Free allocated char array
free(inputLine);
return 0;
}
main()
{
printf ("%d=%x sizeof=%d\n", EOF, EOF, sizeof(EOF));
}
The output is:
-1=ffffffff sizeof=4
EOF is not a char, it is an int
if you type the Control sequence signifying end of file - it will be translated to an int whose value is -1

fork() system call and while loop ( part 2)

Does anyone know why the printf("Type q to quit") line prints twice in the terminal when I run this code:
#include <stdio.h>
#include <unistd.h>
int main (int argc, char *argv[])
{
char run[2];
run[0]='a';
int pid=0;
while (run[0]!= 'q')
{
printf("Type q to quit \n");
fgets (run, 2, stdin);
pid=fork();
//wait();
if(pid==0) { break;}
}
}
I would like the child to break from the loop and the parent to continue looping (to create new children). If I call wait() the execution ends after the first iteration regardless of whether I enter 'q' or not. Otherwise it works as expected but prints the "Type q to quit" line twice every time. Why does this happen?
You have three bugs. First, the carriage return that the user types, after whatever letter, counts as input. Assuming the user types only one character per line, your fgets calls will alternate between returning the character you care about, and returning '\n'. You need to read and discard characters until you reach the end of each line of input, on each iteration. This is what is causing the double printouts.
Second, you need to test for 'q' in between reading from stdin and calling fork; right now, you fork once more after reading the 'q'. Right now this is invisible, but once the child process starts doing something useful it won't be.
Third, this program will go into an infinite loop if the user types ^D at it, because you're not checking for EOF.
Putting that together, corrected code looks like this. I've also fixed some style nits, and arranged so that the parent process exits immediately rather than dropping out of the for loop; this means that when control reaches the point marked with a comment, you know you're in a child process, rather than in the parent on its way out.
#include <stdio.h>
#include <unistd.h>
int
main(void)
{
pid_t pid;
int c;
for (;;)
{
puts("Type q to quit");
c = getchar();
if (c == 'q')
return 0;
if (c == '\n')
continue;
while (c != EOF && c != '\n')
c = getchar();
if (c == EOF)
return 0;
pid = fork();
if (pid == 0)
break;
else if (pid == -1)
{
perror("fork");
return 1;
}
}
/* control reaches this point only in child processes */
return 0;
}
When you type x<enter> on your terminal, you'll get (assuming ordinary encodings all over) two bytes sent to your process: one for the x, one for the newline.
Your fgets call reads at most one byte (so, the x), forks of a child that dies "instantly", prints the messages and calls fgets. fgets picks up where it left: it reads the newline char without blocking, your code forks again for no reason, and loops back.
At that point there's nothing left in the input stream, so fgets waits for I/O.
See for example: I am not able to flush stdin for ways to "clear out" the input stream that you could use here.
You need to wait for these forked process down the line:
int main (int argc, char *argv[])
{
char run[2];
run[0]='a';
int pid=0;
int pids[256]; // should be enough.
int j,i = 0;
while (run[0]!= 'q')
{
printf("Type q to quit \n");
fgets (run, 2, stdin);
pid=fork();
//wait();
if(pid==0) { break;}
else { pids[i] = pid; i++; }
}
for (j = 0 ; j < i && pid != 0 ; j++)
wait(pids[j]);
if(pid == 0){
// do something
}
}
You could instead have the child call another function (such as a program wrapper or even itself in non-forkable version) instead of breaking. The waiting would remain the same i.e. wait only once all forks are, well, forked.

Resources