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 :

termcap et les signaux ?


Sujet :

C

  1. #1
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2014
    Messages
    84
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2014
    Messages : 84
    Points : 69
    Points
    69
    Par défaut termcap et les signaux ?
    Bonjour,

    Actuellement je fais un projet avec la bibliothèque termcap. Mon terminal est en mode non canonique :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    term.c_lflag &= ~(ICANON);
    term.c_lflag &= ~(ECHO);
    term.c_cc[VMIN] = 1;
    term.c_cc[VTIME] = 0;
    Cependant je bloque pour récupérer un signal :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    void          my_sigstp()
    {
         printf("Dedans\n");
    }
     
    void		my_manage_signal(void)
    {
           signal(SIGTSTP, my_sigstp);
    }
    La fonction my_sigstp n'est jamais exécuté... avez-vous une idée ? Je voudrais pouvoir faire un Ctrl + Z puis un fg sans problème... Merci.

  2. #2
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    26 860
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 860
    Points : 219 062
    Points
    219 062
    Billets dans le blog
    120
    Par défaut
    Bonjour,

    Je ne suis pas sur que vous ayez à gérer vous même le Ctrl+Z. Sinon, où est le code pour gérer la capture du signal ?
    De plus, pour être sur qu'une fonction est exécutée, autant utiliser un débogueur et un point d'arrêt au début de la fonction.
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  3. #3
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 372
    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 372
    Points : 23 628
    Points
    23 628
    Par défaut
    Bonjour,

    La prise en charge des signaux spéciaux envoyés au processus depuis le clavier n'est pas conditionnée au mode canonique, qui formellement concerne la discipline de ligne et les facilités d'édition avant envoi de la saisie au processus, mais par le flag ISIG dont il faut que tu vérifies l'état. En principe, il est actif par défaut et ton Ctrl-Z devrait fonctionner sans que tu aies à t'en soucier.

    Si ce flag est désactivé, tu ne recevras plus les signaux concernés (et donc, tu ne pourras plus interrompre un programme qui ne répond plus depuis la console où il s'exécute) mais tu recevras à la place le caractère correspondant à la combinaison de touches en question, soit 26 (ou 1A en hexadécimal) pour un Ctrl-Z, et cela même si tu as installé un gestionnaire de signal, puisque vu du processus, ces signaux peuvent venir de n'importe où et ne sont pas spécialement liés aux combinaisons clavier.

    En outre, il faut que ton programme appelle effectivement au moins une fois la fonction my_manage_signal() au début de son exécution pour que ton gestionnaire soit bien mis en place. Lance ton programme, ouvre un second terminal, trouve le PID de ton programme avec la commande ps, et envoie ton signal à la main avec « kill -SIGTSTP <pid> ». Ça te permettra de savoir si le gestionnaire fonctionne bien, indépendamment de l'état de la console.

  4. #4
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2014
    Messages
    84
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2014
    Messages : 84
    Points : 69
    Points
    69
    Par défaut Du progrès ... mais pas encore ça !
    Merci pour vos réponses.

    Je n'ai pas touché au flag ISIG car j'ai lu comme tu l'as dit que par défaut il est activé. J'ai essayé d'attraper d'autres signaux, SIGINT (Ctrl + C) fonctionne mais SIGTSTP ( Ctrl + Z ) ne réagit pas.

    En outre, il faut que ton programme appelle effectivement au moins une fois la fonction my_manage_signal() au début de son exécution pour que ton gestionnaire soit bien mis en place. Lance ton programme, ouvre un second terminal, trouve le PID de ton programme avec la commande ps, et envoie ton signal à la main avec « kill -SIGTSTP <pid> ». Ça te permettra de savoir si le gestionnaire fonctionne bien, indépendamment de l'état de la console.
    La fonction my_manage_signal() est bien appelée juste avant l'initialisation de mon terminal ( passage en mode non canonique ).
    J'ai essayé depuis un autre terminal d'envoyer le signal est il est bien capté dans ce cas :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    void my_manage_signal()
    {
          [...] //Des signaux
          signal(SIGTSTP, SIG_DFL);
    }
    Cependant, je dois exécuter un handler pour remettre le terminal dans son mode " canonique " par défaut :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
     
    void my_sigtstp()
    {
         printf("La fonction est charge...");
         my_restore_term(&env); //env contient une structure termios avec les paramètres par défaut.
    }
     
    void my_manage_signal()
    {
          [...] //Des signaux
          signal(SIGTSTP, my_sigtstp);
    }
    Dans le deuxième cas (celui qui m'interesse), ma fonction est bien exécutée mais le programme ne se « coupe pas » . J'ai donc essayé d'ajouter signal(SIGTSTP, SIG_DFL); dans my_sigtstp cependant cela ne fonctionne qu'au 2ème signal envoyé ... ( logique..). J'ai pas le droit à la fonction kill, sinon j'aurai envoyé moi même le signal ensuite, je vais voir du coté de ioctl() qui est autorisé.

    Concernant le fait que CTRL + C fonctionne mais pas CTRL + Z, il n'y a donc pas de raison que mon flag ISIG soit en cause... je ne sas pas de quel coté chercher.

  5. #5
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 372
    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 372
    Points : 23 628
    Points
    23 628
    Par défaut
    Je viens d'essayer chez moi et tout fonctionne comme attendu. Si, en plus, ton programme réagit correctement quand tu utilises kill depuis une autre console, c'est que pour une raison ou une autre, ton signal n'est pas envoyé. Il y a deux possibilités qui viennent immédiatement à l'esprit : soit d'autres flags entrent en conflit et provoquent un comportement inattendu (je ne vois pas lesquels a priori), soit la combinaison de touches utilisée pour provoquer un suspend n'est pas le Ctrl-Z habituel.

    Que donne un « stty -a » dans la console depuis laquelle tu utilises ton programme ?

  6. #6
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2014
    Messages
    84
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2014
    Messages : 84
    Points : 69
    Points
    69
    Par défaut
    Bonjour,

    Si, en plus, ton programme réagit correctement quand tu utilises kill depuis une autre console, c'est que pour une raison ou une autre, ton signal n'est pas envoyé.
    Effectivement, j'ai trouvé le problème, pour garder la "version" originale de la structure termios (fournie par tcgetattr()) je la sauvegardais attribut par attribut dans une autre structure ce qui provoquait des conflits, quoi qu'il en soit je n'y trouve plus d'intérêt à la conserver, je rétablis la structure ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    env->term->c_lflag |= (ICANON | ECHO);
    if (tcsetattr(0, TCSANOW, env->term) < 0)
    	my_puterror_fatal(M_ERR);
    Désormais Ctrl + Z est bien attrapé par my_manage_signal(), mais le problème n'est pas complètement résolu ( presque ^^). Le signal SIGTSTP doit me permettre de rétablir le Shell dans sa configuration initiale puis SIGCONT (fg depuis le Shell) me remettre mon shell dans l'état précédent afin d'y remettre l'execution là où il en était. J'ai réussi à obtenir le résultat voulu ainsi : (j'ai l'impression que c'est du bricolage... dis moi ce que tu en penses...)
    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
     
    static void	my_sigstp()
    {
    	char	cmd[2];
     
    	cmd[0] = env.term->c_cc[VSUSP]; //contient 26
    	cmd[1] = '\0';
    	my_restore_term(&env); //restaure terminal par defaut
    	signal(SIGTSTP, SIG_DFL); //Reconfigure SIGTSTP par son état par défaut
    	ioctl(0, TIOCSTI, cmd); //Ecrit le caractere 26 soit ctrl + Z afin de passer en bg (le problème c'est qu'il m'écrit réellement le caractère ^Z)
    }
     
    static void	my_sigcont()
    {
    	my_init_term(&env); //Reinitialise le term en mode non canonique
    	my_print_dlst(env.dlst->first); //Affiche le visuel là où il en était...
    	signal(SIGTSTP, my_sigstp); //Raccorde my_sigstp pour un prochain ctrl + Z
    }
     
    void		my_manage_signal(void)
    {
    	signal(SIGTSTP, my_sigstp);
    	signal(SIGCONT, my_sigcont);
    }
    Le problème est qu'il m'écrit le caractère ^Z (ioctl), as-tu une solution ? Je vais regarder s'il n'y a pas moyen de se débrouiller avec tsetattr()... Merci Obsidian.

  7. #7
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 372
    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 372
    Points : 23 628
    Points
    23 628
    Par défaut
    Bonjour,

    Oui, effectivement, relancer un signal et injecter artificiellement un caractère de saisie censé re-déclencher une nouvelle suspension, c'est assez sale dans le principe. Pour information, pourquoi sauvegardes-tu attribut par attribut l'état initial du terminal ? Pourquoi ne récupères-tu pas le tout dans une structure que tu conserverais en l'état pendant la durée du processus ?

    Pour le reste, pour faire ce que tu veux faire, je restaurerais l'état initial du terminal dans le handler puis je provoquerais la suspension du processus avant de le quitter, soit en relançant le signal avec raise() (mais ça fait deux signaux pour rien), soit en utilisant sigaction() et en rappelant le handler système original qui m'aura été renvoyé par la fonction en question.

    En outre, je ne maintiendrais en mémoire que la structure conservant l'état initial du terminal, et j'écrirais une seconde fonction qui s'occuperait de le mettre dans l'état souhaité en copiant cette structure dans une variable locale, en modifiant les flags de celle-ci, en faisant l'opération et en libérant le tout. Elle pourrait être ensuite appelée depuis le gestionnaire de SIGCONT.

  8. #8
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2014
    Messages
    84
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2014
    Messages : 84
    Points : 69
    Points
    69
    Par défaut
    Bonjour,

    Pour information, pourquoi sauvegardes-tu attribut par attribut l'état initial du terminal ? Pourquoi ne récupères-tu pas le tout dans une structure que tu conserverais en l'état pendant la durée du processus ?
    Je voulais garder en mémoire la structure originale pour ce faire, je faisais ainsi (en simplifié): (sachant que j'ai une structure termios term enregistrée dans une structure env )
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    struct termios new_term;
     
    tgetent(NULL, getenv("TERM"));
    tcgetattr(0, env->term); //Je stocke l'original dans la structure env pour remettre en état d'origine en appelant tcsetattr
    new_term.c_lflag = env->term.c_lflag;
    new_term.c_lflag &= ~(ECHO | ICANON);
    new_term.c_iflag = env->term.c_iflag;
    [....]
    tcsetattr(0, TCSANOW, new_term);
    Actuellement j'ai mieux :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    	char		*name;
     
    	if (!(name = getenv("TERM")))
    		name = "xterm";
    	if (tgetent(NULL, name) <= 0)
    		my_fputerr(NULL, "Error: Could not access the termcap database.\n");
    	name = ttyname(STDIN);
    	if (isatty(STDIN) == 0 || tcgetattr(STDIN, env->term) == -1)
    		my_fputerr(NULL, "Error: Not a terminal\n");
    	env->term->c_lflag &= ~(ICANON | ECHO);
    	env->term->c_cc[VMIN] = 1;
    	env->term->c_cc[VTIME] = 0;
    	if (tcsetattr(STDIN, TCSANOW, env->term) < 0)
    		my_fputerr(env, "Error: termios\n");
    Pour le reste, pour faire ce que tu veux faire, je restaurerais l'état initial du terminal dans le handler puis je provoquerais la suspension du processus avant de le quitter, soit en relançant le signal avec raise() (mais ça fait deux signaux pour rien), soit en utilisant sigaction() et en rappelant le handler système original qui m'aura été renvoyé par la fonction en question.
    Dans le principe ça ressemble à ce que je viens de faire, mise à part que j'utilise ioctl au lieu de raise. Quoi qu'il en soit je fais actuellement un projet d'Epitech et je n'ai pas le droit à la fonction raise ( ni sigaction() mais merci pour l'idée, c'est toujours bon à prendre ).

    En outre, je ne maintiendrais en mémoire que la structure conservant l'état initial du terminal, et j'écrirais une seconde fonction qui s'occuperait de le mettre dans l'état souhaité en copiant cette structure dans une variable locale, en modifiant les flags de celle-ci, en faisant l'opération et en libérant le tout. Elle pourrait être ensuite appelée depuis le gestionnaire de SIGCONT.
    Parfait, c'est ce que je fais

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    void			my_restore_term(t_env *env)
    {
    	tputs(tgetstr(CURSOR_VISIBLE, NULL), 0, my_tputchar);
    	env->term->c_lflag |= (ICANON | ECHO);
    	if (tcsetattr(STDIN, TCSANOW, env->term) < 0)
    	{
    		my_puterror("Error\n");
    		exit(-1);
    	}
    }
    D'ailleurs tu viens de me faire penser, tous mes signaux fonctionnent mais je n'arrive pas à récupérer le signal KILL ( de ce que j'ai lu, ce n'est pas possible ). Ce qui veux dire que lorsque je kill -KILL PID mon shell n'est jamais remis dans l'état initial, à part ça tout roule, merci

  9. #9
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 372
    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 372
    Points : 23 628
    Points
    23 628
    Par défaut
    Bonsoir,

    Citation Envoyé par sbill Voir le message
    Bonjour,

    Je voulais garder en mémoire la structure originale pour ce faire, je faisais ainsi (en simplifié): (sachant que j'ai une structure termios term enregistrée dans une structure env )
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    struct termios new_term;
     
    tgetent(NULL, getenv("TERM"));
    tcgetattr(0, env->term); //Je stocke l'original dans la structure env pour remettre en état d'origine en appelant tcsetattr
    new_term.c_lflag = env->term.c_lflag;
    new_term.c_lflag &= ~(ECHO | ICANON);
    new_term.c_iflag = env->term.c_iflag;
    [....]
    tcsetattr(0, TCSANOW, new_term);
    Ce n'est pas mal mais à aucun moment tu ne copies env->term dans newterm, si bien que les flags qui t'intéressent sont bien positionnés comme tu l'entends, mais tous les autres sont dans un état complètement indéterminé.

    Actuellement j'ai mieux :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    	char		*name;
     
    	if (!(name = getenv("TERM")))
    		name = "xterm";
    	if (tgetent(NULL, name) <= 0)
    		my_fputerr(NULL, "Error: Could not access the termcap database.\n");
    	name = ttyname(STDIN);
    	if (isatty(STDIN) == 0 || tcgetattr(STDIN, env->term) == -1)
    		my_fputerr(NULL, "Error: Not a terminal\n");
    	env->term->c_lflag &= ~(ICANON | ECHO);
    	env->term->c_cc[VMIN] = 1;
    	env->term->c_cc[VTIME] = 0;
    	if (tcsetattr(STDIN, TCSANOW, env->term) < 0)
    		my_fputerr(env, "Error: termios\n");
    Ce n'est pas mieux mais moins bien : tu modifies l'état de la sauvegarde, ce qui est précisément ce que l'on cherche à éviter.

    Dans le principe ça ressemble à ce que je viens de faire, mise à part que j'utilise ioctl au lieu de raise.
    À*ceci près que ioctl() n'a aucun rapport avec raise(), ni même avec les signaux d'une manière générale.

    « ioctl » signifie « I/O controls » et sert en principe à régler les paramètres d'un flux d'entrée/sortie déjà ouvert et accessible via un descripteur de fichier. Ça peut être par exemple la vitesse de transmission d'un port série, mais ça peut aussi concerner les disques, ou les fonctionnalités annexes des lecteurs amovibles, comme l'éjection d'un CD ou d'un DVD, ou le paramétrage bas niveau d'un disque dur, etc. Ça peut également concerner les sockets d'une connexion réseau. Ça veut dire également qu'UNIX en avait défini une bonne partie à l'époque et que POSIX en reprend également un bon nombre, mais que la plupart des commandes disponibles vont être dépendantes du système d'exploitation utilisé et de la version de son noyau.

    Quoi qu'il en soit je fais actuellement un projet d'Epitech et je n'ai pas le droit à la fonction raise ( ni sigaction() mais merci pour l'idée, c'est toujours bon à prendre ).
    Ce qui est effectivement un point à prendre en compte. Les projets d'Epita/tech ont fait l'objet de nombreuses controverses sur différents forums. Restreindre les ressources disponibles à l'apprenti-programmeur est en soi une bonne idée, pour éviter de recourir à des fonctions trop peu répandues ou à des facilités qui proposent directement le service que l'élève est censé développer (et bien sûr, de recourir à « system() » pour appeler les fonctions shell qu'il est justement censé réécrire). Il est aussi très intéressant de refaire réinventer les fonctions de base d'un système d'exploitation à ces mêmes personnes en partant du principe que celui-ci n'existe pas encore : ça permet de comprendre comment ça fonctionne et c'est en soi un bon exercice si le candidat est appelé à développer ou maintenir un système d'exploitation à l'avenir.

    Par contre, si ces entraves sont mal pensées, elles risquent au contraire de vous donner de très mauvaises habitudes puisqu'il faudra sans arrêt rappeler ensuite que la meilleure voie à suivre n'est justement pas celle que l'on vous a apprise.

    Aussi, peut-on connaître la liste exhaustive des fonctions qui vous sont interdites, ou celles qui vous sont autorisées si c'est plus court ?

    Parfait, c'est ce que je fais

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    void			my_restore_term(t_env *env)
    {
    	tputs(tgetstr(CURSOR_VISIBLE, NULL), 0, my_tputchar);
    	env->term->c_lflag |= (ICANON | ECHO);
    	if (tcsetattr(STDIN, TCSANOW, env->term) < 0)
    	{
    		ft_puterror("Error\n");
    		exit(-1);
    	}
    }
    Non, on ne fait pas la même chose : dans ton code, tu passes bien la structure en paramètre mais tu la modifies en réactivant ICANON et ECHO, c'est-à-dire en faisant l'hypothèse que ton terminal est forcément en mode canonique au lancement de ton programme.

    Ton terminal peut même se trouver dans un état complètement invraisemblable au moment du lancement de ton application. Il faudra malgré tout le remettre dans l'état dans lequel tu l'as trouvé.

    D'ailleurs tu viens de me faire penser, tous mes signaux fonctionnent mais je n'arrive pas à récupérer le signal KILL ( de ce que j'ai lu, ce n'est pas possible ). Ce qui veux dire que lorsque je kill -KILL PID mon shell n'est jamais remis dans l'état initial, à part ça tout roule, merci
    Non, mais cela, ça reste de la responsabilité de l'administrateur. Le signal SIGKILL demande au système de mettre directement fin au processus sans notification. Le programme est arrêté et les ressources qui lui étaient allouées par le système sont libérées. C'est nécessaire pour se débarrasser d'un programme qui ne répond plus mais qui, parallèlement, aurait quand même redéfini les handlers de tous les signaux, ou au moins de ceux qui servent à y mettre fin proprement. Il est donc normal qu'on ne puisse pas intercepter ce signal, mais il faut éviter d'y recourir d'emblée et à tout bout de champ. Il faudrait en principe envoyer SIGINT (2) et SIGTERM (15) avant d'envoyer un -9.

  10. #10
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2014
    Messages
    84
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2014
    Messages : 84
    Points : 69
    Points
    69
    Par défaut
    Bonjour,

    D'accord, donc si j'ai bien compris ce que tu attends est plus proche de ça : (n'hésite pas à me dire, s'il y a mieux)
    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
     
    void			my_init_term(t_env *env)
    {
    	char		*name;
    	t_termios	new_term;
     
    	if (!(name = getenv("TERM")))
    		name = "xterm";
    	if (tgetent(NULL, name) <= 0)
    		my_fputerr(NULL, "Error: Could not access the termcap database.\n");
    	if (isatty(STDIN) == 0 || tcgetattr(STDIN, env->term) == -1)
    		my_fputerr(NULL, "Error: Not a terminal.\n");
    	name = ttyname(STDIN);
    	if ((env->fd = open(name, O_WRONLY)) == -1)
    		my_fputerr(NULL, "Error: Could not open fd.\n");
    	new_term = *(env->term); //Je copie la structure originale dans new_term afin de modifier par la suite ce qui m'interesse
    	new_term.c_lflag &= ~(ICANON | ECHO);
    	new_term.c_cc[VMIN] = 1;
    	new_term.c_cc[VTIME] = 0;
    	if (tcsetattr(STDIN, TCSANOW, &new_term) < 0) //Je change le terminal, env->term est inchangé
    		my_fputerr(env, "Error: termios.\n");
    	tputs(tgetstr(CURSOR_HIDDEN, NULL), 0, my_tputchar);
    	tputs(tgetstr(CLEAR, NULL), 0, my_tputchar);
    }
     
    /* Retour à la normal */
    void			my_restore_term(t_env *env)
    {
    	tputs(tgetstr(CURSOR_VISIBLE, NULL), 0, my_tputchar);
    	if (tcsetattr(STDIN, TCSANOW, env->term) < 0) //Utilisation de la structure "propre" enregistrer
    	{
    		my_puterror("Error\n");
    		exit(-1);
    	}
    	if (close(env->fd) == -1)
    	{
    		my_puterror("Error: Could not close fd.\n");
    		exit(-1);
    	}
    }
    Aussi, peut-on connaître la liste exhaustive des fonctions qui vous sont interdites, ou celles qui vous sont autorisées si c'est plus court ?
    Oui, alors les fonctions autorisées sont les suivantes : open, read, close, exit, ioctl, write, malloc, free, signal, ttyname, ttyslot, isatty, getenv, tgetflag, tgetnum, tgetstr, tcgetattr, tcsetattr, tgentent, tputs, tgoto.
    Avec ce qui est autorisé, je n'ai rien trouvé de mieux que le double signal avec ioctl() pour le ctrl + Z, si tu ne vois pas non plus, je laisserai comme ça car le premier but est que ça fonctionne

  11. #11
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 372
    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 372
    Points : 23 628
    Points
    23 628
    Par défaut
    Citation Envoyé par sbill Voir le message
    Oui, alors les fonctions autorisées sont les suivantes : open, read, close, exit, ioctl, write, malloc, free, signal, ttyname, ttyslot, isatty, getenv, tgetflag, tgetnum, tgetstr, tcgetattr, tcsetattr, tgentent, tputs, tgoto.
    Ça ressemble beaucoup à une liste de primitives élémentaires choisies au départ dans l'optique de ce que l'on avait exposé au-dessus, et qui a été ensuite étendue au cas par cas quand les auteurs des exercices se sont rendus compte que les sujets d'exercices étaient infaisables en l'état. Ça m'ennuie dans le principe car normalement, c'est tout l'un ou tout l'autre : soit on évite volontairement de recourir à des bibliothèques tierces si ce n'est que pour se servir d'une ou deux fonctions qui pourraient très bien être ré-implémentées en quelques lignes et on s'attache alors à garantir la portabilité, soit on prend la décision de s'appuyer sur un framework et dans ce cas, on essaie de le cerner en entier. On essaie même de vérifier s'il est éventuellement possible de s'appuyer exclusivement dessus.

    En l'occurence, les dernières fonctions de ta liste sont des fonctions de curses, qui sert justement à gérer l'affichage et la présentation d'un terminal.

    Avec ce qui est autorisé, je n'ai rien trouvé de mieux que le double signal avec ioctl() pour le ctrl + Z, si tu ne vois pas non plus, je laisserai comme ça car le premier but est que ça fonctionne
    Par conséquent, et à ce propos, es-tu sûr que la remise en l'état du terminal sur une simple suspension (Ctrl+Z) fasse partie de l'exercice ? Ne t'aurait-on pas simplement demandé de veiller à le faire en fin de processus uniquement, chose qui aurait pu être garantie avec un atexit(), par exemple ?

  12. #12
    Membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2014
    Messages
    84
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2014
    Messages : 84
    Points : 69
    Points
    69
    Par défaut
    Par conséquent, et à ce propos, es-tu sûr que la remise en l'état du terminal sur une simple suspension (Ctrl+Z) fasse partie de l'exercice ? Ne t'aurait-on pas simplement demandé de veiller à le faire en fin de processus uniquement, chose qui aurait pu être garantie avec un atexit(), par exemple ?
    Oui je suis sur, "On doit pouvoir interrompre votre programme avec un ctrl+z et le restaurer avec fg sans que cela influe sur son comportement". Quoi qu'il en soit mon problème initiale est résolu, je te remercie pour ces échanges, je passe donc le sujet en résolu.
    Merci Obsidian, bonne soirée.

  13. #13
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 372
    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 372
    Points : 23 628
    Points
    23 628
    Par défaut
    Citation Envoyé par sbill Voir le message
    Oui je suis sur, "On doit pouvoir interrompre votre programme avec un ctrl+z et le restaurer avec fg sans que cela influe sur son comportement".
    Oui mais ça, ça ne veut pas dire qu'il faille forcément restaurer l'état du terminal pendant la phase de suspension. Cela veut dire que l'opération doit être transparente pour ton programme, qui ne doit pas être perturbé par cette manipulation. Cela va en fait principalement concerner les appels systèmes bloquants, tels que la lecture d'un caractère, qui sont généralement débloqués sur réception d'un signal et qui, par conséquent, échouent. Il faut prendre ce cas en compte et ne terminer le programme qu'en cas de réel échec.

    Il est possible, dans certains cas, de paramétrer le gestionnaire de signal pour que les appels système soient automatiquement relancés le cas échéant, mais je ne sais pas si les fonctions nécessaires à régler tout cela font partie de ta liste blanche.

    Quoi qu'il en soit mon problème initiale est résolu, je te remercie pour ces échanges, je passe donc le sujet en résolu.
    Merci Obsidian, bonne soirée.
    À toi de même. Merci d'avoir passé le fil en « résolu ».

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Programmation systeme en C et les signaux
    Par Traboulidon dans le forum Réseau
    Réponses: 27
    Dernier message: 06/02/2007, 10h32
  2. Soucis avec les signaux
    Par meuble2001 dans le forum C
    Réponses: 5
    Dernier message: 24/01/2007, 14h11
  3. utiliser une classe pour gerer les signaux
    Par TrueBeliever dans le forum Qt
    Réponses: 2
    Dernier message: 21/12/2006, 17h57
  4. Outils pour trapper les signaux
    Par ericbardoux dans le forum Applications et environnements graphiques
    Réponses: 5
    Dernier message: 22/11/2005, 13h41
  5. [C#] Gérer les signaux genre ctrl+c?
    Par BleudeBromothymol dans le forum Windows Forms
    Réponses: 8
    Dernier message: 17/11/2004, 15h32

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