Subject: Re: bug#14190: cat command bug

From: Bob Proulx <[email-masked]>
Date: Sun, 14 Apr 2013 14:13:31 -0600

hockseng leow wrote:
> >> Ctrl-c is behaving like Ctrl-d.

In the context you describe, yes, by necessity.  It always has.

> >> When redirecting from standard-in to an existing file, Ctrl-c empties
> >> out the old file contents. In the past, Ctrl-c just aborts cat and
> >> leave the existing file unchanged.
>
> $ cat abc.txt
> abc
> $ cat >abc.txt
> def
> ^C
> $ cat abc.txt
> def

That is the test case explanation you needed to have included before!
It explains what you are seeing and thinking.  Let's walk through it
line by line.

  $ cat abc.txt
  abc

A file has existing contents.

  $ cat >abc.txt

The shell has immediately truncated the contents of the file to a zero
lenth file.  The previous contents are gone.  If you check at that
point you will find that the file is empty.

  def

You typed in "def" followed by enter which generated a newline and cat
copied that to the file.  (Sometimes programs will buffer output and
in general libc's stdio buffering will cache up small writes into
larger writes for performance reasons.  But here it is going to write
it line by line because it is coming from your terminal.)

  ^C

You typed in control-C which generated a SIGINT sent to the cat
process.  The cat process exited due to that signal.  If you check the
exit code using the wait(2) macros WIFEXITED(status) and others you
will find it is exiting non-zero due WIFSIGNALED(status).  The shell
usually maps this to 130 which is a bit-mapped value for exiting
because of SIGINT.  "echo $?" will show this as "130".

Because the program has exited the operation system will close all of
the processes open file descriptors.  The stdout for that process was
redirected to the file by the shell.  When the process exited any open
file descriptors are closed by the operating system.

That may have a result similar to a control-D but the reasoning is
completely different.  With a C-d the stty driver would answer the
cat process' read(2) call by sending a zero byte result.  The cat
program would interpret that as an end of file and then it would close
the output itself and exit with a success exit code 0 just as if it
had come to the end of a file.

C-c interrupts the process and results in a non-zero failure exit
code.  C-d is a normal operation and results in the process closing
the output file normally and exiting with a zero success exit code.
The two things are different things.

> >> It happens in Fedora 17.

And it also happens on every Unix and GNU operating system dating back
to 1970.  That is the way things work.  Anything else would be
incorrect operation.  Starting with the shell truncating the file
immediately upon seeing the redirection of stdout to it with
">abc.txt".  Immediately upon doing the redirection that file is
truncated to zero.

Hope that explanation helps.

Bob