Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 30/11/2015, à 15:06

DonutMan75

[RESOLU] [C] Exemple d'utilisation de la fonction dup()

Bonjour à tous,

j'essaie de faire fonctionner la fonction dup sur un exemple simple : un programme fork
- Le fils lance un ls et redirige sa sortie standard vers un tube anonyme
- Le père attend que son fils termine, redirige son entrée standard sur l'entrée du tube anonyme puis lance un wc -l

Comportement attendu : le nombre de fichiers du répertoire courant devrait s'afficher sur le terminal

Comportement obtenu : le programme "attend" (rien ne s'affiche et il faut faire Ctrl-C pour quitter).

Après quelques tests, il me semble que wc -l du père ne lit rien sur son entrée.... Avez-vous des idées ?

Merci d'avance smile


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


main()
	{

	int p[2];
	int pid, pid_ret, status;
	
	pipe(p);
	
	printf("Pipe ouvert\n\t- Lecture :\t%d\n\t- Ecriture :\t%d\n", p[0], p[1]);
	
	
	switch( (pid = fork()) )
		{
		case 0: // FILS

			close(STDOUT_FILENO);
			dup(p[1]); //Le premier descripteur libre (stdout) pointe maintenant vers p[1] (écriture dans tube anonyme)
			close(p[1]); // Desormais inutile

			execlp("ls", "ls", "-l", NULL);
			
			break;
		default: // PERE

			printf("Le PERE attend la fin du fils...\n");
			pid_ret = waitpid(pid, &status, 0);
			printf(" ok...\n");
			
			close(STDIN_FILENO);
			dup(p[0]); // Le premier descripteur libre (stdin) pointe maintenant vers p[0] (lecture depuis tube anonyme)
			close(p[0]);
			printf("Execution...\n");
			execlp("wc", "wc", "-l", NULL);
			
		}

	}

Dernière modification par DonutMan75 (Le 30/11/2015, à 18:59)

Hors ligne

#2 Le 30/11/2015, à 16:10

claudius01

Re : [RESOLU] [C] Exemple d'utilisation de la fonction dup()

Bonjour,

Tout d'abord, je ne comprends pas ton utilisation de dup() qui retourne normalement une copie du descripteur passé en argument.
Essaye dans un premier temps de tester le retour de dup() à des fins de tests ;-)...

cf. un exemple de dup (C System Call) (2nd exemple "You can also use dup() to redirect standard output by taking advantage of the fact that it always uses the smallest available file descriptor" ;-)

Edit: Si j'ai bien compris, tu souhaites faire:

$ ls -l | wc -l

avec le ls lancé par le fils et wc par le père...

A suivre...

Dernière modification par claudius01 (Le 30/11/2015, à 18:28)

Hors ligne

#3 Le 30/11/2015, à 18:39

DonutMan75

Re : [RESOLU] [C] Exemple d'utilisation de la fonction dup()

Bonjour Claudius,
merci pour ta réponse rapide.
En effet je cherche bien à reproduire

ls -l | wc -l

Mais ici :
- le fils lance ls
- le père attends la fin de son fils puis lance wc -l

J'ai lu avec beaucoup d'intérêt le lien que tu m'as donné et j'ai fais tourner (avec succès smile ) le code du deuxième exemple.
En fait, si j'ai bien compris, l'utilisation primaire de "int tata = dub(toto)" est de dupliquer le descripteur toto dans tata. La valeur de tata est le premier entier libre dans la table des descripteurs du processus.
Désormais un puts() n'écrira plus sur la sortie standard mais dans le fichier "output".

Dans le cas de mon code (en fait il est tiré du livre "Linux : Programmation système et réseau" de Joëlle Delacroix aux éditions Dunod, chapitre 7 page 218), il me semble qu'on fait exactement la même chose sauf qu'on lit/écrit dans un tube anonyme au lieu d'un fichier normal...

En clair les différentes étapes sont :

Initialisation (étape commune au père et au fils) : je crée un tube anonyme p
- p[0] = sortie du tube (lecture)
- p[1] = entrée du tube (écriture)

Les étapes du le fils (celui qui ECRIT dans le tube anonyme) :
1 - je ferme stdout (par convention stdout = 1)
2 - je duplique le descripteur p[1] : comme c'est la plus petite valeur libre qui lui sera affectée et que stdout est disponible alors stdout va pointer vers l'entrée du tube p
3 - j'écris quelque chose dans le tube (ici ls -l)

Les étapes du père (celui qui LIT dans le tube anonyme) :
1 - j'attends que mon fils se termine
2 - je ferme stdin (par convention stdin = 0)
3 - je duplique le descripteur p[0] : de la même façon, stdin va maintenant pointer vers la sortie du tube p
4 - j'écrase mon code avec exec("wc -l")

Mais j'ai l'impression que wc -l "attend" quelque chose avant d'afficher le résultat... C'est un peu comme si j'écrivais dans le shell

tail -f toto.txt | wc -l

Et je ne vois pas trop comment m'en sortir...

Hors ligne

#4 Le 30/11/2015, à 18:48

DonutMan75

Re : [RESOLU] [C] Exemple d'utilisation de la fonction dup()

Aaah j'ai trouvé !!!
En fait, tant que le nombre d'écrivains du tube n'est pas nul, il est toujours possible que quelqu'un vienne écrire dans le pipe.
Et donc wc lit la sortie du tube jusqu'à qu'il reçoive une fin de fichier. Cette fin de fichier n'est envoyée que lorsque le nombre d'écrivain est égal à 0.

Du côté du fils, tout est en règle car  il s'est terminé correctement. (même si un close(p[0]) en plus du close(p[1]) aurait été mieux)

Du côté du père en revanche, l'absence de close(p[1]) est déterminante ! Comme le père peut toujours écrire dans le tube, wc -l poireaute...
J'ai rajouté les close qu'il faut et tout marche nickel smile

Je remarque au passage que la commande ls -l | wc -l renvoie le même résultat que le schell MOINS DEUX (par exemple si ls -l | wc -l renvoie 50 dans mon schell, avec mon code C ça me renvoie 48...). Après examen, il se trouve que le execlp("ls", "ls", "-l", NULL); ne retourne ni "." ni ".."', curieux non ?

Merci et bonne soirée smile

Donut.

Dernière modification par DonutMan75 (Le 30/11/2015, à 18:50)

Hors ligne

#5 Le 30/11/2015, à 18:59

pingouinux

Re : [RESOLU] [C] Exemple d'utilisation de la fonction dup()

Bonjour,
Il est normal que ls -l ne retourne ni . ni ..
Pour les avoir, c'est ls -la

Hors ligne

#6 Le 30/11/2015, à 19:06

DonutMan75

Re : [RESOLU] [C] Exemple d'utilisation de la fonction dup()

Bonjour pingouinux,
ah bah tient oui, j'avais un alias dans mon bash_profile, tout s'explique !

alias ls='\ls -a'

Hors ligne

#7 Le 30/11/2015, à 19:10

claudius01

Re : [RESOLU] [C] Exemple d'utilisation de la fonction dup()

DonutMan75 a écrit :

... Aaah j'ai trouvé !!!

Bravo, entre temps et en mettant en œuvre ton programme j'ai trouvé si cela t’intéresse: Using dup2 for I/O Redirection and Pipes dont j'ai un peu modifié l'exemple 'pipe.c' comme suit pour rejoindre ton cas d'application; à savoir:

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

int main(int argc, char **argv)
{
  int pipefd[2];
  int pid;

  char *ll_args[] = {"ls", "-l", NULL};
  char *wc_args[] = {"wc", "-l", NULL};

  // make a pipe (fds go in pipefd[0] and pipefd[1])

  pipe(pipefd);
  pid = fork();
  if (pid == 0)
    {
      // child gets here and handles "wc -l"
      // replace standard input with input part of pipe
      dup2(pipefd[0], 0);

      // close unused hald of pipe
      close(pipefd[1]);

      // execute wc -l
      execvp("wc", wc_args);
    }
  else
    {
      // parent gets here and handles "ls -l"
      // replace standard output with output part of pipe
      dup2(pipefd[1], 1);

      // close unused unput half of pipe
      close(pipefd[0]);

      // execute ls -l
      execvp("ls", ll_args);
    }

  return 0;
}

et qui donne bien

$ gcc -Wall -o pipe pipe.c
$ ./pipe
$ 13
^C
$ ls -l | wc -l
13

NB: Une seule chose me chagrine, c'est l'obligation de faire un Ctrl^C ou un Carriage Return pour retrouver le prompt ;-(

Dernière modification par claudius01 (Le 30/11/2015, à 20:26)

Hors ligne