As per my understanding Ctrl+Z means EOF, isn't it? When Ctrl+Z is passed in as an input in the following program;
#include <stdio.h>
int main()
{
int a;
a = getchar();
if(a == EOF)
printf("Program Ended\n");
printf("Finished");
return 0;
}
It prints;
Program Ended
Finished
which is totally reasonable.
But when Ctrl+C is passed in as an input, Why does it outputs;
Program Ended, and simply end the program? Wasn't it supposed to end the program without printing anything as per the code?
PS: I'm using gcc 6.3.0
Ctrl-C maps to the ASCII control character ETX (End-of-Text - 0x03), while Ctrl-Z maps to ASCII EOF (End-of-Text - 0x26). There is also Ctrl-D for EOT (End-of-Transmission - 0x04).
Now what a particular platform does when either of these are occur in the the stdin stream is platform specific (and not C language or GCC specific). However the macro EOF has integer value -1 (rather than ASCII value 0x03)
When your code is executed at https://onlinegdb.com/4bF8adsM4 :
Ctrl-C : Program terminates immediately (causes SIGINT signal to terminate process)
Ctrl-D : a = -1, getchar() returns immediately.
Ctrl-Z : a == '\n' `getchar() returns after newline (i.e. Ctrl-Z is ignored).
On Windows, (with Microsoft C in my tests):
Ctrl-C : a = -1, getchar() returns immediately, Program terminates after outputting "Program Ended\n" with exception "Exception thrown at 0x7747B915 (KernelBase.dll) in scratch2.exe: 0x40010005: Control-C."
Ctrl-D : a == EOT, getchar() returns after newline
Ctrl-Z : a == -1, getchar() returns after newline
In the Ctrl-C case, the exception was shown in the debugger, in normal use (from the command line, nothing is reported). When run from the command line, it actually output "Finished\n" as well. It seems that the process termination is asynchronous to the I/O and program execution and the program can continue to run for some time before being terminated. I added further text, and only some of it was output. YMMV
Either way, on Windows, Ctrl-Z on stdin does trigger an EOF signal for the stdin stream, while in Unix/Linux, it is Ctrl-D. In both cases Ctrl-C causes process termination by SIGINT, but on Windows at least, it is an asynchronous signal/exception, and the process may not terminate immediately. Also in Windows, the EOF after Ctrl-Z is buffered until after newline, whereas in Unix/Linux, it aborts the input immediately.
Note that it is possible to implement a SIGINT signal handler to trap Ctrl-C to prevent process termination by that method (or handle it more elegantly).
All the other ASCII control characters have Ctrl-key mappings, what any particular platform does with these and stdin is also platform dependent.
Related
Lately have been testing out using signals such as SIGINT and SIGHUP and their role on ongoing processes on Linux. Running the following code returned some interesting results.
#include <signal.h>
#include <stdio.h>
void routine(int p){
puts("Not finishing");
sleep(2);
}
main(){
int i = 0;
signal(SIGINT, routine);
signal(SIGHUP, routine);
while(1){
printf("%d \n", i++);
}
}
As you can see, it simply counts from 0 on an infinite loop. Then, by using kill -SIGINT on the process it created, I got the following:
Routine
As you can see, before the line I requested the routine to print, the program repeated the last number (and it does not happen always). I would really like to know why.
It is likely that you are narrowly avoiding horrible bugs by accident.
What I think is happening is that the signal sometimes interrupts while printf is in progress formatting the string into the output buffer. Then the puts in the signal handler inserts more string into the output buffer. Then the handler returns, printf inserts the newline and flushes the buffer.
But guess what would happen if this signal occurred just before the flush of a full 8K output buffer. The buffer positions would be at the end. Then the puts call happens, not realizing that printf is already in process of flushing and clearing the buffer. Where exactly would it be putting the puts string? At the beginning? At the end? Would the excess data printf was in the process of writing write over the string that puts had added? All of those things are possible.
Buffered C output is not reentrant and cannot be used in signal handlers.
Here is a piece of c code that I wrote after testing some stuffs.
I know this is not a vulnerability concern, but I don't understand why the stdin is not flushed after the normal return of the program, at the point that the prompt get back stdin,stdout,stderr. I mean why the remaining chars on stdin are redirected to stdout after the end of the normal execution of the program and not flushed?
$cat dummy.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
int main(){
char rbuf[100];
if (read(0, rbuf,5) == -1){
perror("learn to count");
printf("errno = %d.\n", errno);
exit(1);
}
//printf("rbuf : %s\n",rbuf);
return 1;
}
Here the execution:
$ gcc -o dummy dummy.c
$ ./dummy
AAAAA /bin/sh
$ /bin/sh
sh-3.2$ exit
exit
$
I guess this is just the remaining string of the stdin printed on the mew stdout which is the prompt. Plus the line feed at the end, it somehow emulates the enter pressed by the user to execute a command. What's going on? I'm just curious to know more about that.
Yes, your guess is right, these are extra characters in stdin:
do this:
void flush_stdin()
{
while(getchar() != '\n');
}
Note: do not use fflush() on stdin because that is undefined behavior
edit
The stdin is wired to the terminal which starts the program(which is bash). This starts a new program dummy and the stdin of dummy is wired to the stdin of bash.
From there on, the dummy process reads five characters, neglects the others(leaving them in the stdin buffer). When the control returns to bash it waits until there is atleast one character to read from in the buffer. Low and behold, there are characters in the stdin buffer, hence the program - instead of waiting, starts to read from the stdin and since the stdin at the end, contains \n the process is actually executed. This starts /bin/sh. The rest is up to /bin/sh to worry about!
To execute your program, the shell calls fork(2) to create a child process, and in the child process calls exec(3) to replace itself with the "dummy" program.
I imagine there is something like this in the shell's source code (if it is written in C):
if (fork() == 0)
execlp(program, arguments)
The child process inherits the file descriptors of the parent; in this case the shell. So the child process has the same stdin/stdout as the shell that exec'd it, which is the virtual terminal.
I'm not sure exactly how, but I'd imagine the parent process (the original shell you typed the command in) disregards stdin somehow whilst the child process is running.
When the program exits, the shell gets its stdin back. Any extra characters that weren't read by the your program will go to the shell. And then of course the shell just treats them as a command.
If you try using fgetc(3) instead of read(2) at first it appears the extra characters are lost, not sent to the shell... but, if you unbuffer stdin, you get the same effect using fgetc(2), ie: extra characters go back to the shell.
char rbuf[100];
setbuf(stdin, NULL); // with this line - same effect as using read(2)
// without it - extra characters are lost
for (int i = 0; i < 5; ++i)
rbuf[i] = (char)fgetc(stdin);
By default stdin is line buffered. So it looks like this behaviour is avoided when using buffered stdin because the entire line is read, and extra characters are discarded, whereas unbuffered stdin (or low level reads) will not read until the end of the line, and extra characters remain to be read by the parent (shell) once your program exits.
I am having a very confusing problem right now. I wrote a test program for myself, but sometimes after I input Crtl+C, which is what I assume to be the EOF, the program closes early without running through some more commands below the While Loop I wanted it to cancel from.
#include <stdio.h>
#include <string.h>
int main()
{
char message[140];
char* p = message;
int count;
int i = 0;
int charGT;
while((charGT=getchar()) != EOF)
{
message[i] = charGT;
i++;
printf("%d" , i);
}
printf("next");
count = strlen(p);
printf("%d", count);
printf("after");
return (0);
}
Inputting "asd\n^C" will cause my program to end early. "next" or "after" will not be printed
My theory is that somehow, the \n is causing the program to step out of the loop for a moment, and then Crtl+C is exiting the program, but I don't know how that would work.
Ctrl+C is the break command and will send an interrupt signal to your application. The default handler will cause this to exit the process.
Ctrl+D is the EOF command you are looking for.
For running on windows, to enter EOF press Ctrl+Z and then press ENTER. In UNIX systems it is Ctrl+D, in Windows Ctrl+Z.
When a program is running if you press Ctrl-c a signal is sent to abort the program and the program is aborted. However, if you want to use Ctrl-c as an input but not abort the program write one signal handler which catches the signal when you press Ctrl-c and perform the action you wanted to.
I got some code that prints to stdout, in pseudo code it looks like
int main(){
//allocate data
while(conditional){
char *string = makedata();
fprintf(stdout,"%s",string);
}
//cleanup
}
This works fine, if the conditional is toggled to zero, but if I pipe the output like
./a.out |head -n10 >dumped
Then the code never reaches the cleanup part, I don't understand how to check if the stdout gets closed.
Thanks
Your stdout hasn't been closed, so checking for that will be useless. Your program has received a SIGPIPE and exited. A SIGPIPE is delivered whenever your program writes to a pipe on which there are no readers. In your example, that happens when head exits, closing its stdin.
You should ignore SIGPIPE if you want your program to continue. This code will ignore SIGPIPE:
(void)signal(SIGPIPE, SIG_IGN);
If you don't want to modify your program, you can arrange that something continues to read from the pipe, even after head closes its input. 1
./a.out | ( head -n10 >dumped ; cat > /dev/null )
1: The shell example is valid for bash, maybe not for csh.
It is closed by killing the process with SIGPIPE.
If you want to go on when your output is being ignored, then set up a SIG_IGN handler for SIGPIPE, and handle the error from the fprintf (which will be delayed by buffering, so you cannot assume data that has been written has actually reached the user).
As Rob points out in comments to his answer, you are not worried that stdout has been closed; rather, you are worried that the other end of the pipe is closed. This may be pedantry, but it leads to the solution of your problem. Namely, you do not care if stdout is closed, but only if your printf succeeds. You should check the return value of printf: if it is -1, then the write has failed.
As Simon Richter points out, you will never get the return value of printf if you do not ignore SIGPIPE, because a result of writing to stdout when the other side of the pipe has been closed is that SIG_PIPE will be sent to the process. So you need to do something like:
signal( SIGPIPE, SIG_IGN ); /* Careful: you now must check the return of *all* writes */
if( fprintf( stdout, ... ) == -1 ) {
/* handle the error */
}
I've not tried this, but provided you were using the standard file descriptor for stdout, you may be able to try performing an fstat(1, &stat_structure) and check the return and error codes.
#include<stdio.h>
#include<signal.h>
#include<stdlib.h>
void handler(int signo)
{
printf("First statement");
system("date");
exit(EXIT_SUCCESS);
}
int main()
{
signal(SIGINT,handler);
printf("Waiting for KeyboardInterrupt\n");
for(;;);
return 0;
}
Test run:-
shadyabhi#shadyabhi-desktop:~/c$ gcc main.c
shadyabhi#shadyabhi-desktop:~/c$ ./a.out
Waiting for KeyboardInterrupt
^CWed Mar 10 23:55:47 IST 2010
First statementshadyabhi#shadyabhi-desktop:~/c$
Why is "First Statement" getting printed after system() call??
The standard input, output and error streams are created when your process starts, which in this case is your C program. When you make the system call, another process is created to execute the date command, and it gets its own set of streams.
In your program, the printf output is buffered to the standard output stream of your C program. Then the output of date is buffered to its own standard output stream. When the system call ends, the date standard output stream is flushed, so you see the output. Then, when your C program ends, its standard output stream is flushed and you see the printf output.
You might find this fellow's posting helpful: http://www.pixelbeat.org/programming/stdio_buffering/
Did you try flushing the buffer before calling system("date")?
I just added fflush(NULL); before system, and the output is as expected.
The C IO API buffers things up in order to print more efficiently. Typically the buffer is flushed whenever you write out a newline or manually flush it.
So you can use a newline to flush the buffer:
printf("First statement\n");
Or use the fflush function:
printf("First statement");
fflush (stdout);