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

C Discussion :

Utiliser ligne de commande Linux dans un programme C


Sujet :

C

  1. #1
    Membre habitué Avatar de zodd
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    276
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 276
    Points : 147
    Points
    147
    Par défaut Utiliser ligne de commande Linux dans un programme C
    Bonjour,

    Je cherche une solution pour utiliser une ligne de commande Linux directement dans mon programme.

    J'ai trouvé facilement comment lancer une commande avec:
    system("ma commande linux");

    Par contre je cherche à voir comment récupérer le résultat de la commande.

    J'ai entendu parlé d'utilisation de pipes avec fork() ou encore de socket mais je ne m'en suis jamais servi.

    De la même façon je compte lancer un démon qui en temps normal affiche des données lorsque nécessaire dans la console. J'aimerai donc aussi pouvoir "surveiller" ce démon pour récupérer les données renvoyées par celui-ci dans mon programme.

    J'ai bien pensé à faire un script qui renvoie les sorties de ces fonctions/programmes dans un fichier de log que je consulterai à intervalle régulier mais je trouve cette solution "capilotractée" ..
    Stay a while and listen...

  2. #2
    Expert éminent sénior
    Avatar de Kannagi
    Homme Profil pro
    cyber-paléontologue
    Inscrit en
    Mai 2010
    Messages
    3 214
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : cyber-paléontologue

    Informations forums :
    Inscription : Mai 2010
    Messages : 3 214
    Points : 10 140
    Points
    10 140
    Par défaut
    c'est popen que tu recherche ?
    http://www.lix.polytechnique.fr/~lib...ONS/popen.html

    Genre un exemple utilisation pour récupérer ls
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
        FILE *fichier;
        char chaine[100];
     
        fichier = popen("ls","r");
     
     
        while(fgets(chaine, 100,fichier) != NULL)
            printf("%s",chaine);
     
     
     
        pclose(fichier);

  3. #3
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 368
    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 368
    Points : 23 620
    Points
    23 620
    Par défaut
    Citation Envoyé par zodd Voir le message
    Je cherche une solution pour utiliser une ligne de commande Linux directement dans mon programme.

    J'ai trouvé facilement comment lancer une commande avec:
    system("ma commande linux");
    C'est à cela qu'elle sert, effectivement.

    Par contre je cherche à voir comment récupérer le résultat de la commande.
    Si c'est simplement le code de retour qui t'intéresse, il est renvoyé directement par system() (ou « -1 » en cas d'erreur), ce qui rend cette fonction extrêmement simple d'utilisation. Par contre, si c'est la sortie standard du programme lancé qui t'intéresse, il va falloir procéder autrement.

    J'ai entendu parlé d'utilisation de pipes avec fork() ou encore de socket mais je ne m'en suis jamais servi.
    Regarde du côté de popen(). Le principe est le même : la fonction appelle un shell et lui passe la commande en argument, ce qui permet à celle-ci d'être relativement complexe si nécessaire. En retour, tu obtiens en revanche un descripteur de fichier. C'est à toi de préciser si tu veux que ce descripteur, et donc ton programme, soit relié à l'entrée standard ou à la sortie.

    De la même façon je compte lancer un démon qui en temps normal affiche des données lorsque nécessaire dans la console. J'aimerai donc aussi pouvoir "surveiller" ce démon pour récupérer les données renvoyées par celui-ci dans mon programme.

    J'ai bien pensé à faire un script qui renvoie les sorties de ces fonctions/programmes dans un fichier de log que je consulterai à intervalle régulier mais je trouve cette solution "capilotractée" ..
    Le mieux est un socket UNIX.

    Tu peux également choisir de t'appuyer sur DBus s'il est en place.

  4. #4
    Membre habitué Avatar de zodd
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    276
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 276
    Points : 147
    Points
    147
    Par défaut
    Merci pour vos réponses.

    popen() pourrait visiblement faire le boulot mais ça revient un peu au même que faire du log dans un fichier non? En gros je suis en train de comprendre que ouvrir un pipe revient à créer un fichier temporaire intermédiaire?

    Concernant systeme(), ce n'est pas que le code retour mais carrément la réponse complète de la commande. Par exemple dans le cas d'un ls -la , je voudrai récupérer ce qui s'affiche dans le terminal lorsque je fais cette commande. Cette méthode n'est donc pas suffisante d'après ce que je comprends et c'est là que popen() serait plus adapté je suppose..

    Je n'ai jamais mis en oeuvre de socket UNIX (mise à part ce de mes cartes réseaux), ni Dbus.. je vais essayer de me documenter à ce sujet..

    Juste au cas où, j'aimerai essayer de trouver une solution qui puisse être "portable", dans la mesure du possible, sous windows car la commande/démon que je souhaite utiliser sous Linux existe aussi sous forme de service sous windows.

    Edit: concernant le descripteur de fichier en retour de popen(), tu dis qu'on peut le relié à l'entrée standard ou à la sortie. Je n'ai pas bien compris ce que tu veux dire par là? Dans mon cas il s'agirait de la sortie stdout..?
    Stay a while and listen...

  5. #5
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 368
    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 368
    Points : 23 620
    Points
    23 620
    Par défaut
    Citation Envoyé par zodd Voir le message
    popen() pourrait visiblement faire le boulot mais ça revient un peu au même que faire du log dans un fichier non? En gros je suis en train de comprendre que ouvrir un pipe revient à créer un fichier temporaire intermédiaire?
    Pas tout-à-fait : quand tu disposes d'un descripteur de fichiers, celui correspond en temps normal à… un fichier, on s'en serait douté, mais il s'agit surtout d'un flux de données. Lorsque tu crées un tube avec pipe(), le système te renvoie une paire de descripteurs de fichiers, l'un en écriture, l'autre en écriture. Et tout ce qui est envoyé dans le premier est automatiquement redirigé vers le second sans passer par le disque, avec une mémoire tampon de 4 Kio par défaut.

    Quand tu utilises popen(), cette fonction crée un tube, puis « forke » pour créer un processus fils qui hérite de sa paire de descripteur et remappe l'un d'eux sur l'entrée ou la sortie standard, de sorte que le processus à lancer ne s'apercevra pas que c'est en fait dans ce tube qu'il écrit. Du côté du processus père, la fonction te rend la main en te renvoyant l'autre descripteur.

    Juste au cas où, j'aimerai essayer de trouver une solution qui puisse être "portable", dans la mesure du possible, sous windows car la commande/démon que je souhaite utiliser sous Linux existe aussi sous forme de service sous windows.
    Dans ce cas-là, tu peux définir une interface commune mais les infrastructures proposées par les deux systèmes sont assez différentes.

    Edit: concernant le descripteur de fichier en retour de popen(), tu dis qu'on peut le relié à l'entrée standard ou à la sortie. Je n'ai pas bien compris ce que tu veux dire par là? Dans mon cas il s'agirait de la sortie stdout..?
    Chaque fois que tu lances un programme, son processus naît avec trois fichiers déjà ouverts, qui portent les numéros 0, 1 et 2 dans la liste des descripteurs Unix et qui sont nommés « stdin », « stdout » et « stderr » dans la norme C (ces derniers référencent tous une structure FILE *). Ils correspondent aux fichiers qui sont lus ou écrits lorsque tu utilises une fonction sans passer de descripteur explicite. Chaque fois que tu écris « printf ("Bonjour"); », par exemple, la chaîne est en fait envoyée vers stdout.

    Il se trouve que ces fichiers peuvent être fermés s'ils sont inutiles, comme des fichiers ordinaires, et que leur descripteur peut éventuellement être remplacé par un autre. En le remplaçant justement par le descripteur d'un tube que l'on a préalablement ouvert, on redirige les entrées et sorties standards vers là où on veut qu'elles aillent. Et popen() se charge de faire tout cela pour toi.

    Le programme de Kannagi fait exactement ce que tu cherches à faire : il exécute « ls » puis récupère le résultat ligne par ligne avant de les afficher lui-même.

  6. #6
    Membre habitué Avatar de zodd
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    276
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 276
    Points : 147
    Points
    147
    Par défaut
    Merci pour ta réponse. ça devient plus clair. Je vais approfondir ce sujet qui me semble incontournable sous Linux car c'est bien pratique^^
    Et je vais partir du code de kannagi et de son lien pour mettre tout ça en pratique
    Stay a while and listen...

  7. #7
    Membre habitué Avatar de zodd
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    276
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 276
    Points : 147
    Points
    147
    Par défaut
    Alors je viens de tester popen(), c'est vraiment excellent !

    Par contre comment ça se passe si je ne sais pas quand est ce que le retour est sensé arriver? Par exemple j'ouvre un pipe avec popen(), je lance un démon, et à partir de là je suis susceptible de recevoir des données sur ce pipe durant toute la durée d'exécution du programme; En gros je ne peut pas rester dans le while, comment récupérer le flux ailleurs?

    Pour l'instant ma seule idée est de faire une commande spéciale pour faire écrire ma commande dans un fichier un peut comme ça:

    system("ls >>foo");

    Mais là ça oblige à nouveau à consulter régulièrement le contenu du fichier.

    En gros ma nouvelle question est en fait comment récupérer la sortie d'un démon..
    Stay a while and listen...

  8. #8
    Membre émérite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2008
    Messages
    1 515
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 515
    Points : 2 505
    Points
    2 505
    Par défaut
    Difficile de réponde sans savoir ce que ton programme doit faire en dehors de scruter la sortie du démon. Mais as-tu déjà compris qu'un read() sur le pipe bloque tant que les données ne sont pas disponibles ?

    Donc en gros, si tout ce que fait ton programme est scruter la sortie du démon et prendre des actions quand des sorties sont produites, ça sera une boucle sur un read(). Quand des données deviennent disponibles sur le pipe le read retourne et tu peux prendre les actions nécessaires (faire un truc, ou éventuellement refaire un read car rien ne te garantie que toutes les données dont tu as besoin vont arriver en une fois).

    Si par contre ton programme doit faire d'autres choses en parallèle, c'est un peu plus compliqué. Soit tu créés un thread à part qui se chargera de scruter les données du pipe, soit tu poll le pipe régulièrement dans la boucle principale de ton programme. Pour poller le pipe tu peux soit faire des read() non bloquant, soit faire un select() avec un timeout nul (ou un poll() ou un epoll(), qui fonctionnent sur le même principe avec une API différente).

  9. #9
    Membre habitué Avatar de zodd
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    276
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 276
    Points : 147
    Points
    147
    Par défaut
    Alors oui mon programme doit faire quelque chose en même temps et donc je ne peux pas me permettre d'attendre que mon démon m'envoie quelque chose..

    là pour l'instant, comme j'utilise Qt, j'utilise le mécanisme des Signaux/SLOT à la place des threads et ça marche parfaitement.

    Mon dernier problème vient de comment espionner l'output d'un démon déjà lancé car du coup, je ne sais pas comment lui associer le pipe.
    Stay a while and listen...

  10. #10
    Membre expert
    Avatar de Metalman
    Homme Profil pro
    Enseignant-Chercheur
    Inscrit en
    Juin 2005
    Messages
    1 049
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Enseignant-Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 1 049
    Points : 3 532
    Points
    3 532
    Par défaut
    Là...il faut d'autres IPC "partagées" : MKFIFO, POSIX MQ, socket UNIX (il me semble), fichier partagé.... ou faire comme syslogd : un port d'écoute/écriture sur lequel faire transiter des infos.
    --
    Metalman !

    Attendez 5 mins après mes posts... les EDIT vont vite avec moi...
    Les flags de la vie : gcc -W -Wall -Werror -ansi -pedantic mes_sources.c
    gcc -Wall -Wextra -Werror -std=c99 -pedantic mes_sources.c
    (ANSI retire quelques fonctions comme strdup...)
    L'outil de la vie : valgrind --show-reachable=yes --leak-check=full ./mon_programme
    Et s'assurer que la logique est bonne "aussi" !

    Ma page Developpez.net

  11. #11
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 368
    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 368
    Points : 23 620
    Points
    23 620
    Par défaut
    Citation Envoyé par zodd Voir le message
    Alors je viens de tester popen(), c'est vraiment excellent !

    Par contre comment ça se passe si je ne sais pas quand est ce que le retour est sensé arriver? Par exemple j'ouvre un pipe avec popen(), je lance un démon, et à partir de là je suis susceptible de recevoir des données sur ce pipe durant toute la durée d'exécution du programme; En gros je ne peut pas rester dans le while, comment récupérer le flux ailleurs?
    Tu mélange plusieurs choses, mais admettons.

    Soit ton dæmon est réellement autonome et indépendant, qui doit vivre sa vie indépendamment des processus avec lesquels il doit être en contact et là, oui, tu utilises un fichier de log si tu as des données à y consigner à long terme. Sous UNIX, on les range en général dans /var/log. Si ce n'est déjà fait, va y faire un tour pour voir ce que l'on y trouve. Mais dans ce cas, l'administrateur de la machine concernée utilise un simple éditeur de texte pour les consulter, toujours indépendamment du programme qui les a engendrés.

    Soit ton dæmon produit des informations à la volée, éphémères, et qui n'ont de sens que pour son client. Dans ce cas, le client doit utiliser select() ou ses dérivées (poll(), ppoll()) pour surveiller plusieurs descripteurs de fichiers à la fois si c'est nécessaire et se débloquer dès que l'un d'eux propose quelque chose en lecture.

    Pour l'instant ma seule idée est de faire une commande spéciale pour faire écrire ma commande dans un fichier un peut comme ça:

    system("ls >>foo");

    Mais là ça oblige à nouveau à consulter régulièrement le contenu du fichier.
    Sache toutefois que system() est généralement bannie de toute projet qui se respecte et que popen() l'est presque tout autant parce qu'elles lancent le shell et, donc, dépendent toutes deux de l'extérieur. En plus, elles engendrent au moins deux processus supplémentaires : le shell lui-même et la commande à lancer.

    En gros ma nouvelle question est en fait comment récupérer la sortie d'un démon..
    Pour cela, il faut quand même mettre au clair un certain nombre de définitions puisque ce qui caractérise un daemon d'un processus, c'est le fait qu'il se place soi-même en arrière plan en se détachant de la session en cours ET de sa console de contrôle. Par définition, donc, un dæmon n'a plus d'entrée ni de sortie. Il reçoit d'ailleurs un signal s'il essaye de les exploiter quand même.

    Pour communiquer avec un dæmon, donc :

    • Soit tu crées un tube avec un pipe() avant de forker et tu l'utilises pour communiquer avec puisqu'il héritera des descripteurs ;
    • Soit tu utilises un « tube nommé » (cas de lpd, par exemple), qui va servir de point de rendez-vous entre deux programmes distincts lancés à des instants différents ;
    • Soit encore tu utilises un socket UNIX qui, en gros, est une extension du concept de tube nommé et qui permet à quiconque de se « connecter » à un nom de fichier comme tu te connecterais à une adresse IP et un port puis, de là, entrerais en relation avec le serveur qui se trouve en face.

  12. #12
    Membre habitué Avatar de zodd
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    276
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 276
    Points : 147
    Points
    147
    Par défaut
    Alors effectivement, le daemon que j'essaie de "poller" a pour sortie un fichier dans /var/log. ça doit faire une demie heure que j'essaie de "bricoler" avec "tail -f " pour récupérer les données dans mon programme.. mais clairement ce n'est pas la bonne solution..

    J'avoue que je n'ai aucune idée de comment lui associer un pipe de façon à forker dessus.

    Je ne crois pas qu'il ai de tube nommé, en consultant son man, en tout cas, je n'ai pas l'impression qu'il fasse autre chose que d'écrire dans le Log. Par contre il peut "forwarder" ce qui rentre vers un autre socket j'ai l'impression.

    je suppose, que le mieux serait donc de créer un socket UNIX de façon à me "connecter" à ce fichier de Log. Je vais essayer de fouiller pour voir comment faire ça car je n'ai jamais fait une telle chose avant..
    Stay a while and listen...

  13. #13
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 368
    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 368
    Points : 23 620
    Points
    23 620
    Par défaut
    Citation Envoyé par zodd Voir le message
    Alors effectivement, le daemon que j'essaie de "poller" a pour sortie un fichier dans /var/log. ça doit faire une demie heure que j'essaie de "bricoler" avec "tail -f " pour récupérer les données dans mon programme.. mais clairement ce n'est pas la bonne solution..

    J'avoue que je n'ai aucune idée de comment lui associer un pipe de façon à forker dessus.
    Attends, attends, attends. Tu veux dire que ce n'est pas TON dæmon ? Depuis le départ, tu nous parles d'écrire un programme qui exécute une commande de façon asynchrone, pas d'aller surveiller un logiciel déjà en production à l'heure actuelle.

    De quel programme s'agit-il ? Et quelles données cherches-tu à récupérer ?

    je suppose, que le mieux serait donc de créer un socket UNIX de façon à me "connecter" à ce fichier de Log. Je vais essayer de fouiller pour voir comment faire ça car je n'ai jamais fait une telle chose avant..
    Non, tu ne crées pas un socket pour te connecter à un fichier de log. Un socket est un point de connexion qui peut être associé à une adresse, et le domaine de ces adresses peut être soit le système de fichiers (sockets UNIX), soit celui des adresses réseau (c'est pour cela qu'encore aujourd'hui, c'est l'interface la plus utilisée pour exploiter ce réseau), mais également d'autres domaines comme Netlink, pour le noyau, etc.

    Si tu cherches juste à monitorer ce qui tombe dans le fichier de log, le mieux est effectivement tail -f. Si tu veux faire des traitements dessus en temps réel, tu peux remplacer le fichier de log (qui est actuellement un fichier ordinaire, donc) par un tube nommé qui portera le même nom au même endroit. Ce sera entièrement transparent pour ton dæmon qui écrira dedans de la même façon, sauf que tout ce qu'il y enverra sera redirigé vers le processus qui se met en lecture sur ce tube. Ça peut être simplement « cat » dans un premier temps, comme ça peut être un programme de ton propre cru.

    Attention à bien stopper le dæmon avant de remplacer le fichier (sinon, il continuera à garder un handle dessus et à le remplir même s'il a été effacé par rm), ainsi qu'à faire en sorte que ce que tu interceptes soit bien enregistré au final dans un autre fichier, sinon ces infos seront perdues après que tu les aies traitées.

  14. #14
    Membre habitué Avatar de zodd
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    276
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 276
    Points : 147
    Points
    147
    Par défaut
    Merci beaucoup pour tes explication. Je débute totalement dans ce domaine, c'est pourquoi c'est encore confus pour moi et j'ai tendance à mélanger certaines choses.

    Donc le daemon dont je veut intercepter la sortie est le démon snmptrapd fournit par net-snmp. Celui-ci enregistre tout les TRAP reçut dans un fichier de log /var/log/snmp/snmptrapd.log

    Le problème, c'est que pour l'instant je ne sais pas comment créer un tube nommé qui remplacera ce fichier et donc récupérer les données à la volée. C'est pour ça que j'ai tenté de trafiquer avec tail -f mais pour l'instant ça me "bloque" mon programme.. (j'ai était d'ailleurs obligé de changer les droits de tout les répertoire se trouvant sur le chemin du fichier log)..

    je vais essayer de voir en partant de ça : "cat file > my_pipe"

    Edit: alors j'ai réussi à utiliser un pipe avec cat dans la console comme cici:

    $ mkfifo my_pipe
    $ cat /var/log/snmp/snmptrapd.log > my_pipe

    et dans un autre shell :
    $ tail -f /var/log/snmp/my_pipe

    je vois bien ce qui était à l'origine dans snmptrapd.log.

    Mais par contre j'ai du mal à voir comment implémenter ça dans mon programme.
    Stay a while and listen...

  15. #15
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 368
    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 368
    Points : 23 620
    Points
    23 620
    Par défaut
    Citation Envoyé par zodd Voir le message
    Merci beaucoup pour tes explication. Je débute totalement dans ce domaine, c'est pourquoi c'est encore confus pour moi et j'ai tendance à mélanger certaines choses.
    Et c'est normal. Ce n'est pas forcément difficile ni très long à appréhender, mais il faut voir ces thèmes en entier et l'un après l'autre, sans essayer de courir plusieurs lièvres à la fois, sous peine de se retrouver dans une confusion totale et, au final, n'avoir rien acquis du tout.

    Voici une page Wikipédia qui recense un certain nombre de commandes UNIX usuelles : https://fr.wikipedia.org/wiki/Commandes_Unix

    Donc le daemon dont je veut intercepter la sortie est le démon snmptrapd fournit par net-snmp. Celui-ci enregistre tout les TRAP reçut dans un fichier de log /var/log/snmp/snmptrapd.log

    Le problème, c'est que pour l'instant je ne sais pas comment créer un tube nommé qui remplacera ce fichier et donc récupérer les données à la volée.
    C'est mknod nomdufichier p (« p » comme « pipe ») ou plus simplement mkfifo nomdufichier. Il faut effacer, déplacer ou renommer le fichier au préalable s'il existe déjà.

    C'est pour ça que j'ai tenté de trafiquer avec tail -f mais pour l'instant ça me "bloque" mon programme.. (j'ai était d'ailleurs obligé de changer les droits de tout les répertoire se trouvant sur le chemin du fichier log)..
    Il est possible que tu aies besoin des droits en lecture, effectivement. Mais ça ne devrait pas « bloquer » ton programme.

    je vais essayer de voir en partant de ça : "cat file > my_pipe"
    Regarde plutôt la man page en détails : comme pratiquement tous les dæmons, il est équipé d'une option qui lui demande justement de ne pas passer en arrière plan :

    Citation Envoyé par man snmptrapd
    -f
    Do not fork() from the calling shell.

    Il est également doté de l'option « -L » qui lui permet de savoir où il doit loguer ses informations : sortie standard, sortie d'erreur standard, fichier ou syslog. C'est « -Lo » pour lui demander d'orienter le tout vers la sortie standard.

    À ce stade, si tu es le seul à avoir besoin de ce programme et qu'il n'a pas besoin d'être en exploitation « normale » sur la machine où il tourne, tu peux te contenter de lancer :

    Code Shell : Sélectionner tout - Visualiser dans une fenêtre à part
    $ snmptrapd -f -Lo | ./tonprogramme

    Il te suffit alors de lire l'entrée standard normalement avec scanf() ou fgets(), voire même d'écrire un simple script shell. Les deux programmes prendront fin automatiquement dès que l'un d'eux se terminera pour une quelconque raison.

  16. #16
    Membre habitué Avatar de zodd
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    276
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 276
    Points : 147
    Points
    147
    Par défaut
    c'est cool ça avance bien ^^ merci encore

    Comme tu as pu le voir dans mon edit de mon message précédent, j'avais bien utilisé mkfifo pour créer mon pipe ^^

    Par contre mon programme doit fonctionner en exploitation "normal" ..

    Malgrè tout la commande :
    Ne me renvoie pas la même chose que ce qui s'écrivait dans le fichier de log mais ceci à la place:
    No access configuration - dropping trap.
    Je suppose que dans ce mode, le fichier de configuration appelé n'est pas le même...

    du coup j'ai pensé reprendre l'exemple de popen() comme cici:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
      FILE *fichier;
        char chaine[100];
     
        fichier = popen("snmptrapd -f -Lo","r");
     
     
        while(fgets(chaine, 100,fichier) != NULL)
            printf("%s",chaine);
     
     
     
        pclose(fichier);

    Qu'en penses tu? L'idéal serait quand même de réussir à comprendre comment faire ça avec un pipe nommé..
    Stay a while and listen...

  17. #17
    Membre éclairé
    Inscrit en
    Juillet 2012
    Messages
    231
    Détails du profil
    Informations forums :
    Inscription : Juillet 2012
    Messages : 231
    Points : 870
    Points
    870
    Par défaut
    Citation Envoyé par Obsidian Voir le message
    Si tu cherches juste à monitorer ce qui tombe dans le fichier de log, le mieux est effectivement tail -f.
    Perso, je partirai plutôt sur du inotify (si tant est que l’on reste sur du Linux bien sûr).

  18. #18
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 368
    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 368
    Points : 23 620
    Points
    23 620
    Par défaut
    Citation Envoyé par zodd Voir le message
    c'est cool ça avance bien ^^ merci encore

    Comme tu as pu le voir dans mon edit de mon message précédent, j'avais bien utilisé mkfifo pour créer mon pipe ^^
    C'est exact, mea culpa. J'avais sauté le message en question.

    Cela dit, ça ne pouvait pas marcher en l'état : cat lit le contenu d'un fichier qui a toujours une fin, même si ton dæmon y ajoute des choses, et l'envoie dans le tube. Dès que cat atteint la fin du fichier, il referme le tube et prend lui-même fin.

    Par contre mon programme doit fonctionner en exploitation "normal" ..
    Le plus « sage » sous Linux consisterait aujourd'hui à utiliser inotify pour être prévenu des changements appliqués à un fichier et pouvoir agir en conséquence. Ce n'est pas ce qu'il y a de plus propre en la situation, ni de plus portable, mais ça aurait le mérite de laisser tes traitements transparents vis-à-vis du reste du système et ton administrateur système apprécierait.

    Malgrè tout la commande :
    Ne me renvoie pas la même chose que ce qui s'écrivait dans le fichier de log mais ceci à la place:
    No access configuration - dropping trap.
    Ce n'est pas dû à notre manip' mais au fait qu'on lance le programme avec trop peu d'informations. Il faudrait au moins lui passer le chemin vers le fichier de config', j'imagine…

    du coup j'ai pensé reprendre l'exemple de popen() comme cici:

    Qu'en penses tu?
    Qu'en l'occurrence, tu ne gagnes absolument rien à lancer le programme toi-même. Ce programme est équivalent à la commande shell que je t'ai donnée, excepté le fait que c'est ton programme et pas le shell qui lance ton dæmon.

    j'aimerai quand même réussir à comprendre comment faire ça avec un pipe nommé..
    Essaie déjà de comprendre comment fonctionne un tube nommé, ce qui est extrêmement simple :

    • Ouvre deux terminaux sur ton écran, côte à côte ;
    • Assure-toi que tu te trouves dans le même répertoire de chaque côté ;
    • Crée un tube nommé avec mknod montube p ;
    • Saisis echo "Bonjour" > montube dans un des terminaux ;
    • Saisis ensuite cat montube dans l'autre terminal ;
    • Recommence en saisissant d'abord cat puis echo ;
    • N'oublie pas d'effacer le tube avec rm montube avant de refermer tes terminaux ;

  19. #19
    Membre habitué Avatar de zodd
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    276
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 276
    Points : 147
    Points
    147
    Par défaut
    A l'heure actuel je n'ai pas d'administrateur système. Je suis tout seul sur mon PC

    Pour le coup des chemins de configurations, j'ai trouvé il fallait ajouter ça :
    -c /etc/snmp/snmptrapd.conf

    Pour en revenir aux pipes, merci beaucoup pour ton petit exercice. Effectivement ça se comporte vraiment comme un fichier.. je peux même le voir avec ls, et j'ai enfin compris le mécanisme dans les deux sens, c'est vraiment impressionnant je trouve.

    Du coup j'ai créé un pipe snmptrapd.log à la place du fichier d'origine dont j'ai changé le nom.
    Et dans un terminal, je fais un :
    cat /var/log/snmp/snmptrapd.log

    et dans un autre je génère le trap:
    sudo snmptrap -v 2c -c public 127.0.0.1 "" .1.3.6.1.2.1.1.4.0

    et mon trap est bien affiché dans le terminal où j'ai fait le cat.
    (j'ai tout de même un truc bizarre car seul un trap sur deux est affiché et cat ne se ferme pas tout seul, je dois faire un ctrl+C).

    Mais si j'envoie le trap et que je fais le cat après, rien ne s'affiche alors que dans l'exemple avec le echo puis le cat, ça fonctionnait bien dans ce sens.

    Bon malgré ça j'ai essayé de faire la même chose dans mon programme.. j'ai donc programmé le code ci-dessous mais ça ne marche pas (un truc doit encore m'échapper, je vais fouiller du coté de fork()):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
        FILE *fichier;
        char chaine[100];
        fichier = popen("cat /var/log/snmp/snmptrapd.log","r");
     
     
        while(fgets(chaine, 100,fichier) != NULL)
        {
            affichage->append(QString(chaine));// printf("%s",chaine);
        }
     
     
        pclose(fichier);
    Stay a while and listen...

  20. #20
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 368
    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 368
    Points : 23 620
    Points
    23 620
    Par défaut
    Citation Envoyé par zodd Voir le message
    Pour le coup des chemins de configurations, j'ai trouvé il fallait ajouter ça : -c /etc/snmp/snmptrapd.conf
    C'est une bonne chose : ça veut dire que tu débutes mais que tu comprends vite et sais retrouver seul l'information qu'il te manque.

    Pour en revenir aux pipes, merci beaucoup pour ton petit exercice. Effectivement ça se comporte vraiment comme un fichier.. je peux même le voir avec ls, et j'ai enfin compris le mécanisme dans les deux sens,
    Tu as surtout dû remarquer que le premier des deux pairs reste en attente le temps que tu lances le second. Ce n'est pas anodin.

    c'est vraiment impressionnant je trouve.
    Et ce n'est que le début ! Tout UNIX est comme ça. Enfin, au moins sous sa forme traditionnelle car les UNIX libres, bien qu'excellents en eux-mêmes, servent aujourd'hui de plateforme pour y faire fonctionner des environnements de bureau (GNOME, par exemple) qui, eux, laissent beaucoup moins de latitude à leur utilisateur.

    Du coup j'ai créé un pipe snmptrapd.log à la place du fichier d'origine dont j'ai changé le nom.
    Et dans un terminal, je fais un :
    cat /var/log/snmp/snmptrapd.log

    et dans un autre je génère le trap:
    sudo snmptrap -v 2c -c public 127.0.0.1 "" .1.3.6.1.2.1.1.4.0

    et mon trap est bien affiché dans le terminal où j'ai fait le cat.
    (j'ai tout de même un truc bizarre car seul un trap sur deux est affiché et cat ne se ferme pas tout seul, je dois faire un ctrl+C).
    Tu as peut-être lancé plusieurs fois le même processus ou laissé tourner plusieurs clients en lecture sur le même tube. En outre, je ne vois pas l'option « -f » dans ta ligne de commande, donc snmptrap passe en arrière plan. Tu récupères la main dans ton terminal mais lui continue d'accaparer le tube et tant qu'il ne l'a pas refermé, il n'y a pas de raison pour que cat se termine de lui-même.

    Mais si j'envoie le trap et que je fais le cat après, rien ne s'affiche alors que dans l'exemple avec le echo puis le cat, ça fonctionnait bien dans ce sens.
    Essaie ps auxw | grep snmptrap pour voir combien tu en as lancés.

    Bon malgré ça j'ai essayé de faire la même chose dans mon programme.. j'ai donc programmé le code ci-dessous mais ça ne marche pas (un truc doit encore m'échapper, je vais fouiller du coté de fork()):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
        FILE *fichier;
        char chaine[100];
        fichier = popen("cat /var/log/snmp/snmptrapd.log","r");
     
     
        while(fgets(chaine, 100,fichier) != NULL)
        {
            affichage->append(QString(chaine));// printf("%s",chaine);
        }
     
     
        pclose(fichier);
    Là, pour le coup, faire un popen() sur « cat » ne sert vraiment à rien ! Si tu veux récupérer le contenu du fichier en lecture, alors il faut ouvrir le fichier, tout simplement :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
        fichier = fopen("/var/log/snmp/snmptrapd.log","r");

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 3 123 DernièreDernière

Discussions similaires

  1. Réponses: 12
    Dernier message: 03/12/2010, 16h08
  2. Utiliser des commandes linux dans un shell
    Par Info_76 dans le forum Shell et commandes GNU
    Réponses: 4
    Dernier message: 20/03/2008, 12h03
  3. [Système] Commande Linux dans Programme PHP
    Par makohsarah dans le forum Langage
    Réponses: 3
    Dernier message: 10/09/2007, 12h36
  4. utilisation des commandes shell dans un programme C
    Par rasgueados dans le forum Linux
    Réponses: 15
    Dernier message: 03/08/2006, 17h25
  5. Réponses: 2
    Dernier message: 24/06/2003, 20h31

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