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 :

execve à partir d'un path récupéré


Sujet :

C

  1. #1
    Futur Membre du Club
    Homme Profil pro
    étudiant @ Epitech
    Inscrit en
    Novembre 2012
    Messages
    16
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

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

    Informations forums :
    Inscription : Novembre 2012
    Messages : 16
    Points : 9
    Points
    9
    Par défaut execve à partir d'un path récupéré
    Bonjour à toutes et à tous ! En espérant que vous passez de bonnes fêtes... !

    Pour ma part, cela fait maintenant 4 jours que je galère à utiliser les binaires du shell.
    J'ai fait un interpréteur de commandes, et, si je tape "ls" ou "pwd", on est sensé voir leur exécution à l'écran.

    Je me suis donc appliqué à rechercher le PATH= contenant les chemins vers les binaires correspondant. Une fois trouvé, j'ai découpé chaque binaire dans un char** à partir de leur ":"

    j'obtenais donc des trucs du style "/usr/bin". J'ai ensuite rajouté un '/' à la fin de chaque ligne du tableau afin de n'avoir plus qu'à mettre avec un strcat la commande souhaité. Après avoir faire la fonction de découpe, j'ai donc fait la commande pour mettre la commande :

    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
    int     cmd(char **av, char **envp, char *str)
    {
      int   i;
      char  **path;
      char  *toto[4]; // = { "/bin/ls", "-l" ,"--color", NULL};                                                                                                                           char  *cmd; // = strdup("/bin/ls");                                                                                                                                    
     
      path = binar(av, envp, str);
      i = 0;
      while (path[i])
        {
          toto[0] = path[i];
          toto[1] = NULL;
          if (access(path[i], F_OK) == 0)
            {
              my_strcat(path[i], str);
              cmd = strdup("/bin/pwd");
              if ((execve(cmd, toto, NULL)) == -1)
                write(2, "Erreur d'execve\n", my_strlen("Erreur d'execve\n"));
            }
          i++;
        }
    }
    que je vous explique rapidement : au début, après avoir fait les découpes et m'assurer que j'entrais bien dans le 1er if, j'ai essayé d'executer execve en dur (on me l'a conseillé), tout marche nickel. Entre temps, mon strcat qui était en dehors du if a cessé de fonctionner, impossible de ré entrer dans le if. je sais pas pourquoi, il a fallu que je remette le my_strcat à l'endroit où vous le voyez.
    Bref, à partir de là j'ai essayé de bidouiller (je suis débutant en prog, tout n'est pas encore très claire dans ce que je fais :p ) afin d'avoir l'argument entré qui déclenche le binaire souhaité !
    Dans le char ** toto, quand je remplace les " { } " du début par mon path, nickel, ca fonctionne, mais quand il faut utiliser CMD... SI je le remplace par path[i] mon execve tend constamment vers -1.

    Je vais être franc avec vous, je mise beaucoup sur ce projet, et là je craque complètement, en 5 jours j'ai fais des pas de fourmis.

    Si quelqu'un peut m'aider, je lui en serrais reconnaissant !

    Merci d'avance


    edit : je ne sais pas pourquoi c'est caché, mais en dessous de *toto[4], il y a normalement :

    char *cmd; // = strdup("/bin/ls");

  2. #2
    Expert éminent sénior
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Points : 13 926
    Points
    13 926
    Par défaut
    Il y a quelque chose qui me chagrine :
    Je ne sais pas ce que fait binar(), surtout quel genre d'allocation il fait. Du coup, j'ai des soupçons sur le my_strcat() qui ajoute une chaine à la chaine path[i]. Comment le tableau path[i] peut-il avoir été dimensionné correctement lors de sa création pour tenir compte du fait qu'il doit contenir au final une chaine plus grande que la chaine d'origine ?
    Publication : Concepts en C

    Mon avatar : Glenn Gould

    --------------------------------------------------------------------------
    Une réponse vous a été utile ? Remerciez son auteur en cliquant le pouce vert !

  3. #3
    Membre expérimenté Avatar de plxpy
    Homme Profil pro
    Ingénieur géographe
    Inscrit en
    Janvier 2009
    Messages
    792
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 59
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur géographe
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Janvier 2009
    Messages : 792
    Points : 1 481
    Points
    1 481
    Par défaut
    Salut

    déjà, la ligne

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    char  *toto[4]; // = { "/bin/ls", "-l" ,"--color", NULL};
    (surtout son commentaire) me fait dire que tu ne sais pas utiliser execve.

    Si tu n'as pas l'habitude d'utiliser ce genre de fonctions, commence par t'assurer que tu en as bien compris le fonctionnement. Notamment, en n'essayant que ça et en ne rejoutant pas des trucs autour pour commencer.

    Par exemple, ceci fonctionne :

    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
    plx@satellite:~$ more execve.c 
    #include <stdio.h>
    #include <stdlib.h>
     
    int main(int argc,char *argv[])
    {
    	char *new_argv[] = { "ls", NULL };
    	char *new_envp[] = { NULL };
     
    	execve("/bin/ls", new_argv, new_envp);
    }
    plx@satellite:~$ 
    plx@satellite:~$ gcc -o execve execve.c
    plx@satellite:~$ 
    plx@satellite:~$ ./execve
    Bureau	Documents  IGN	Images	Mod??les  Musique  Public  T??l??chargements  Vid??os  bin  data  execve  execve.c  pere_noel.jpg  softs
    plx@satellite:~$
    alors que ça, non (le différence est à la ligne 7 du code source)

    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
    plx@satellite:~$ more execve.c
    #include <stdio.h>
    #include <stdlib.h>
     
    int main(int argc,char *argv[])
    {
    	char *new_argv[] = { NULL };
    	char *new_envp[] = { NULL };
     
    	execve("/bin/ls", new_argv, new_envp);
    }
    plx@satellite:~$ 
    plx@satellite:~$ gcc -o execve execve.c
    plx@satellite:~$ 
    plx@satellite:~$ ./execve
    A NULL argv[0] was passed through an exec system call.
    Abandon (core dumped)
    plx@satellite:~$
    Le message d'erreur te mettra sur la voie ...


    Autre chose : pourquoi utiliser execve et pas execv quand tu ne modifies pas l'environnement et que tu passes NULL en guise d'environnement à exec ?

    Dernière chose, quand un execX réussit, le code du processus courant est remplacé par un autre code (exécutable). Faire une boucle où, à chaque itération, tu tentes de faire un execX c'est faire preuve d'un grand pessimisme/défaitisme !!! Si (quand ! un peu d'optimisme, que diable !) ton premier execX fonctionnera, ta boucle while sera partie aux oubliettes !

    Dit autrement, tu boucles (while) tant que ton execve échoue ... (puis vient parallèlement à la condition du while).
    "La simplicité ne précède pas la complexité, elle la suit." - Alan J. Perlis
    DVP ? Pensez aux cours et tutos, ainsi qu'à la FAQ !

  4. #4
    Futur Membre du Club
    Homme Profil pro
    étudiant @ Epitech
    Inscrit en
    Novembre 2012
    Messages
    16
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

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

    Informations forums :
    Inscription : Novembre 2012
    Messages : 16
    Points : 9
    Points
    9
    Par défaut
    je vois ce que tu veux dire plxpy.

    le commentaire était pour montrer ce que j'avais effectuer en dur. Si tu enlèves le com et met un "=", execve fonctionne.

    De base sur mon shell, j'avais execve("/bin/ls", new_arg, new_evp);

    avec new_arg:
    new_arg[] = { "ls", ".", NULL}
    new_enp[] = {"USER=Test", NULL}

    ceci fonctionnait très bien, mais ça n'aurait pas été répondre au sujet que de faire une forêt de if avec chaque commande.

    Je n'utilise que execve et pas execv car je n'ai pas le droit à execv !

    Je prend note de lancer execv après la boucle, et non dedans !

    diogène, dans la fonction binar() j'ai fait un malloc(sizeof(char) * 1000) de mon path. C'est crade mais je ne me suis pas encore penché dessus, et je n'ai pas mis de '\0' à la fin du char **, car cela me faisait tout planter, je me consacrerai à ça par la suite. Cependant, quand j'utilise printf pour m'assurer que tout se fait correctement (à savoir si strcat a bien mis la commande à la suite de chaque binaire, en gros) j'ai un retour positif !

  5. #5
    Membre expérimenté Avatar de plxpy
    Homme Profil pro
    Ingénieur géographe
    Inscrit en
    Janvier 2009
    Messages
    792
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 59
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur géographe
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Janvier 2009
    Messages : 792
    Points : 1 481
    Points
    1 481
    Par défaut
    Ok pour la compréhension de execve.

    Par contre, il faudrait que tu nettoyes ton code. Je sais ce que c'est : on rajoute un truc ici, on teste, on rajoute un truc là, on re teste, etc ...

    Bref, à la fin, c'est un gros "bordel" où trainent des variables jamais utilisées, des commentaires contradictoires avec ce que ça fait réellement, j'en passe et des pires.

    Là, par exemple, cmd est le nom de ta fonction ET de la chaine de caractères contenant "/bin/pwd". Cette chaîne est toujours le premier paramètre de execve, etc ...

    Bref, nous qui débarquons dans ton code, c'est le bazar ... Fais du nettoyage, ça te profitera aussi je crois !
    "La simplicité ne précède pas la complexité, elle la suit." - Alan J. Perlis
    DVP ? Pensez aux cours et tutos, ainsi qu'à la FAQ !

  6. #6
    Futur Membre du Club
    Homme Profil pro
    étudiant @ Epitech
    Inscrit en
    Novembre 2012
    Messages
    16
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

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

    Informations forums :
    Inscription : Novembre 2012
    Messages : 16
    Points : 9
    Points
    9
    Par défaut
    C'est exactement ce que j'ai fais en attendant vos réponses

    Voilà un truc plus propre, juste après le découpage de l'envp à la fin :

    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
     
    char    **make_it_works(char **envp)
    {
      char  **path;
      int   x;
     
      if ((path = malloc(sizeof(char *) * number_element(envp))) == NULL)
        {
          write(2, "Error malloc\n", my_strlen("Error malloc\n"));
          exit(0);
        }
      x = 0;
      path = find_path(envp);
      while (path[x])
        {
          path[x][my_strlen(path[x])] = '/';
          path[x][my_strlen(path[x]) + 1] = '\0';
          x++;
        }
      return (path);
    }
    char    **cmd(char **envp, char **tab)
    {
      char  **path;
      int   i;
     
      path = make_it_works(envp);
      i = 0;
      while (path[i])
        {
          my_strcat(path[i], tab[0]);
          printf("%s", path[i]);
          if (access(path[i], F_OK) == 0)
            my_putchar('a');
          i++;
        }
    }
     
    int     number_element(char **envp)
    {
      int   i;
     
      i = 0;
      while (envp[i])
        i++;
      return (++i);
    }
    ce que j'obtiens avec le printf que vous voyez dans la boucle de la dernière fonction :

    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
    (Jay Cee)./minishell
    welcome: ls
    PATH=/usr/sbin/ls
    /usr/bin/ls
    /sbin/ls
    /bin/ls
    /usr/school/sbin/ls
    /usr/school/bin/ls
    /usr/netsoul/sbin/ls
    /usr/netsoul/bin/ls
    /usr/kerberos/sbin/ls
    /usr/kerberos/bin/ls
    /usr/local/sbin/ls
    /usr/local/bin/ls
    /usr/bin/eclipse/ls
    welcome:
    impossible d'entrer dans le if de access...

  7. #7
    Membre expérimenté Avatar de plxpy
    Homme Profil pro
    Ingénieur géographe
    Inscrit en
    Janvier 2009
    Messages
    792
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 59
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Ingénieur géographe
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Janvier 2009
    Messages : 792
    Points : 1 481
    Points
    1 481
    Par défaut
    En vrac

    • tu comptes une variable d'environnement de trop dans la fonction number_element.

    • pourquoi encore manipuler, si près du but (dans la fonction cmd par exemple), envp alors que, si j'ai bien compris, seule la valeur de la variable d'environnement PATH est utile ? Très en amont, récupère ce que vaut PATH (forme initiale, découpée selon les ':', avec un '/' final ajouté, sous la forme que tu veux) et sers t'en.

    • de façon générale, sauf "figure imposée" de l'exercice, l'utilisation de envp m'échappe. Je lui préfèrerais getenv (stdlib.h) en recherchant PATH

    • comme il faut reproduire la recherche d'une "commande" (sans info de chemin) dans le PATH, c'est plutôt X_OK qu'il faut utiliser dans access, sur le chemin de la commande, et pas F_OK sur les répertoires de PATH. Dans la première version postée, c'est pour cela que tu te lançais dans une boucle while sur les execve je suppose : c'est execve qui, in fine, testait l'existence et "l'exécutabilité" de la commande. Mouais ...

    • plusieurs choses clochent dans la fonction make_it_works :


      • path est alloué à la ligne 7 mais tu lui affectes le résultat de find_path. Je serais curieux de voir ne serait-ce que le prototype de find_path

      • lors de l'allocation de path, toujours à la ligne 7, le nombre de variables d'environnement apparait dans le calcul de la taille à allouer ??? C'est le nombre de répertoires contenus dans PATH qui joue un rôle.


    • n'oublie pas, quand tu coderas la boucle qui passe en revue les différents répertoires du PATH, qu'un "shell normal" arrête sa recherche au premier chemin exécutable existant trouvé et ne teste pas les possibilités suivantes

    • en gros, une bonne partie de ton programme doit reproduire ce que fait la commande which. Si j'avais à faire ton exo, dans mon découpage, je coderais bien une fonction

      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      char *which(const char *cmd)
      qui utiliserait getenv("PATH") et retournerait le chemin de la commande (ou NULL si pas trouvé).

      Les autres parties seraient la saisie par l'utilisateur de la commande (de l'exécutable) et la partie exécution ('lun ou l'autre des execX)

    • dans la toute dernière partie du "code" posté (les chemins possibles de ls), tu sembles vouloir faire une boucle de saisie de la commande par l'utilisateur. N'oublie pas une de mes toutes premières remarques : on ne "revient" d'un exec que si il s'est mal passé. Si tu veux faire une telle boucle, il va falloir utiliser fork et garder un processus père qui s'occupera de cette boucle. Sinon, à la première commande trouvée et exécutée, ton programme s'arrêtera.


    Courage !


    EDIT

    aussi :

    - ligne 9 : un appel système (write) pour écrire sur stderr ... bof
    - ligne 10 : arrêt très/trop brutal (exit) avec code retour inapproprié (0 pour une erreur ...)
    "La simplicité ne précède pas la complexité, elle la suit." - Alan J. Perlis
    DVP ? Pensez aux cours et tutos, ainsi qu'à la FAQ !

  8. #8
    Futur Membre du Club
    Homme Profil pro
    étudiant @ Epitech
    Inscrit en
    Novembre 2012
    Messages
    16
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

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

    Informations forums :
    Inscription : Novembre 2012
    Messages : 16
    Points : 9
    Points
    9
    Par défaut
    Alors en effet, je n'ai pas le droit à getenv !

    Merci pour ces divers remarques qui vont me permettre d'améliorer mon code.

    Les fonctions que j'ai posté ici s’exécutent déjà dans un fork en fait !

    Je prend note de tes remarques, merci

Discussions similaires

  1. [CR 10.5] Afficher une image à partir d'un path
    Par roshy dans le forum SAP Crystal Reports
    Réponses: 3
    Dernier message: 30/03/2010, 10h10
  2. Ouvrir lecteur video à partir d'un path
    Par crofteur dans le forum Général Java
    Réponses: 1
    Dernier message: 23/07/2009, 17h57
  3. Réponses: 3
    Dernier message: 19/08/2008, 14h55
  4. Dimension d'une image à partir de son path
    Par Gregory.M dans le forum C#
    Réponses: 4
    Dernier message: 06/08/2008, 09h48
  5. [Excel-VBA]Nom d'un workbook a partir de son path
    Par Tartenpion dans le forum Macros et VBA Excel
    Réponses: 14
    Dernier message: 19/10/2006, 15h34

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