IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

POSIX C Discussion :

Récupérer code de sortie d'un multi-pipe


Sujet :

POSIX C

  1. #1
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2011
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2011
    Messages : 7
    Points : 5
    Points
    5
    Par défaut Récupérer code de sortie d'un multi-pipe
    Bonjour,
    Alors ça fait une semaine que je me prends la tête sur comment récupérer le code de sortie sur un pipe multiple.

    Admettons la commande : cmd1 | cmd2 | cmd3 |cmd4.

    Dans mon programme, je fais (dans le fils) :
    1. pipe
    2. fork
    3. dup
    3.1 appel récursif du point 1 jusqu'à arriver à la cmd4.
    3.2 exécution de la commande en cours (en partant de la 4 pour remonter
    à la 1)
    Du côté du père je fait un "wait4(pid, &status, 0 NULL);" (avec "status", un int déclaré un peu avant).
    Mon problème c'est que j'arrive à avoir le bon code de sortie si c'est cmd1 ou cmd2 qui s'exécute mal. Mais si c'est cmd3 qui se foire, je sais qu'il y a eu un problème (le message d'erreur s'affiche). Mais le code de sortie que me retourne le tout premier processus père est 0 (car la cmd1 s'est bien exécutée).
    Auriez-vous une solution ? Ce truc est en train de me rendre complètement fou

    Merci d'avance

  2. #2
    Membre éclairé
    Avatar de Pouet_forever
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    671
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 671
    Points : 842
    Points
    842
    Par défaut
    On peut avoir un code minimal qui reproduit le problème ?
    Plus tu pédales moins fort, moins t'avances plus vite.

  3. #3
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 371
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 371
    Points : 23 626
    Points
    23 626
    Par défaut
    Bonsoir,

    Citation Envoyé par Padawel Voir le message
    Auriez-vous une solution ? Ce truc est en train de me rendre complètement fou
    Tu tournes en rond parce que c'est en fait ton postulat de départ qui est faux. Lorsque tu lances un pipeline tel que « cmd1 | cmd2 | cmd3 | cmd4 » depuis un shell, celui-ci ne lance pas récursivement ces programmes, mais il les crée tous en parallèle. Ils sont donc frères, indépendant entre eux, et ont pour processus père le même shell.

    De la même façon que c'est en définitive la sortie standard du dernier programme (« cmd4 », en excluant la sortie d'erreur) qui apparaît sur ton écran, c'est le code de retour de ce même dernier programme qui sera renvoyé au shell (sauf option pipefail, au moins sous bash).

    C'est logique car les premiers programmes de la chaîne sont également les premiers à se terminer : si un programme en aval se termine avant qu'un rédacteur n'ait fini d'écrire, ce dernier recevra un SIGPIPE. En revanche, si un écrivain termine son travail et referme la sortie standard en mourant, cela se traduira par un simple EOF du côté du lecteur qui pourra donc se terminer proprement à son tour.

    À part cela, algorithmiquement, si tu as lancé toi-même et récursivement tes quatre processus, il appartient à chacun d'eux de propager le code de retour en faisant un return de la valeur retournée par wait.

  4. #4
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2011
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2011
    Messages : 7
    Points : 5
    Points
    5
    Par défaut
    Bonsoir,
    Tout d'abord merci énormément, en effet, en créant les processus parallèlement les uns aux autres (des frères quoi ), ça marche impeccablement.
    Cependant, quand je passe une une commande qui n'existe pas dans mon shell, j'obtiens un SIGPIPE.
    Y'a-t-il un moyen d'éviter les broken pipe ? Ou est-ce que ce comportement est normal pour un shell ?
    (Je travaille sous tcsh, et j'obtiens le même fonctionnement que le shell, mais j'aimerais, si possible, éviter d'avoir des broken pipe )

    Si c'est "non", c'est pas grave, c'est juste pour savoir si c'est faisable ou pas

  5. #5
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 371
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 371
    Points : 23 626
    Points
    23 626
    Par défaut
    Bonjour,

    Citation Envoyé par Padawel Voir le message
    Cependant, quand je passe une une commande qui n'existe pas dans mon shell, j'obtiens un SIGPIPE.
    Comme je te le dis, un SIGPIPE se produit lorsqu'un tube est brisé. C'est-à-dire soit lorsque le lecteur referme son tube avant l'écrivain, soit quand il se passe quelque chose sur le trajet et qui interrompt la connexion (dans le cadre d'une liaison réseau) et que cette chose peut être détectée (ce qui n'est pas forcé avec des liaisons par paquets). Il est donc normal de recevoir ce signal si jamais quelque tourne mal.

    À dire vrai, c'est fait exprès : si ton programme n'est pas explicitement écrit pour le prendre en charge, alors la réception de ce signal provoquera la mort du processus. C'est pratique parce si la chaîne est rompue, tous les programmes associés se terminent automatiquement, et heureusement !

    Le mieux que tu aies donc à faire est de ne pas t'en soucier du tout, ce qui devrait t'arranger. Si tu veux avoir le temps de faire une action donnée avant de mourir, tu peux intercepter ce signal en lui définissant un handler associé avec signal() ou sigaction(). Par contre, il ne faut pas utiliser ces dernières fonctions pour simplement ignorer le signal. Si tu le reçois intempestivement, c'est qu'il y a quelque chose de mal conçu en amont.

  6. #6
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2011
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2011
    Messages : 7
    Points : 5
    Points
    5
    Par défaut
    Je vais donc laisser les messages d'erreur si j'ai une commande du style : "ls -l | grep main | lol | cat -e".
    Est-ce que vous savez pourquoi j'obtiens un broken pipe sur "cat /dev/urandom | less" ? La commande étant valide, l'exécution se passe bien.. Alors pourquoi je reçois un SIGPIPE ?

  7. #7
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 371
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 371
    Points : 23 626
    Points
    23 626
    Par défaut
    Citation Envoyé par Padawel Voir le message
    Est-ce que vous savez pourquoi j'obtiens un broken pipe sur "cat /dev/urandom | less" ? La commande étant valide, l'exécution se passe bien.. Alors pourquoi je reçois un SIGPIPE ?
    Ça marche chez moi. Dans quel contexte reçois-tu ton SIGPIPE ?

  8. #8
    Futur Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2011
    Messages
    7
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2011
    Messages : 7
    Points : 5
    Points
    5
    Par défaut
    Sous tcsh, quand j'exécute la commande "cat /dev/urandom | less", l'exécution se passe bien, mais quand je quitte et je reviens à mon terminal, il m'affiche broken pipe.
    Je sais que dans certains cas, les développeurs des différents terminaux n'affichent pas le message. Possible que ce soit ton cas.

    EDIT :
    Ah non, au temps pour moi. Ca marche très bien chez moi aussi j'avais mal placé mes conditions
    Maintenant, j'ai un petit dilemme ^^'
    J'ai plus aucun problème avec des SIGPIPE.. mais du coup si je fais :
    "ls |cat -e | grep toto | wc && ls", sachant qu'il n'y a aucun fichier nommé toto, donc au niveau du grep il y une "erreur" et le "ls" après le "&&" ne devrait pas être exécuté. Cependant vu qu'il y a le "wc" après le "grep", je récupère le code de sortie de "wc qui lui s'exécute bien, et du coup l'exécution de la 2ème partie de la commande se fait alors qu'elle ne devrait pas.
    Comment faire pour signaler qu'il y a eu une erreur et arrêter l'exécution ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
     
    int              var;
     
    void            exec_cmd(t_binary *tree, t_execinf *info)
    {
      t_execvar     exe;
     
      if (tree && tree->flag != PIPE_F)
        xexecve(tree, info);
      else if (!tree || pipe(exe.p) == -1 || (exe.pid = fork()) == -1)
        exit(EXIT_FAILURE);
      if (!exe.pid)
        {
          if (close(exe.p[0]) == -1 || dup2(exe.p[1], STDOUT_FILENO) == -1)
            exit(EXIT_FAILURE);
          xexecve(tree, info);
        }
      else
        {
          if (close(exe.p[1]) == -1 || dup2(exe.p[0], STDIN_FILENO) == -1)
            exit(EXIT_FAILURE);
          while (exe.pid != (exe.ret = wait4(exe.pid, &var, WNOHANG, NULL)))
            if (exe.ret == -1)
              exec_cmd(tree->right, info);
          if (tree->right && !var)
            exec_cmd(tree->right, info);
          else
            exit(EXIT_FAILURE);
        }
    }
    Dans ce code, si je place la boucle de wait4 après le if... else..., j'ai aucun problème d'exécution, mais j'ai des problèmes pour récupérer le bon code de sortie (s'il y a eu une "erreur" durant l'exécution ou pas..).
    Mais si je laisse comme ça, c'est l'inverse
    Vous auriez un conseil à me donner ?

Discussions similaires

  1. Récupérer le code de sortie
    Par Ti-EN dans le forum Scripts/Batch
    Réponses: 2
    Dernier message: 19/08/2014, 23h05
  2. Réponses: 2
    Dernier message: 16/04/2014, 14h27
  3. Comment récupérer le code de sortie d'un service ?
    Par CleM_71 dans le forum Windows
    Réponses: 12
    Dernier message: 15/01/2009, 15h49
  4. récupérer le code de sortie d'un programme dans un c shell
    Par awalter1 dans le forum Shell et commandes GNU
    Réponses: 4
    Dernier message: 17/01/2008, 15h17
  5. Récupérer code HTML en JS.
    Par Kernel_Panic dans le forum Général JavaScript
    Réponses: 6
    Dernier message: 27/02/2006, 19h22

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo