Fgets () call with redirect receives abnormal data stream

I was going to write a C language shell. The following is the source code:

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/wait.h>
#include <stdlib.h>

int
getcmd(char *buf, int nbuf)
{
  memset(buf, 0, nbuf);
  fgets(buf, nbuf, stdin);
  printf("pid: %d, ppid: %d\n", getpid(), getppid());
  printf("buf: %s", buf);
  if(buf[0] == 0) {// EOF
    printf("end of getcmd\n");
    return -1;
  }
  return 0;
}

int
main(void)
{
  static char buf[100];
  int fd, r, ret;

  // Read and run input commands.
  while((ret = getcmd(buf, sizeof(buf))) >= 0){
    if(fork() == 0)
      exit(0);
    wait(&r);
  }
  exit(0);
}

When I execute a compiled executable with redirecting stdin to a file called t.sh, which has the value "1111 \ n2222 \ n", for example. / myshell <t.sh, exit:

pid: 2952, ppid: 2374
buf: 1111
pid: 2952, ppid: 2374
buf: 2222
pid: 2952, ppid: 2374
buf: 2222
pid: 2952, ppid: 2374
buf: end of getcmd

Obviously, the getcmd () function gets 3 lines (1111, 2222, 2222), whereas in t.sh. And this situation gets even worse when placing more lines in t.sh.

And the main process is the only process executed by getcmd that we can determine by the output of pid.

By the way, I found that if the code wait string (& r) is deleted, the output may become normal.

+6
1

wait , , . strace Linux,

% strace -f ./a.out
[lots of stuff]
wait4(-1, strace: Process 29317 attached
 <unfinished ...>
[pid 29317] lseek(0, -2, SEEK_CUR)      = 0
[pid 29317] exit_group(0)               = ?
[pid 29317] +++ exited with 0 +++
<... wait4 resumed> [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 29317
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=29317, si_uid=1000, si_status=0
    _utime=0, si_stime=0} ---
[lots of stuff]

fork, . , , fgets , . libc fork. , stdout.

, ... , , <stdio.h> . lseek , 4095 stdin! read write <unistd.h>. , main, - stdin:

if (setvbuf(stdin, NULL, _IONBF, 0) != 0) {
    perror("setvbuf:");
   exit(1);
}

stdin , . , Linux fgets :

        stdio (2)        , ;         undefined , , , .

, , stdin :

% echo -e '1\n2' | ./a.out  
pid: 498, ppid: 21285
buf: 1
pid: 498, ppid: 21285
buf: 2
pid: 498, ppid: 21285
buf: end of getcmd

, , - , .


P.S.

fgets, , .

, .

+5

All Articles