Partage
  • Partager sur Facebook
  • Partager sur Twitter

Message d'erreur execv

A NULL argv[0] was passed through an exec system call

Sujet résolu
    10 mai 2018 à 18:15:57

    Bonjour à tous,

    Dans le cadre d'un projet je dois créer un terminal virtuel, et donc gérer aussi la commande cd x, pour faire ceci j'utilise la fonction chdir(x) mais si je tente de l'utiliser deux fois de suite ça me met ceci :

    a null argv[0] was passed through an exec system call

    Et du coup je comprends pas trop pourquoi et comment régler ça malgré mes recherches...

    Mon code pour gérer le cd est comme ceci :

    if(strcmp(argv[i], "cd")==0){
    	if(argv[i+1]!=NULL){
    		chdir(argv[i+1]);
    		cmds[cmd_idx].argv[argv_idx]=NULL;
    		cmd_idx++;
    		argv_idx=0;
    		continue;
    	}
    }


    cmds est en gros la ligne de commande actuelle

    • Partager sur Facebook
    • Partager sur Twitter
      10 mai 2018 à 18:31:30

      Tu appelle une fonction exec() avec des arguments au mauvais format.

      Avec plus de code, on pourrait t'aider plus.

      • Partager sur Facebook
      • Partager sur Twitter
        10 mai 2018 à 21:46:57

        Salut,

        Il me semble que si tu veux lancer un programme standard POSIX (typiquement ls ou chmod par exemple), il faut donner au programme au moins 1 argument qui est son nom (ou son chemin je ne sais pas honnêtement). La liste d'argument doit être terminée par NULL (c'est le standard C pour argv[][] qui veut ça).

        execve("/bin/ls", (char *[3]){"ls", "-al", NULL}, env);

        Ici on appelle ls avec -al en argument (comme `ls -al`dans le shell quoi).

        Il semble d'après ton message d'erreur que le premier argument donné (reçu dans le argv[0] du programme) soit NULL.

        N'hésites pas à donner plus de code comme le suggère mon vdd, penses à vérifier le retour de chdir(), et d'où sors-tu le message d'erreur ? Il apparait tout seul ? strerror()/perror() ?

        -
        Edité par Gam' 10 mai 2018 à 22:10:20

        • Partager sur Facebook
        • Partager sur Twitter
          12 mai 2018 à 7:00:26

          Salut, pour lancer une commande à partir d'un code en C j'utilise exec comme ceci :

          int execute_comm(char *argv[],int ind1){
          
            pid_t p = create_process();// Tu peux remplacer par pid_t p = fork() ;
            if(p==0){
              execvp(argv[ind1],argv + ind1);
              exit(1);
            }
            else{
              int status = 1 ;
              wait(&status);
              if(WIFEXITED(status))
                status = WEXITSTATUS(status);
              if(WIFSIGNALED(status))
                status = WTERMSIG(status);
              return status ;
            }
          }

          En gros la seule chose à gérer sont les paramètres de la fonction, et elle lance la commande toute seule :)

          En gros tu dois créer un tableau de char* avant d'appeler la fonction.

          Imagine ce tableau char *args[] ( déjà allouer ) :

          args[0]="cd";

          args[1]="Le_répertoire";

          args[2]=NULL; // Le NULL est très important pour le bon fonctionnement du recouvrement par exec

          args[3]="ls";

          args[4]="-all";

          args[5]=NULL; // idem

          Si tu appelle la fonction,  execute_comm avec comme argument ton tableau args, et l'entier 0 ;

          Cette fonction exécutera la commande à l'indice 0 avec les arguments contenu dans ton tableau jusqu'au prochain NULL. En gros "cd Le_répertoire" sera lancé

          Si tu décide d'appeler execute_comm avec args, et 3 comme arguments;

          La fonction exécutera "ls -all"

          La valeur de retour renvoyé est 0 -> tout c'est bien passé.

                                                          sinon la valeur de retour de la commande ou du signal qui l'a interrompu ( genre ctrl-c )

          Tu peux remplacer exit(1) par return 1; cette ligne signifie que la commande n'as pas pu se lancer ( genre "eckko hello" );

          Je ne sais pas si ca répond à ta questions, mais je lance mes commandes dans un prog C comme ceci.

          PS : a oui pense à inclure : <unistd.h> <sys/wait.h> et à compiler avec -std=gnu99

          En espérant t'avoir aidé



          -
          Edité par Golgoo 12 mai 2018 à 7:01:55

          • Partager sur Facebook
          • Partager sur Twitter
            14 mai 2018 à 23:29:43

            Excusez moi du temps de réponse j'ai du finir un autre projet où j'ai pas mal galéré ...

            Alors pour mon code j'ai 3 fichier, parser.c, exec.c et main.c (avec leur .h correspondant)

            parser.c a trois fonctions

            #include <string.h>
            #include <stdio.h>
            
            int trim(char * str) {
            
            	int pos = strspn(str, " \t");
            // supprimer les espace /tab au début et à la fin de str
            // ex :	str : " ... ... ... abc ... ... d ... ..."
            // => "abc ... ... d"
            	// suprimme les espaces inutile du début.
            	memmove(str, str+pos, strlen(str+pos)+1);
            
            	int i = strlen(str)-1;
            
            	// suprimme les espaces inutile de fin.
            	while (i > 0) {
            		if (str[i] == ' ' || str[i] == '\t') {
            			//str[i] = str[i-1];
            			i--;
            		}
            		else {
            			str[i+1]='\0';
            			break;
            		}
            	}
            	return 0;
            }
            
            int suppr_doublons(char * str) {
            	char * dbl;
            	while ((dbl=strstr(str,"  ")) != NULL)
            		memmove(dbl, dbl+1,strlen(dbl));
            	return 0;
            }
            	
            int tokenize(char * str, char * argv[], int max_arg){
            	// aaaa					bbbbb					cccc
            	// aaaa = argv[0];		bbbbb = argv[1]			cccc = argv[2];
            	int argv_ind = 0;
            	int i = 0;
            	while (argv_ind < max_arg) {
            		argv[argv_ind] = str;
            		while (*str != ' ' && *str != '\0' )
            			str++;
            		if (*str == '\0') {
            			argv[argv_ind+1]=NULL;
            			return 0;
            		}
            		if (*str == ' ') {
            			// "casser" la chaine
            			*str = '\0';
            
            			++str;
            			++argv_ind;
            		}
            	}
            	return 1;
            }

            exec.c (un peu grand à écrire c'est pour ça que j'ai préféré ne pas tout mettre :/ )

            int search_path (char * filename, char * path) {
            	// /usr/bin:/bin/:usr/local/bin
            	char* env_path = getenv("PATH");
            	if (env_path == NULL) {
            		return 1;
            	}
            	while ((env_path != NULL)){
            		char * fin = strchr(env_path, ':');
            		if (fin == NULL)
            			fin=strchr(env_path, '\0');
            		strncpy(path, env_path, fin-env_path);
            		path[fin-env_path]='/';
            		path[fin-env_path+1]='\0';
            		//if(filename!=NULL)
            			strcat(path, filename);
            		if (* fin == '\0')
            			env_path=NULL;
            		else
            			env_path = fin + 1;
            		FILE* f;
            		f = fopen(path,"r");
            		if (f != NULL) {
            			fclose(f);
            			return 0;
            		}
            	}
            	return 1;
            }
            
            int make_commands(char * str, command_t * cmds, int max){
            	int cmd_idx=0, argv_idx=0;
            	trim(str);
            	suppr_doublons(str);
            	char * argv[MAX_ARGS];
            
            	tokenize(str, argv, MAX_ARGS);
            
            	/*for (int i = 0; argv[i]!=NULL; ++i) {
            		printf("argv[%d] = %s\n", i, argv[i]);
            	} 
            */
            	for (int i=0; argv[i] != NULL && cmd_idx<max; ++i){
            		// a compléter
            		if(strcmp(argv[i], "exit")==0){
            			exit(EXIT_SUCCESS);
            		}
            
            
            		.......
            
            
            		if(strcmp(argv[i], "cd")==0){
            			if(argv[i+1]!=NULL){
            				chdir(argv[i+1]);
            				cmds[cmd_idx].argv[argv_idx]=NULL;
            				cmd_idx++;
            				argv_idx=0;
            				continue;
            			}
            		}
            		// faire les autres if avec '<' etc...
            		// code éxecuté que dans le cas ou il n'y a pas de redirection
            		cmds[cmd_idx].argv[argv_idx]=argv[i];
            		argv_idx++;
            	}
            
            	cmds[cmd_idx].argv[argv_idx]=NULL;
            	if (search_path(cmds[cmd_idx].argv[0], cmds[cmd_idx].path)!=0) {
            		return -1;
            	}
            	return cmd_idx+1;
            }
            
            int exec_commands(command_t* cmds, int nb){
            	command_t * cmd = &cmds[0];
            	while(cmd!=NULL){
            		if((cmd->pid=fork())==0){
            			dup2(cmd->stdin, STDIN_FILENO);
            			dup2(cmd->stdout, STDOUT_FILENO);
            			dup2(cmd->stderr, STDERR_FILENO);
            			//stdout, stderr / STDOUT_FILEND, STDERR
            			if(cmd->stdin!=STDIN_FILENO)
            				close(cmd->stdin);
            			if(cmd->stdout!=STDOUT_FILENO)
            				close(cmd->stdout);
            			if(cmd->stderr!=STDERR_FILENO)
            				close(cmd->stderr);
            			execv(cmd->path,cmd->argv);
            			exit(-1);
            		}
            		if(cmd->bg==0)
            			waitpid(cmd->pid, &cmd->status, 0);
            		if(WEXITSTATUS(cmd->status)==0)
            			cmd=cmd->next_success;
            		else
            			cmd=cmd->next_failure;
            		//printf("%d\n", WEXITSTATUS(cmd->status));
            	}
            	return 0;
            
            }
            
            int init(command_t* cmds, int max){
            	int i=0;
            	while(i<max){
            		cmds[i].stdin=STDIN_FILENO;
            		cmds[i].stdout=STDOUT_FILENO;
            		cmds[i].stderr=STDERR_FILENO;
            		cmds[i].next_success=NULL;
            		cmds[i].next_failure=NULL;
            		cmds[i].bg=0;
            		i++;
            	}
            	return 0;
            }

            main.c

            #include <stdio.h>
            
            #include <stdlib.h>
            #include <unistd.h>
            #include <string.h>
            #include "parser.h"
            #include "exec.h"
            
            void clean(const char *buffer, FILE *fp);
            
            int main(int argc, char * argv[]) {
            	command_t cmds[256];
            	char * str="\0";
            	while(1){
            		init(cmds,256);
            		/*char * str = strdup("ls || cat dsds");
            		for(int i=0; i<strlen(str); i++){
            			printf("%c\n",str[i]);
            		}*/
            		
            		char chaine[256]="";
            		printf("$");
            		fgets(chaine, sizeof(chaine), stdin);
            		clean(chaine,stdin);
            		str=strdup(chaine);
            			//printf("str : -%s-\n", str);
            		//}*/
            		
            		int nb=make_commands(str,cmds,256);
            		exec_commands(cmds, nb);
            		
            	}
            	return 0;
            }
            
            void clean(const char *buffer, FILE *fp)
            {
                char *p = strchr(buffer,'\n');
                if (p != NULL)
                    *p = 0;
                else
                {
                    int c;
                    while ((c = fgetc(fp)) != '\n' && c != EOF);
                }
            }

            Et du coup d'après mon code normalement j'ajoute un NULL à la fin donc ça devrait aller enfin je pense je sais pas trop



            -
            Edité par maxime80foulon 14 mai 2018 à 23:33:47

            • Partager sur Facebook
            • Partager sur Twitter
              14 mai 2018 à 23:41:20

              A premiere vue ta fonction tokenize ne fait pas ce qu'il faut.

              Je regarderai plus en détail demain a tete reposée. La je fatigue

              • Partager sur Facebook
              • Partager sur Twitter
                14 mai 2018 à 23:43:34

                D'accord, ça c'est une fonction que notre prof nous a donné en cours donc c'est possible j'ai déjà débuggé pas mal d'erreurs de son code, merci en tout cas, bon repos
                • Partager sur Facebook
                • Partager sur Twitter
                  15 mai 2018 à 10:10:08

                  En effet, la fonction tokenize est fausse. Deja j'ai l'impression qu'il y a confusion entre caracteres et chaine de caracteres. 

                  Si tu pouvais m'expliquer comment elle est censé fonctionner je pourrais t'aider a la debuguer.

                  EDIT : Apres mainte relecture, je pense qu'elle fonctionne bien qu'elle soit relativement difficile a comprendre. Cependant tu n'initialises jamais argv.

                  -
                  Edité par thetui 15 mai 2018 à 10:20:34

                  • Partager sur Facebook
                  • Partager sur Twitter
                    15 mai 2018 à 10:16:04

                    Et bien en fait si j'ai bien compris, cette fonction sépare chaque champ comme par exemple "ls -l\0" par des \0 de façon à les délimiter et à les récupérer après, et quand on obtient le dernier argument, on ajoute NULL à argv[ind +1]

                    Donc l'exemple devient "ls\0-l\0" et les argv sont si je ne me trompe pas argv[0]=ls argv[1]=-l argv[2] = NULL

                    -
                    Edité par maxime80foulon 15 mai 2018 à 10:16:19

                    • Partager sur Facebook
                    • Partager sur Twitter
                      15 mai 2018 à 10:56:34

                      Je pense que tu n'as pas vu mon edit du precedent message.

                      Et pourquoi rajouter NULL a la fin fans make_cmd() puique tu le fais dans tokenize()? Ou peut-etre que ce n'est pas nécessaire dans tokenize.

                      Mais je pense que tu devrait commencer par initialiser argv

                      • Partager sur Facebook
                      • Partager sur Twitter
                        15 mai 2018 à 13:29:31

                        A vrai dire, je l'initialise dans la fonction init dans exec.c, voici mon exec.h pour avoir la structure de type command_t

                        #ifndef EXEC_H
                        #define EXEC_H
                        
                        #define MAX_CMD_SIZE 1024
                        #define MAX_ARGS 256
                        #define MAX_PATH_SIZE 256
                        
                        #include <sys/types.h>
                        
                        int search_patch(char * filename, char * path);
                        typedef struct command_t {
                            char path[MAX_PATH_SIZE];
                            char * argv[MAX_ARGS];
                            int stdin, stdout, stderr;
                            int bg;
                            pid_t pid;
                            int status;
                            struct command_t* next_success;
                            struct command_t* next_failure;
                            
                        }command_t;
                        int init(command_t* cmds, int max);
                        int exec_commands(command_t * cmd, int nb);
                        int make_commands(char * str, command_t * cmds, int max);
                        #endif


                        et pour le NULL dans make cmd je ne sais plus exactement pourquoi mais je sais que c'est important sinon ça ne fonctionne pas

                        • Partager sur Facebook
                        • Partager sur Twitter
                          15 mai 2018 à 14:15:18

                          Tu n'initialises jamai sle argv de command_t (il faudrait un malloc). Et fait un autre malloc pour le argv a la ligne 34 de exec.c.

                          J'ai vu que tu avais commenté l'affichage de la sortie de tokenize. Cela signifie-t-il que la fonction renvoie le résultat que tu souhaites?

                          Ensuite une question de conception, pourquoi utiliser un tableau de cmd?

                          Et pour finir que contient str lors de l'appel a make_cmd()? Parce que je crois que je n'ai pas tout compris. Avec une seule chaine str tu remplis le tableau argv de toutes tes commandes?

                          • Partager sur Facebook
                          • Partager sur Twitter
                            16 mai 2018 à 11:06:11

                            En gros dans str après make_command chaque espace est remplacé par \0 et chaque champ est dans argv[ind] avec un indice différent. et ça fait ça pour chaque ligne de commande qu'elle soit séparée par un ";" ou non. Et euh parce que ça paraissait plus utile un tableau de commande pour se déplacer dedans

                            Et le tokenize marche bien oui

                            • Partager sur Facebook
                            • Partager sur Twitter
                              17 mai 2018 à 17:25:29

                              Pour mon soucis en fait je pense savoir pourquoi ça m'affiche cette erreur sans savoir comment la régler,

                              Quand je retires cette ligne :

                              cmds[cmd_idx].argv[argv_idx]=NULL;

                              et que je fais un ls puis un cd .. par exemple, ça me refait un ls quand je fais le cd

                              Vous avez une idée ?
                              • Partager sur Facebook
                              • Partager sur Twitter
                                17 mai 2018 à 17:41:29

                                Je pense que le probleme vient du fait que tu traites le cd avec chdir() mais que tu apelles quand meme exec_cmd() après.
                                • Partager sur Facebook
                                • Partager sur Twitter
                                  19 mai 2018 à 14:48:25

                                  Le problème venait du fait que je traitais cd dans make command, je l'ai mis dans exec_commands comme ceci :

                                  if(strcmp(cmd->argv[0], "cd")==0){
                                  	if(cmd->argv[1]!=NULL){
                                  		chdir(cmd->argv[1]);
                                  	}
                                  }


                                  et ça marche parfaitement bien

                                  • Partager sur Facebook
                                  • Partager sur Twitter

                                  Message d'erreur execv

                                  × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                  × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                  • Editeur
                                  • Markdown