dup2 / dup - por que eu preciso duplicar um descritor de arquivo?


85

Estou tentando entender o uso de dup2e dup.

Na página de manual:

Por que eu precisaria dessa chamada de sistema? qual é a utilidade de duplicar o descritor de arquivo?

Se eu tiver o descritor de arquivo, por que desejaria fazer uma cópia dele?

Eu apreciaria se você pudesse me explicar e me dar um exemplo onde dup2/ dupé necessário.

obrigado


Como você implementaria a funcionalidade de tubulação de shells sem dupou dup2? Você precisa ligar pipe(2)e, em seguida, ter um dos descritores de arquivo dup-ed para, por exemploSTDIN_FILENO
Basile Starynkevitch

Respostas:


48

A chamada de sistema dup duplica um descritor de arquivo existente, retornando um novo que se refere ao mesmo objeto de E / S subjacente.

O Dup permite que os shells implementem comandos como este:

O 2> & 1 diz ao shell para fornecer ao comando um descritor de arquivo 2 que é uma duplicata do descritor 1. (isto é, stderr & stdout apontam para o mesmo fd).
Agora a mensagem de erro para chamar ls em um arquivo não existente e a saída correta de ls em um arquivo existente aparecem no arquivo tmp1 .

O código de exemplo a seguir executa o programa wc com a entrada padrão conectada à extremidade de leitura de um tubo.

O filho copia a extremidade de leitura para o descritor de arquivo 0, fecha o arquivo de scriptors em p e execs wc. Quando o wc lê a partir de sua entrada padrão, ele lê a partir do tubo.
É assim que os pipes são implementados usando dup, bem, esse uso de dup agora você usa o pipe para construir outra coisa, essa é a beleza das chamadas do sistema, você constrói uma coisa após a outra usando ferramentas que já estão lá, essas ferramentas foram construídas internamente usando algo mais e assim por diante .. No final, as chamadas de sistema são as ferramentas mais básicas que você obtém no kernel

Felicidades :)


1
Portanto, dupé útil para o chamador e não para o lsprograma em si? Existe algum benefício em ter dupusado um programa como o próprio ls se já tiver acesso ao arquivo? Aqui, por exemplo, lsgrava erros 2que são codificados, então tenho uma maneira de substituí-lo como consumidor de ls. Acho que é um ponto sutil, não?
Nishant

3
Seu programa de exemplo parece ter um bug; você está ligando, dup(p[STDIN])mas depois jogando fora o resultado. Você quis dizer usar dup2(p[STDIN], 0)?
Quuxplusone

1
@Quuxplusone dupretorna o "descritor de menor número atualmente não em uso pelo processo." Como fd 0 acabou de ser fechado, dupdeve retornar 0. dup2é explícito sobre qual fd deve ser usado, em vez de apenas usar o fd livre mais baixo, então eu preferiria isso.
Wodin

@Wodin: Ah, aposto que você está certo sobre o que OP estava pensando. Eu também estou certo, porém, que "recém-fechado" é relativo, e o código do OP pode quebrar na presença de, por exemplo, threads simultâneos que podem estar abrindo arquivos também?
Quuxplusone

@Quuxplusone Suspeito que você esteja certo, mas não tenho certeza. Mas, nesse caso, você terá outros problemas. Se você fechar o stdin porque deseja ler de outro lugar e outro thread abrir um arquivo antes de você, ele obterá fd 0. Se você usar dup2, ele fechará o fd que o outro thread abriu, para que o outro thread agora estará lendo (e gravando?) o arquivo que você abrir. De qualquer forma, se bem me lembro, você não deve ligar exec*de um processo multithread. Mas eu não sou um especialista em threading :)
Wodin

18

Outra razão para duplicar um descritor de arquivo é usá-lo com fdopen. fclosefecha o descritor de arquivo que foi passado fdopen, portanto, se você não quiser que o descritor de arquivo original seja fechado, é necessário duplicá-lo dupprimeiro.


fdopen()parece não duplicar um descritor de arquivo, ele apenas cria um buffer no espaço do usuário.
Trump 2020 - Justiça virá

3
Você interpretou mal minha resposta. A questão é que você pode querer dupfd antes de passá-lo para, fdopenpois fcloseirá fechá-lo.
R .. GitHub PARAR DE AJUDAR O ICE

1
@ theferrit32: Se você alocar um FILEidentificador para acessar um arquivo aberto preexistente por meio de interfaces stdio, será necessário chamar fclosepara desalocar esse FILEidentificador. Se você quiser continuar usando o arquivo aberto subjacente, ou se sua arquitetura de software for tal que o código do "proprietário" original para o descritor de arquivo o fará close, o fato de fclosetambém fechar o descritor de arquivo subjacente que você entregou fdopené um problema. Você pode evitar esse problema usando duppara fazer um novo descritor de arquivo para o mesmo arquivo aberto passar fdopen, de modo que fclosenão feche o original.
R .. GitHub PARAR DE AJUDAR O ICE

1
O ponto é que fdopen () move a propriedade do fd para o FILE, ao invés de copiá- lo. Isso é algo que os usuários devem estar cientes. Os consumidores que precisam reter um fdidentificador utilizável além do FILEobjeto devem duplicar o fd. Isso é tudo.
Conrad Meyer

1
@ConradMeyer: Sim, é uma boa maneira de colocar as coisas, com uma observação de que não há nenhuma operação para "mover a propriedade" para longe do FILE depois que você transfere a propriedade para ele.
R .. GitHub PARAR DE AJUDAR O ICE

4

dup é usado para redirecionar a saída de um processo.

Por exemplo, se você deseja salvar a saída de um processo, duplica a saída (fd = 1), redireciona o fd duplicado para um arquivo, bifurca e executa o processo e, quando o processo termina, redireciona novamente o salvou o fd na saída.


4

Alguns pontos relacionados a dup / dup2 podem ser observados, por favor

dup / dup2 - Tecnicamente, o objetivo é compartilhar uma entrada de tabela de arquivo dentro de um único processo por meio de diferentes identificadores. (Se estivermos bifurcando, o descritor é duplicado por padrão no processo filho e a entrada da tabela de arquivos também é compartilhada).

Isso significa que podemos ter mais de um descritor de arquivo com atributos possivelmente diferentes para uma única entrada de tabela de arquivo aberta usando a função dup / dup2.

(Embora atualmente pareça apenas o sinalizador FD_CLOEXEC é o único atributo para um descritor de arquivo).

http://www.gnu.org/software/libc/manual/html_node/Descriptor-Flags.html

As diferenças são (para o último) - Exceto por algum valor errno entre dup2 e fcntl close seguido por fcntl pode aumentar as condições de corrida, pois duas chamadas de função estão envolvidas.

Os detalhes podem ser verificados em http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html

Um exemplo de uso -

Um exemplo interessante durante a implementação de controle de trabalho em um shell, onde o uso de dup / dup2 pode ser visto .. no link abaixo

http://www.gnu.org/software/libc/manual/html_node/Launching-Jobs.html#Launching-Jobs

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.