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

Linux Discussion :

Les pseudo-terminaux sous *nix


Sujet :

Linux

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 10
    Par défaut Les pseudo-terminaux sous *nix
    Bonjour,

    Je me suis mis en tête de programmer un émulateur de terminal en C.
    J'ai tout d'abord simplement penser qu'il suffisait d'un popen sur un shell et d'afficher tout ça.
    J'ai regardé les sources de rxvt et de xterm. Apparement c'est un peu plus compliqué : il faut ouvrir un pseudo-terminal libre (ces fameux "ttyXX" qui traine partout dans /dev). J'ai lu le man de openpty et consort, mais je n'arrive toujours pas à comprendre à quoi correspondent les terminaux maîtres et esclaves, les relations qu'ils ont entre eux, etc. D'autant plus que le code de xterm/rxvt est un peu fouilli dût au fait que ce genre d'opération dépend *fortement* du système (comprendre: ya des #ifdef partout). Bref, help.

    En espérant que quelqu'un puisse me mettre sur la voie, merci.

  2. #2
    Membre Expert Avatar de nicolas.sitbon
    Profil pro
    Inscrit en
    Août 2007
    Messages
    2 015
    Détails du profil
    Informations personnelles :
    Âge : 42
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 2 015
    Par défaut
    http://www.gnu.org/software/libtool/..._002dTerminals
    Si tu ne comprends toujours pas dis le moi.
    Cordialement.

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 10
    Par défaut
    Merci, j'ai un peu avancé.
    Voici un petit programme test:

    EDIT: Attention programme faux, une version corrigée est donnée plus bas.

    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
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    #include <stdlib.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <string.h>
    #include <pty.h>
    #include <utmp.h>
    #include <ctype.h>
     
    void
    safe_print (char* s)
    {
        while(*s++) {
            if(*s == '\n')
                printf("\\n");
            else if(iscntrl(*s))
                printf("\\e(%d)", *s);
            else
                putchar(*s);
        }
    }
     
     
    int
    main (void)
    {
        char buf[BUFSIZ];
        int master;
        int ret = forkpty(&master, NULL, NULL, NULL);
     
        if(ret == -1)
            puts("no fork"), exit(0);
     
        if(!ret) { 
            execl("/bin/sh", "sh", NULL);
            exit(0);
        }
     
        write(master, "date\n", sizeof "date\n");
     
        while(1) {
            switch(ret = read(master, buf, BUFSIZ)) {
            case -1:
                puts("error!"); 
                exit(1);
                break;
            case 0:
                puts("rien.."), sleep(1);
                break;
            default:
                printf("slave output : <");
                safe_print(buf);
                puts(">");
            }
        }
     
        close(master);
     
        return 0;
    }
    j'obtiens ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    slave output : <date\e(13)\n^@>
    slave output : <$ te\e(13)\n^@>
    slave output : <Sun Jan 25 00:49:47 CET 2009\e(13)\n>
    slave output : <$ n Jan 25 00:49:47 CET 2009\e(13)\n>
    ^C


    EDIT:
    J'ai trouvé quelques bugs, code corrigé :
    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
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    #include <stdlib.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <string.h>
    #include <pty.h>
    #include <utmp.h>
    #include <ctype.h>
     
    void
    safe_print (char* s)
    {
        while(*s) { /* ne pas incrémenter s dès le départ ... */
            if(*s == '\n')
                printf("\\n");
            else if(iscntrl(*s))
                printf("\\e(%d)", *s);
            else
                putchar(*s);
            s++;
        }
    }
     
     
    int
    main (void)
    {
        char buf[BUFSIZ] = {0};
        int master;
        int ret = forkpty(&master, NULL, NULL, NULL);
     
        if(ret == -1)
            puts("no fork"), exit(0);
     
        if(!ret) { 
            execl("/bin/sh", "sh", NULL);
            exit(0);
        }
     
        sleep(1); /* on laisse le temps au shell de se lancer, toussa */
     
        #define CMD "date"
        write(master, CMD "\n", sizeof(CMD "\n" ));
     
        while(1) {
            switch(ret = read(master, buf, BUFSIZ)) {
            case -1:
                puts("error!"); 
                exit(1);
                break;
            case 0:
                puts("rien.."), sleep(1);
                break;
            default:
                buf[ret] = '\0'; /* c'est un buffer, pas une string : le
                                    shell ne sait pas quand je lis..     */
     
                printf("slave output : <");
                safe_print(buf);
                puts(">");
            }
        }
     
        close(master);
     
        return 0;
    }
    Sortie correspondante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    slave output : <$ date\e(13)\n^@Sun Jan 25 15:20:42 CET 2009\e(13)\n>
    slave output : <$ >
    ^C
    Bon, tout ce que j'écris dans le master est envoyé dans slave. OK.
    Je reconnais le \r\n (\e(13)\n), mais c'est quoi ce ^@ ?

    master est la stdin/stdout du terminal selon que j'écris ou lis dedans si j'ai bien compris. Que devient la stderr ?

  4. #4
    Membre du Club
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 10
    Par défaut
    bump.

    Je viens de comprendre que c'est le shell qui gère la stderr, il se trouve qu'il l'affiche sur la même sortie que la stdout, du coté du master il n'y donc aucune différence..

    Ma question sur le ^@ subsiste toujours par contre.

  5. #5
    Membre confirmé Avatar de loupapet
    Homme Profil pro
    Retraité d'Eurocopter
    Inscrit en
    Janvier 2009
    Messages
    69
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 84
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité d'Eurocopter
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Janvier 2009
    Messages : 69
    Par défaut
    Bonjour Aaptel, bonjour Nicolas.Sitbon

    Je me permets d'intervenir dans vos échanges sur les pseudo-terminaux car, moi aussi, je travaille sur cette possibilité pour encapsuler une commande comme je l'ai demandée dans mon message intitulé
    "Écriture d'une fonction d'encapsulation ("Front End")"
    Nouvel arrivant dans le forum, on ne peut pas dire que l'accueil a été chaleureux car le modérateur m'a rembarré en me reprochant de demander aux autres de faire mon travail !!... Drôle de conception de l'aide pour un modérateur car, par principe, aider quelqu'un qui ne sait pas comment agir c'est justement faire en quelque sorte un peu son travail par quelqu'un qui sait en attendant en plus des explications et ça c'est le côté pédagogique. Mais bon, il a l'air d'ignorer tout ça !... zéro pointé pour lui !.... Pardon pour ma petite parenthèse.

    J'ai donc repris votre exemple qui ne traite que le flux de sortie de l'esclave pour y ajouter une "tentative de dialogue" bi-directionnel et je me heurte au même problème que celui que j'ai rencontré dans ma demande d'origine et qui n'est toujours pas résolu comme je l'avais cru un moment.

    Finalement, Aaptel, ne cherchons-nous pas tous les deux à trouver une solution au même problème pour réaliser, vous votre émulateur, et moi mon encapsulation ?

    A vous Aaptel et vous Nicolas.Sitbon qui êtes expérimenté, si vous me le permettez, je joins ce que j'ai fait, de mon côté, en espérant que cela ne sera pas encore interprété injustement par le modérateur comme une demande à autrui de faire mon travail... Je suis à la retraite et je fais cela pour m'amuser et pour rendre service à un professeur de mathématiques si c'est possible bien entendu !!....

    1°) - Le programme-console à encapsuler que j'ai appelé "mon_programme" :

    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
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    /*******************************************************************************
      Prototype de programme à encapsuler : 
            il simule le dialogue stdin-stdout d'une application console
    *******************************************************************************/
    int main (int argc, char **argv)
    { 
      char buffer[10], *resp ;
      int  i,n ;
     
      printf ("Prototype de programme-console...\n") ;
      printf ("Test avec la ligne 1...\n") ;
      printf ("Test avec la ligne 2...\n") ;
      printf ("Test avec la ligne 3...\n") ;
      printf ("Test avec la ligne 4...\n") ;
     
      while (1)
      { printf ("mpgm=>") ;
        resp = fgets(buffer,sizeof(buffer),stdin) ;              // lecture commande
        resp[strlen(resp)-1] = '\0' ;                                // on enlève NL
     
        if (strcmp(resp,"quit") == 0) break ;                           // terminé
        n = atoi(resp) ;                               // nombre de ligne à afficher
        if (n == 0) n = 1 ;
        for (i=0 ; i<n ; i++) fprintf (stdout,"ligne %d\n",i) ;        // on affiche
      }
    }
    qui donne le dialogue suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    loupapet@loupapet-laptop:/media/Jean-Pierre/Dvlp/ENCAPS$ mon_programme
    Prototype de programme-console...
    Test avec la ligne 1...
    Test avec la ligne 2...
    Test avec la ligne 3...
    Test avec la ligne 4...
    mpgm=>2
    ligne 0
    ligne 1
    mpgm=>1
    ligne 0
    mpgm=>quit
    loupapet@loupapet-laptop:/media/Jean-Pierre/Dvlp/ENCAPS$
    2°) - Le programme-encapsuleur que j'ai appelé "t_encaps" :

    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
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    /*******************************************************************************
                                       Système d'exploitation : Ubuntu Intrepid Ibex
    *******************************************************************************/
    #include <stdio.h>
    #include <errno.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <time.h>
     
    /*******************************************************************************
                             Point d'entrée de la fonction
    *******************************************************************************/
    int main (int argc, char **argv, char **env)
    {
     
      int           pt_maitre  ;    // descripteur de fichier pseudo-terminal maître
      int           pt_esclave ;   // descripteur de fichier pseudo-terminal esclave
      int           pid ;                                    // id du processus fork
      unsigned char buffer[2048], ligne[512], auxligne[512] ;
      int           i, ier, ip, necho ;
     
    //******************************************************************************
      pid = forkpty(&pt_maitre, &pt_esclave, NULL, NULL);
      printf ("exec forkpty\n") ;                            // clonage du processus
    //******************************************************************************
     
      switch(pid)
      { case -1 :
          goto ERR_01 ;
     
    //******************************************************************************
    //*************************** processus-fils ***********************************
    //******************************************************************************
        case 0 :
     
          execl("mon_programme", "mon_programme", NULL);
          goto ERR_02 ;    
     
    //******************************************************************************
    //*************************** processus-père ***********************************
    //******************************************************************************
        default :
     
          //*** Le programme encapsulé envoie des lignes de compte-rendu et 
          //    un prompt pour aquérir une commande. Mais toutes les lignes sont
          //    bufferisées :
          ip = -1 ;                             // au départ, il faut lire l'esclave
          auxligne[0] = '\0' ;          // pas de buffer en echo à priori (**echo**)
     
          while(1) //****** protocole de dialogue avec le programme encapsulé ******
          { if (ip < 0)
            { 
              ENCORE :                                                 // (**echo**)
              sleep(1) ;  //============= !!!!!!!....... pour voir==================
              ier = read(pt_maitre, buffer, sizeof(ligne)) ;
              if (ier == -1) goto ERR_03 ;
              if (ier == 0 ) return (0) ;                                 // terminé
              buffer[ier] = '\0' ;                          // pour fermer la chaîne
              ip = 0 ;               // on positionne le pointeur au début du buffer
              if (auxligne[0] != '\0')                                 // (**echo**)
              { auxligne[0] = '\0' ;                                   // (**echo**)
                goto ENCORE ;                                          // (**echo**)
              }
            }
     
            // - On transfère la ligne jusqu'à un "\r\n" ;
              for (i=0 ; i<sizeof(ligne) ; i++)
              { if (buffer[ip] == '\0') break ;
                if (strncmp(&buffer[ip],"\r\n",2) != 0)           // "\r\n" trouvé ?
                { // non : // on alimente la ligne
                  ligne[i] = buffer[ip] ;
                  ip++ ;                  // on incrémente pour le caractère suivant
                }
                else
                { // oui : On prépare la ligne pour le traitement :
                  ligne[i] = '\0' ;                             // on ferme la ligne
                  ip +=2 ;                       // on ajuste l'index dans le buffer
                  goto TRAITEMENT ;
                }
              }
            // - Ici on a épuisé le buffer reçu :
              ligne[i] = '\0' ;                                 // on ferme la ligne
              ip = -1 ;                     // on marque qu'il faudra lire un buffer
     
    TRAITEMENT :
            printf ("=R=> %s\n",ligne) ;      // impression ligne reçue de l'esclave
     
          // - A-t-on reçu un prompt du programme encapsulé ? 
            if (strncmp(ligne , "mpgm=>" , 6) == 0)
            { printf ( "???? :" ) ;     // affichage du prompt-maitre
              scanf  ( "%s" , ligne) ;      // récuperation de la commande
     
              printf ("=L=> %s\n",ligne) ;
              strcpy(auxligne,ligne) ;   // préserve la ligne pour l'echo (**echo**)
     
          // - L'utilisateur a-t-il entré une commande de sortie du programme ?
          //   On teste aprés conversion en minuscule :
              if (ligne[0] == 'q') return (0) ;
     
              if(write(pt_maitre, ligne, strlen(ligne)) == -1) goto ERR_04 ;
              fsync(pt_maitre) ;
            }
          }
      }
      return 0 ;
     
    //==============================================================================
    ERR_01 : printf ("ERR_01 forkpty() : création processus-esclave\n") ;
             return (1) ;
    ERR_02 : printf ("ERR_02 execl() : lancement du programme encapsulé\n") ;
             return (2) ;
    ERR_03 : printf ("ERR_03 read() : peut pas recevoir de l'esclave\n") ;
             return (3) ;
    ERR_04 : printf ("ERR_04 write() : peut pas envoyer vers l'esclave\n") ;
             return (4) ;
    }
    2°) - Je vous fais part de mes remarques grâce à une session de debug :

    • On peut remarquer que le read sur le file descripteur du maitre reçoit aussi des lignes de son propre stdout comme l'indique le 'p buffer' où le texte "exec forkpty" s'est inséré au début du buffer (mis en caractères gras). Toutes les lignes sont bufferisées ce qui m'a obligé à insérer un petit code de dégroupage.


    • J'ai été amené à inséré aussi du code marqué (**echo**) dans le source car je n'ai pas réussi à positionner le mode noecho quand l'esclave lit son stdin.


    • Enfin une fois le nombre 22 entré pour afficher 22 lignes, le programme se bloque comme si le read sur le maitre n'était pas connecté au stdout du programme encapsulé.


    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
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    loupapet@loupapet-laptop:/media/Jean-Pierre/Dvlp/ENCAPS$ gdb t_encaps
    Copyright (C) 2008 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
    and "show warranty" for details.
    This GDB was configured as "i486-linux-gnu"...
    (gdb) b 59
    Breakpoint 1 at 0x80488eb: file t_encaps.c, line 59.
    (gdb) run
    Starting program: /media/Jean-Pierre/Dvlp/ENCAPS/t_encaps 
    exec forkpty
    
    Breakpoint 1, main (argc=1667594341, argv=0xbffbdd14, env=0xbffbdd1c)
        at t_encaps.c:59
    59	          ip = 0 ;               // on positionne le pointeur au début du buffer
    (gdb) p buffer
    $1 = "exec forkpty\r\nPrototype de programme-console...\r\nTest avec la ligne 1...\r\nTest avec la ligne 2...\r\nTest avec la ligne 3...\r\nTest avec la ligne 4...\r\nmpgm=>", '\0' <repeats 545 times>, "�\202��\230����\202��X���R���D\220߷\000\000\000\0004\000\000\000\022\b\000"...
    (gdb) c
    Continuing.
    =R=> exec forkpty
    =R=> Prototype de programme-console...
    =R=> Test avec la ligne 1...
    =R=> Test avec la ligne 2...
    =R=> Test avec la ligne 3...
    =R=> Test avec la ligne 4...
    =R=> mpgm=>
    ???? :23
    =L=> 23
    
    Breakpoint 1, main (argc=1660957490, argv=0xbffbdd14, env=0xbffbdd1c)
        at t_encaps.c:59
    59	          ip = 0 ;               // on positionne le pointeur au début du buffer
    (gdb) s
    60	          if (auxligne[0] != '\0')                                 // (**echo**)
    (gdb) 
    61	          { auxligne[0] = '\0' ;                                   // (**echo**)
    (gdb) 
    54	          sleep(1) ;  //============= !!!!!!!....... pour voir==================
    (gdb) 
    
    55	          ier = read(pt_maitre, buffer, sizeof(ligne)) ;
    (gdb) 
    
    
    
    ^C
    Program received signal SIGINT, Interrupt.
    0xb7fbe430 in __kernel_vsyscall ()
    (gdb) q
    The program is running.  Exit anyway? (y or n) y
    loupapet@loupapet-laptop:/media/Jean-Pierre/Dvlp/ENCAPS$
    Voilà, je vous livre mes réfléxions après force de lecture sur les pseudo-terminaux et l'épluchage assez laborieux des sources des commandes 'cgdb', 'xdbx', 'ddd' que de mon point de vue je trouve assez brouillon et un peu inextricable.

    J'espère que je n'ai pas été trop long dans mes explications. J'avoue ne pas trop comprendre ce qu'il ne va pas. Pourtant j'ai lu dans d'autres forums que c'était très facile. Peut-être que je ne suis pas assez compétent pour traiter ce sujet, pourtant assez simple dans son principe !...

    Vraiment, bien sincèrement, merci de vos éclairages si vous le voulez bien. De mon côté, je continue mes recherches tout en étant attentif à vos réactions et je suis prêt éventuellement à vous faire un feed back si je trouve quelque chose.

    Merci encore

  6. #6
    Membre du Club
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 10
    Par défaut
    Ok, j'ai pas mal farfouillé. J'ai étudié les sources de rxvt, j'ai lu et relu les pages de manuel.

    Tout se règle grâce au struct termios, qui décrivent les caractéristiques du terminal, et qui peut être passé en argument à forkpty/openpty ou bien utilisé directement avec tcsetattr.

    Les ^@ sont en réalité les caractères représentant la fin de l'input. (@ = 0 + 0x40 activé par le flag ECHOCTL : voir manuel)
    J'invite loupapet à bien lire la page de manuel de termios et tcsetattr.

    Il faut créer un struct termios, puis remplir convenablement les membres c_iflag, c_oflag et c_cc puis passer son adresse au fonctions cités plus haut.
    L'assignation des flags se fait comme d'habitude par des bitwise or :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    mode = FLAG1 | FLAG2 | FLAG3;
    Dans les flags d'output (o_flag) il y a notamment ECHO qui, lorsqu'il est fourni, affiche l'entrée tapée. Il suffit donc de ne pas le mettre pour avoir l'effet désiré par loupapet : je viens de tester, ça marche très bien.

    Je compléterai peut-être ce post d'un code exemple plus tard.

  7. #7
    Membre confirmé Avatar de loupapet
    Homme Profil pro
    Retraité d'Eurocopter
    Inscrit en
    Janvier 2009
    Messages
    69
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 84
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité d'Eurocopter
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Janvier 2009
    Messages : 69
    Par défaut
    Bonjour Aaptel,

    Le programme 't_encaps.c' que j'ai mentionné est une version élaguée qui donne les mêmes résultats que la version initiale que je fournis maintenant ci-après. J'utilisais déjà la structure 'termio' tout comme je l'avais fait dans ma première intervention
    "Écriture d'une fonction d'encapsulation ("Front End")"
    en m'inspirant du source de la commande 'xdbx".
    J'ai reconsulté ce source, j'ai essayé de pomper le plus intelligemment possible ce qui y était fait. Sans grand résultat. Je n'arrive pas à savoir ce petit peu qui manque, je pense, car la communication se fait au début et s'interrompt juste à la lecture de l'esclave qui suit un envoi.

    J'ai essayé de mettre un Termio dans le fortpty avec une préinitialisation de la structure juste avant. Sans grand succés non plus. J'avais déjà lu la doc du Termio. Sincèrement, je ne vois pas. Peut-être que je ne dois pas être trop doué puisque vous dites qu'il n'y a pas de problème !!!....

    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
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    /*******************************************************************************
                                       Système d'exploitation : Ubuntu Intrepid Ibex
    *******************************************************************************/
    #include <stdio.h>
    #include <errno.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <time.h>
    #include <fcntl.h>
    #include <termio.h>
     
    #define FILEDES_IN  0
    #define FILEDES_OUT 1
    #define FILEDES_ERR 2
     
    /*******************************************************************************
                             Point d'entrée de la fonction
    *******************************************************************************/
    int main (int argc, char **argv, char **env)
    { struct termio Termio;
      FILE         *fd_maitre ;              // pour pouvoir utiliser fgets et fputs
      int           pt_maitre  ;    // descripteur de fichier pseudo-terminal maître
      int           pt_esclave ;   // descripteur de fichier pseudo-terminal esclave
      int           pid ;                                 // id du processus forkpty
      int           pid_fils ;                               // id du processus-fils
      int           grpid ;                                      // group-id courant
      unsigned char buffer[2048], ligne[512], auxligne[512] ;
      int           i, ier, ip, necho ;
     
    /*** Reset du contrôle tty.  On fait cela maintenant pour qu'à l'ouverture
         de l'esclave et du maitre, la pty sélectée devienne la tty de contrôle : */
        if ((i = open("/dev/tty", O_RDWR)) > 0) {
    	ioctl(i, TIOCNOTTY, 0);
    	close(i);
        }
     
    //******************************************************************************
      pid = forkpty(&pt_maitre, &pt_esclave, NULL, NULL);
      printf ("exec forkpty\n") ;                            // clonage du processus
    //******************************************************************************
     
      switch(pid)
      { case -1 :
          goto ERR_01 ;
     
    //******************************************************************************
    //*************************** processus-fils ***********************************
    //******************************************************************************
     
    //*** Pour le moment, nous sommes dans le processus-fils 'pt_esclave' qui est
    //    un clone du processus-père et qui a hérité de tout son contexte en
    //    particulier :
    //      - le stdin  qu'il faut connecter au stdout du processus-père,
    //      - le stdout qu'il faut connecter au stdin  du processus-père,
    //      - le stderr qu'il faut connecter au stdin  du processus-père.
        case 0 :
          close(pt_maitre);    // pour avoir les mains libres dans les manipulations
          pid_fils = getpid() ;     // récupération du pid de notre processus (fils)
          printf ("pid du fils = %d\n", pid_fils) ;
     
    //*** On modifie le mode local et output du pty esclave :
          ioctl(pt_esclave, TCGETA, &Termio);
          Termio.c_lflag &= ~ECHO ;                                  // mode No echo
          Termio.c_oflag &= ~ONLCR ;    // on ne transcrit pas NL to CR-NL en sortie
          ioctl(pt_esclave, TCSETA, &Termio);
     
          dup2(pt_esclave, FILEDES_IN) ;                // pt_esclave devient stdin
          dup2(pt_esclave, FILEDES_OUT) ;               // pt_esclave devient stdout
          dup2(pt_esclave, FILEDES_ERR) ;               // pt_esclave devient stderr
     
    //*** Il faut que les nouvelles affectations appartiennent au groupe courant et
    //    au pid courant :
          ioctl(FILEDES_IN, TIOCGPGRP, &grpid) ; 
          setpgid(0,grpid) ;
     
          ioctl(FILEDES_IN, TIOCSPGRP, &pid_fils) ;
          setpgid(0,pid_fils);
     
    //*** Maintenant, on peut REMPLACER le processus courant par le programme à
    //    encapsuler : 
          execl("mon_programme", "mon_programme", NULL);
          goto ERR_02 ;    
     
    //******************************************************************************
    //*************************** processus-père ***********************************
    //******************************************************************************
        default :
     
          //*** Le programme encapsulé envoie des lignes de compte-rendu et 
          //    un prompt pour aquérir une commande. Mais toutes les lignes sont
          //    bufferisées :
          close(pt_esclave);
    	 fcntl(pt_maitre, F_SETFL, FNDELAY);
        	 fd_maitre = fdopen(pt_maitre, "r+");
    	 setlinebuf(fd_maitre);
     
          sleep(1) ;  //================ !!!!!!!....... ==================   
     
          while(1) //****** protocole de dialogue avec le programme encapsulé ******
          { 
          //*** Le programme encapsulé envoie des lignes de compte-rendu et 
          //    un prompt pour aquérir une commande :
            if((fgets(ligne, sizeof(ligne), fd_maitre)) == NULL) goto ERR_03 ;
     
            printf ("=R=> %s",ligne) ;
     
          // - A-t-on reçu un prompt du programme encapsulé ? 
            if (strncmp(ligne , "mpgm=>" , 6) == 0)
            { fprintf ( stdout , "???? :" ) ;     // affichage du prompt-maitre
              fscanf  ( stdin  , "%s" , ligne) ;      // récuperation de la commande
     
              printf ("=L=> %s\n",ligne) ;
     
          // - L'utilisateur a-t-il entré une commande de sortie du programme ?
          //   On teste aprés conversion en minuscule :
              if (ligne[0] == 'q') return (0) ;
     
              if((fputs(ligne, fd_maitre)) == EOF) goto ERR_04 ;
              fflush(fd_maitre) ;
            }
          }
      }
      return 0 ;
     
    //==============================================================================
    ERR_01 : printf ("ERR_01 forkpty() : création processus-esclave\n") ;
             return (1) ;
    ERR_02 : printf ("ERR_02 execl() : lancement du programme encapsulé\n") ;
             return (2) ;
    ERR_03 : printf ("ERR_03 fgets() : peut pas recevoir de l'esclave\n") ;
             return (3) ;
    ERR_04 : printf ("ERR_04 fputs() : peut pas envoyer vers l'esclave\n") ;
             return (4) ;
    }
    Encore merci de vos éclairages car cela rendrait bien service au professeur de mathématiques qui m'a sollicité.
    Bien cordialement.

  8. #8
    Membre confirmé Avatar de loupapet
    Homme Profil pro
    Retraité d'Eurocopter
    Inscrit en
    Janvier 2009
    Messages
    69
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 84
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité d'Eurocopter
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Janvier 2009
    Messages : 69
    Par défaut Plus de nouvelles !....
    Bonjour Aaptel,

    Je n'ai plus aucune nouvelle !... Auriez-vous réglé vos problèmes pour réaliser votre émulateur ?
    Je suis très intéressé de le savoir et de voir comment vous avez abouti dans l'utilisation des pseudo-terminaux.

    Moi aussi, j'ai farfouillé et farfouille pas mal, mais je suis toujours bloqué et sur ce domaine, je ne trouve pas d'éclairage en dehors des cas d'école qui sont proposés et qui n'ont pas trop grand chose à voir avec l'encapsulation de programme.

    Par ailleurs, j'ai une méthode que j'avais utilisée au début des années 80, les pseudo-terminaux n'existaient pas encore, en passant par un pilote caractère simple. Malheureusement, j'ai quelques difficultés à trouver les conventions de programmation de ce type de pilote sous Ubuntu. J'en ai trouvé pour d'autres distributions d'Unix. Je cherche vainement un prototype. Je ne fais pourtant pas de choses extraordinaires, je pense.

    En espérant que ce n'est pas râpé !....
    Cordialement.

  9. #9
    Membre du Club
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 10
    Par défaut
    Je suis assez occupé en ce moment.
    J'ai effectivement réglé mon problème de terminal, et la solution que j'ai proposé plus haut fonctionne. J'ai actuellement un terminal graphique basique fonctionnel bien que je n'y ai pas touché depuis un certain temps.

    Un article traitant des pseudo-terminaux a été publié sur unixgarden récemment, il peut être utile : http://www.unixgarden.com/index.php/...es-interactifs

Discussions similaires

  1. JailbreakMe 3.0 déverrouille les terminaux sous iOS 4.3.3
    Par Hinault Romaric dans le forum Apple
    Réponses: 17
    Dernier message: 26/07/2011, 13h35
  2. Instruction "les ax, sp" sous NT
    Par Eric Sigoillot dans le forum Assembleur
    Réponses: 3
    Dernier message: 12/08/2004, 19h14
  3. Les ports series sous linux...
    Par barucca dans le forum Matériel
    Réponses: 11
    Dernier message: 29/04/2004, 11h15
  4. [kdevelop]linker les lib openGL sous kdevelop
    Par bafman dans le forum OpenGL
    Réponses: 6
    Dernier message: 16/12/2003, 08h36
  5. retrouver les compsants FASTNET sous Delphi 7
    Par fandor7 dans le forum Composants VCL
    Réponses: 4
    Dernier message: 11/06/2003, 18h11

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