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 :

Écrire un programme permettant d'éxecuter en tâche de fond


Sujet :

C

  1. #1
    Membre régulier
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2015
    Messages
    67
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 29
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2015
    Messages : 67
    Points : 108
    Points
    108
    Par défaut Écrire un programme permettant d'éxecuter en tâche de fond
    Bonsoir,

    Je dois réaliser un programme C qui permet d’exécuter des commandes Linux dans le terminal, pour l'instant tout fonctionne avec ceci :

    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
     
    #ifndef _LIGNE_COMMANDE_V2_H
    #define _LIGNE_COMMANDE_V2_H
     
    /**
    CODE DU PROF
     * Cette fonction lit sur l'entrée standard une ligne de texte,
     * la découpe selon les espaces, et retourne un tableau de char*
     * du type attendu par execv et execvp.
     *
     * Si la fin de fichier est rencontrée, cette fonction retourne NULL.
     *
     * Voir aussi les fonctions fin_de_fichier et ligne_vide.
     */
     
    char** lis_ligne();
     
    /**
     * Cette fonction prend en paramètre le tableau de char* retourné par lis_ligne
     * et retourne vrai si et seulement si lis_ligne a rencontré la fin de fichier.
     * (c.à.d. si ligne est NULL)
     */
    int fin_de_fichier(char** ligne);
     
    /**
     * Cette fonction prend en paramètre le tableau de char* retourné par lis_ligne
     * et retourne vrai si la ligne lue était vide.
     * Pré-condition: on n'est pas en fin de fichier, ligne != NULL
     */
    int ligne_vide(char** ligne);
     
     
    /**
     * Cette procédure coupe une chaîne de caractères en deux à l'endroit du signe
     * égal, de sorte qu'après son exécutuion:
     *  - la chaîne passée en paramètre ne contient plus que sa partie gauche,
     *  - le pointeur retourné pointe vers la partie droite.
     *
     * Si la chaîne passée en paramètre ne contient pas le signe égal, la chaîne
     * n'est pas modifiée, et la fonction retourne NULL.
     */
    char* separe_egal(char* str);
     
     
    #endif

    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
     
    /**
     *CODE DU PROF
     * Pour la documentation, voir ligne_commande_v2.h .
     */
     
    #include "ligne_commande.h"
     
    #include <stdio.h>
    #include <string.h>
    #include <unistd.h>
     
    #define LBUF 1024
    #define LLIGNE 256
    static char buf[LBUF];
    static char* ligne[LLIGNE];
     
    char** lis_ligne()
    {
        int i = 0;
        int s;
        do
        {
            s = read(0, buf+i, 1);
            i += s;
        } while (i < LBUF-1  &&  s > 0  &&  buf[i-1] != '\n');
        if (s < 0) perror("erreur de lecture dans lis_ligne");
        if (i == 0) return NULL;
     
        // découpage
        char* tok;
        buf[i] = '\0';
        i = 0;
        ligne[0] = strtok_r(buf, " \t\n\r", &tok);
        while (ligne[i] && i < LLIGNE-1)
        {
            i += 1;
            ligne[i] = strtok_r(NULL, " \t\n\r", &tok);
        }
        if (i == LLIGNE-2) ligne[LLIGNE-1] = NULL;
        return ligne;
    }
     
    int fin_de_fichier(char** ligne)
    {
        return ligne == NULL;
    }
     
    int ligne_vide(char** ligne)
    {
        return ligne[0] == NULL;
    }
     
    char* separe_egal(char* str)
    {
      char* p = str;
      while (*p) {
        if (*p == '=') {
          *p = '\0';
          return p+1;
        }
        p++;
      }
      return NULL;
    }
     
    /* fonction de test */ /*
    int main (int argc, char** argv)
    {
        char** l = lis_ligne();
        int i;
        for(i = 0; l && l[i]; i++) {
            printf("<%s>\n", l[i]);
        }
        printf("c'est tout %d %d\n", fin_de_fichier(l), l && ligne_vide(l));
        // TODO teste aussi separe_egal
        return 0;
    }
    */

    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
     
     
    #include "ligne_commande.h"
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h> /* strcmp */
    #include <unistd.h> /* fork,getpid */
    #include <stdio.h> /* perror */
    #include <sys/types.h> /* getpid */
    #include <sys/wait.h> /* wait */
     
    int commandes_internes(char** cmd);
     
    int main(int argc, char** argv) {
        setenv("INVITE", "\n> ", 1);
        pid_t pid;
        int state;
        while (1) {
            printf("%s ", getenv("INVITE"));
            fflush(stdout);
            char** commande = lis_ligne();
     
            if (fin_de_fichier(commande)) {
                printf("Fin du programme\n");
                return 0;
            } else {
                if (!ligne_vide(commande)) {
                    if (!commandes_internes(commande)) {
     
                        pid = fork();
                        if (pid == 0) {
                            if (execvp(commande[0], commande) == -1)
                                perror("Commande incorrecte\n");
                            exit(0);
                        } else {
                            wait(&state);
                        }
                    }
                }
            }
        }
    }
     
    int commandes_internes(char** cmd) {
        if (!strcmp(cmd[0], "exit")) {
            printf("Fin du programme\n");
            exit(0);
        }
     
        if (!strcmp(cmd[0], "export")) {
            if (cmd[1]) {
                char* value = separe_egal(cmd[1]);
                if (setenv(cmd[1], value, 1) == -1) {
                    perror("Erreur");
                }
            }
            return 1;
        }
        return 0;
    }
    Mais je dois maintenant modifier ce programme afin de permettre à l'utilisateur d’exécuter en tâche de fond la commande si elle commence par tf (tâche de fond) et que le shell affiche directement l'invité de saisie pour une autre commande. Lorsqu'elle est terminée on doit afficher un message indiquant que le processus est fini avec son pid.

    Sans tf, on attendra la fin pour afficher l'invité de saisie, ça j'ai réussi

    Tout cela sans créer de zombie

    Avez-vous des idées car je galère pour la partie tâche de fond

    Merci par avance

  2. #2
    Expert éminent
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 565
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 565
    Points : 7 648
    Points
    7 648
    Par défaut
    Bonjour,
    Après avoir lancé le fils, il ne faut pas faire le wait(), à la place il faut un handler sur événement SIGCHLD qui sera reçu à la mort du fils.
    Dans le handler ne pas oublier de faire wait() qui retournera immédiatement en supprimant le zombie.
    Et avant de quitter l'application faire un wait() sur tous les backgrounds non terminés (il peut y avoir plusieurs alors bien conserver dans une table la liste des pid encore en cours.)

  3. #3
    Membre régulier
    Homme Profil pro
    Étudiant
    Inscrit en
    Octobre 2015
    Messages
    67
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 29
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2015
    Messages : 67
    Points : 108
    Points
    108
    Par défaut
    Finalement avec ça, ça marche

    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
     
     
    #include "ligne_commande.h"
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <string.h> /* strcmp */
    #include <unistd.h> /* fork,getpid */
    #include <stdio.h> /* perror */
    #include <sys/types.h> /* getpid */
    #include <sys/wait.h> /* wait */
     
    int commandes_internes(char** cmd);
     
    int main(int argc, char** argv) {
        setenv("INVITE", "\n> ", 1);
        pid_t pid, pid2;
        int state;
        while (1) {
            printf("%s ", getenv("INVITE"));
            fflush(stdout);
            char** commande = lis_ligne();
     
            if (fin_de_fichier(commande)) {
                printf("Fin du programme\n");
                return 0;
            } else {
                if (!ligne_vide(commande)) {
                    if (!commandes_internes(commande)) {
     
                        pid = fork();
                        if (pid == 0) {
    						if(!strcmp(commande[0], "tf")){
    							pid2 = fork();
    							if(pid2 == 0){
    								if(execvp(commande[1],commande+1) == -1){
    									perror("Commande incorrecte\n");
    									exit(1);
    								   }
     
    								}else{
    									waitpid(pid2,&state,0);
    									printf("Fin du programme %d (%s)\n",getpid(),commande[1]);
    									exit(0);
    								}
    						}
    						else{
    							if (execvp(commande[0], commande) == -1)
    									perror("Commande incorrecte\n");
    							exit(0);
    						}
                        } else {
    							if(strcmp(commande[0],"tf")!=0)
    								waitpid(-1,&state,0);
                        }
                    }
                }
            }
        }
    return 0;
    }
     
    int commandes_internes(char** cmd) {
        if (!strcmp(cmd[0], "exit")) {
            printf("Fin du programme\n");
            exit(0);
        }
     
        if (!strcmp(cmd[0], "export")) {
            if (cmd[1]) {
                char* value = separe_egal(cmd[1]);
                if (setenv(cmd[1], value, 1) == -1) {
                    perror("Erreur");
                }
            }
            return 1;
        }
        return 0;
    }
    Bon par contre, un autre problème se pose, je dois maintenant rediriger la sortie standard d'une première commande sur l'entrée standard d'une deuxième commande avec un tube, la je sèche complètement...

Discussions similaires

  1. Réponses: 6
    Dernier message: 03/03/2013, 23h42
  2. commandes pour écrire un shell script
    Par marieGre dans le forum Applications et environnements graphiques
    Réponses: 1
    Dernier message: 11/09/2009, 15h32
  3. Script Shell permettant de copier une colonne
    Par jaljal dans le forum Unix
    Réponses: 1
    Dernier message: 05/06/2009, 00h08
  4. Comment écrire un shell qui transforme un code ascii en caractère?
    Par jack-ft dans le forum Shell et commandes GNU
    Réponses: 3
    Dernier message: 21/04/2008, 17h51
  5. executable en "tâche de fond"
    Par jaquet_vincent dans le forum Windows
    Réponses: 5
    Dernier message: 22/10/2004, 14h49

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