Processo executado sem leitura do stdin

2

Eu tenho um programa A fazendo o seguinte:

  1. Ler 2 bytes da entrada
  2. Imprimir entrada de leitura
  3. exec ing no programa B.

O programa B faz o seguinte

  1. Ler 2 bytes da entrada
  2. Entrada de impressão

Para torná-lo concreto, seguem os programas A, B:

A:

#include <unistd.h>
#include <stdio.h>

int main(){
  char a[3];
  fgets(a, 3, stdin);
  printf("%s\n", a);
  char* args[] = {NULL};
  execv("./read2", args);
}

B:

#include <stdio.h>

int main(){
   char a[] = "hy";
   fgets(a, 3, stdin);
   printf("%s\n", a);
}

Quando executo como echo 'abcd' | ./A , esperava a seguinte saída

ab
cd

Mas eu recebo     ab     hy

Por que o B não está lendo a entrada padrão?

    
por nitishch 04.04.2017 / 17:50

1 resposta

4

TLDR: o pai DEVE usar IO sem buffer se o processo subseqüente precisar ler exatamente de onde o pai parou.

Com E / S não armazenado em buffer, o programa se comporta corretamente:

#include <stdio.h>
#include <string.h>
#include <unistd.h>

char buf[3];

int main(int argc, char *argv[])
{
    read(STDIN_FILENO, buf, 2);
    printf("%s '%s'\n", *argv, buf);
    if (strcmp(*argv, "./childtu") == 0) return 0;
    execl("./readtwo", "./childtu", (char *) 0);
}

Como executado via

$ make readtwo            
cc     readtwo.c   -o readtwo
$ echo abcdefg | ./readtwo
./readtwo 'ab'
./childtu 'cd'
$ 

O IO com buffer (via fgets ) no pai é o problema, pois o filho só conseguirá ler a partir da entrada padrão se houver mais entrada do que o pai lê antecipadamente:

#include <stdio.h>
#include <string.h>
#include <unistd.h>

char buf[3];

int main(int argc, char *argv[])
{
    fgets(buf, 3, stdin);
    printf("%s '%s'\n", *argv, buf);
    if (strcmp(*argv, "./childtu") == 0) return 0;
    execl("./readtwo", "./childtu", (char *) 0);
}

Se algum curioso puder procurar binário pelo tamanho exato do buffer, ou ver o que está configurado no kernel:

$ perl -e 'print(("a")x99999)' | ./readtwo
./readtwo 'aa'
./childtu 'aa'
$ 

Com strace (ou similar), podemos observar quanto o processo pai read s da entrada padrão (fd 0):

$ echo asdf | strace -o blah ./readtwo
./readtwo 'as'
./childtu ''
$ fgrep 'read(0' blah
read(0, "asdf\n", 4096)                 = 5
read(0, "", 4096)                       = 0
$

Aqui, o pai queria 4096 bytes (mas só tem cinco), e o processo exec 'd tem zero, pois não sobra nada. Portanto, não use uma leitura em buffer no processo pai se isso for um problema.

    
por 04.04.2017 / 18:08

Tags