J’ai une « Erreur de segmentation (core dumped) » qui proviens je pense de la fonction strtok_r() mais que je n’arrive pas à corriger ;(
«je pense» ? Tu n'en es pas certain ? Tu n'as pas utilisé de debuger ou de memory profiler pour t'en assurer ?????
Rachid-Bellaali a écrit:
[...] Je dois utiliser strtok_r() parce que j’ai envie d’exécuter chaque ligne donc pour découper à chaque "\n" (saut de ligne).
Sais-tu que fgets fais exactement cela ? Enfin je dis ça je dis rien hein.
ah oui ... encore une chose : essaye de compiler avec les options qui te donnent un maximum d'indications sur ton code. Lorsque je prends ton bout de code et que je le fais j'obtiens ces warnings ⇒
$ gcc -Wall -Wextra -fanalyzer -o dumb dumb.c
dumb.c:14:6: warning: return type of ‘main’ is not ‘int’ [-Wmain]
14 | void main (int argc, char* argv[]) {
| ^~~~
dumb.c: In function ‘main’:
dumb.c:20:10: warning: unused variable ‘affichage’ [-Wunused-variable]
20 | char affichage[5]; // variable pour stocker les trucs avant de les afficher en stdout
| ^~~~~~~~~
dumb.c:19:9: warning: unused variable ‘qte’ [-Wunused-variable]
19 | int qte; // cmb de charactères ont été lus de popen_result
| ^~~
dumb.c: In function ‘my_popen’:
dumb.c:106:15: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
106 | while(quantite = read(pipefd[0], affichage, 5))
| ^~~~~~~~
dumb.c: In function ‘main’:
dumb.c:56:13: warning: use of NULL ‘saveptr’ where non-null expected [CWE-690] [-Wanalyzer-null-argument]
56 | ligne = strtok_r(contenu, "\n", saveptr); // on commence à couper le contenu par ligne
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
‘main’: events 1-12
|
| 22 | if (argc == 1) { // au moins un argument
| | ^
| | |
| | (1) following ‘false’ branch (when ‘argc != 1’)...
|......
| 27 | fd = open(argv[1], O_RDONLY); // ouvrir le fichier shell
| | ~
| | |
| | (2) ...to here
| 28 |
| 29 | if (fd == -1) { // vérifier que l'ouverture a marché
| | ~
| | |
| | (3) following ‘false’ branch (when ‘fd != -1’)...
|......
| 34 | size_read = read(fd, contenu, CONTENT_SIZE); // lire contenu du fichier shell
| | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (4) ...to here
| 35 |
| 36 | if (size_read == -1) { // si erreur lecture
| | ~
| | |
| | (5) following ‘false’ branch (when ‘size_read != -1’)...
|......
| 40 | else if (size_read == CONTENT_SIZE) { // si fichier plus grand que variable contenu
| | ~
| | |
| | (6) ...to here
| | (7) following ‘false’ branch (when ‘size_read != 2048’)...
|......
| 45 | if(close(fd) == -1) { // on a fini de travailler avec le fichier shell, -1 si erreur
| | ~~~~~~~~~~
| | ||
| | |(8) ...to here
| | (9) following ‘false’ branch...
|......
| 50 | contenu[size_read] = '\0'; // read n'ajoute pas \0 à la fin du string, donc on doit l'ajouter pour que le string soit bien formé
| | ~~~~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (10) ...to here
| | (11) ‘saveptr’ is NULL
|......
| 56 | ligne = strtok_r(contenu, "\n", saveptr); // on commence à couper le contenu par ligne
| | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (12) argument 3 (‘saveptr’) NULL where non-null expected
|
In file included from dumb.c:7:
/usr/include/string.h:350:14: note: argument 3 of ‘strtok_r’ must be non-null
350 | extern char *strtok_r (char *__restrict __s, const char *__restrict __delim,
| ^~~~~~~~
dumb.c: In function ‘my_popen’:
dumb.c:141:15: warning: use of NULL ‘saveptr2’ where non-null expected [CWE-690] [-Wanalyzer-null-argument]
141 | mot = strtok_r(ligne, " ", saveptr2);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
‘my_popen’: events 1-12
|
| 76 | if (strlen(ligne) == 0)
| | ^
| | |
| | (1) following ‘false’ branch...
|......
| 82 | if (pipe(pipefd) == -1) { //créer le pipe et vérifier qu'il n'y a pas d'erreur
| | ~~~~~~~~~~~~~
| | ||
| | |(2) ...to here
| | (3) following ‘false’ branch...
|......
| 87 | pid = fork(); // créer le processus fils
| | ~~~~~~
| | |
| | (4) ...to here
| 88 |
| 89 | if( pid < 0 ) { //erreur dans le fork
| | ~
| | |
| | (5) following ‘false’ branch (when ‘pid >= 0’)...
|......
| 94 | else if ( pid > 0 ) //dans le parent
| | ~
| | |
| | (6) ...to here
| | (7) following ‘false’ branch (when ‘pid <= 0’)...
|......
| 131 | int i = 0; // defini ici pour avoir accées en général !
| | ~
| | |
| | (8) ...to here
| 132 |
| 133 | if (close(pipefd[0]) == -1) { //on écrit dans le fils, donc on ferme le pipe en lecture
| | ~
| | |
| | (9) following ‘false’ branch...
|......
| 139 | char **saveptr2 = NULL;
| | ~~~~~~~~
| | |
| | (10) ...to here
| | (11) ‘saveptr2’ is NULL
| 140 |
| 141 | mot = strtok_r(ligne, " ", saveptr2);
| | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (12) argument 3 (‘saveptr2’) NULL where non-null expected
|
In file included from dumb.c:7:
/usr/include/string.h:350:14: note: argument 3 of ‘strtok_r’ must be non-null
350 | extern char *strtok_r (char *__restrict __s, const char *__restrict __delim,
| ^~~~~~~~
Je n'ai pas lu ton code, mais la description de ton erreur et les indication du compilo me laissent à penser que tu n'as pas lu la doc de strtok_r ⇒ la partie de la man page qui t'intéresse (àmha) :
On the first call to strtok_r(), str should point to the string to be parsed, and the value of *saveptr is ignored (but
see NOTES). In subsequent calls, str should be NULL, and saveptr (and the buffer that it points to) should be unchanged
since the previous call.
Edit: Bon j'ai parcouru ton code. Ça va, j'ai vu bien pire. Donc si tu veux quelques remarques :
fais des fonctions !!!!!! fais des fonctions !!!!!! FAIS DES FONCTIONS !!!!!!
oublie les commentaires !!! aucun des commentaires sur les variables au début du main nesert à quoi que ce soit si le nom des variables est clair. chaque commentaire à côté des fonctions indique que l'appel et les quelques lignes qui suivent ont une logique à être ensemble … oublie les commentaires et fais des fonctions
la lecture du script pêche mais j'imagine que tu vas adapter ça
les exit c'est un peu … violent, mais à nouveau j'imagine que que tu vas modifier cela
et main … main est une fonction qui renvoie un int !!!! on n'est plus en 1975 !!! le disco est mort en même temps que les void main … ok ok, techniquement il n'est jamais mort … ^_^
Qui est ? Parce que c'est toujours sympa de dire quelle était l'erreur et comment tu l'as résolue pour ceux qui vont lire ce sujet en ayant un problème similaire au tien …
@Rachid-Bellaali Bonsoir, on n'efface pas ses messages après avoir reçu de l'aide.
Je recopie ci après le message d'origine pour archive et ferme ce sujet.
Rachid-Bellaali a écrit:
Bonjour à tous, je débute en C et je suis entrain de crée un programme C sous LINUX qui reçoit en paramètre (via la ligne de commande) un shell script (shell file), c’est-à-dire un fichier contenant une suite de commandes shell.
Chacune des commandes du fichier doit être exécutée par un fils, qui renvoie les résultats au père via le pipe et le père affichera les résultats à l’écran.
J’ai une « Erreur de segmentation (core dumped) » qui proviens je pense de la fonction strtok_r() mais que je n’arrive pas à corriger ;(
Je dois utiliser strtok_r() parce que j’ai envie d’exécuter chaque ligne donc pour découper à chaque "\n" (saut de ligne).
Si quelqu'un pourrais m'aider ce serais gentil mercii.
Voici mon programme C :
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#define CONTENT_SIZE 2048 // constante pour pouvoir la changer plus facilement
void my_popen(char ligne[]);
void main (int argc, char* argv[]) {
int fd; // ça va contenir le fd du fichier à lire
char contenu[CONTENT_SIZE]; // ça va contenir le contenu du fichier
char* ligne; // ça va contenir que une ligne du fichier
ssize_t size_read; // ça va contenir cmb de charactères ont été lus
int qte; // cmb de charactères ont été lus de popen_result
char affichage[5]; // variable pour stocker les trucs avant de les afficher en stdout
if (argc == 1) { // au moins un argument
printf("Pas assez d'arguments.\n");
exit(0);
}
fd = open(argv[1], O_RDONLY); // ouvrir le fichier shell
if (fd == -1) { // vérifier que l'ouverture a marché
perror("Ouverture du fichier");
exit(1);
}
size_read = read(fd, contenu, CONTENT_SIZE); // lire contenu du fichier shell
if (size_read == -1) { // si erreur lecture
perror("Lecture du fichier");
exit(1);
}
else if (size_read == CONTENT_SIZE) { // si fichier plus grand que variable contenu
printf("Le fichier est trop grand pour être executé.\n");
exit(1);
}
if(close(fd) == -1) { // on a fini de travailler avec le fichier shell, -1 si erreur
perror("Fermeture du fichier");
exit(1);
};
contenu[size_read] = '\0'; // read n'ajoute pas \0 à la fin du string, donc on doit l'ajouter pour que le string soit bien formé
//char* *saveptr : saveptr est un pointeur qui pointe vers un pointeur char qui lui pointe vers un char (cghar* -> c'est un string)
char **saveptr = NULL;
ligne = strtok_r(contenu, "\n", saveptr); // on commence à couper le contenu par ligne
while(ligne != NULL) { // on va travailler tant qu'il y aura des lignes
my_popen(ligne);
ligne = strtok_r(NULL, "\n", saveptr); //on prend la ligne suivante et on récommence.
}
exit(0);
}
void my_popen(char ligne[])
{
pid_t pid; //stocke le résultat du fork -> pid_t psk c le meilleur pour stocker le result du PID
int pipefd[2]; //file descriptors pour intéragir avec le pipe (0 lecture, 1 écriture)
if (strlen(ligne) == 0)
{
return ;
}
if (pipe(pipefd) == -1) { //créer le pipe et vérifier qu'il n'y a pas d'erreur
perror("Problème création du Pipe().");
exit(1);
}
pid = fork(); // créer le processus fils
if( pid < 0 ) { //erreur dans le fork
perror("Problème avec le Fork() !");
exit(1);
}
else if ( pid > 0 ) //dans le parent
{
if (close(pipefd[1]) == -1) { //le parent lis, donc on ferme celui de ecriture
perror("Problème avec fermeture Pipe() du parent !");
exit(1);
}
// la ont va lire ce qui est dans le pipe
char affichage[5];
ssize_t quantite;
// enregistre le resultat du read dans la variable...
while(quantite = read(pipefd[0], affichage, 5))
{
if (quantite == -1){
perror("Probleme avec le Read() !");
exit(1);
}
if (write(STDOUT_FILENO, affichage, quantite) == -1){ // ecrit dans STDOUT, quantite (var) de caractere d'affichage
perror("Probleme avec le Write() !");
exit(1);
}
}
if (close(pipefd[0]) == -1) {// on ferme le pipe côté parent
perror("Problème fermeture Pipe() du parent !");
exit(1);
}
return; // psk void
}
else //dans le fils
{
char* paramsList[64];
int i = 0; // defini ici pour avoir accées en général !
if (close(pipefd[0]) == -1) { //on écrit dans le fils, donc on ferme le pipe en lecture
perror("Problème fermeture Pipe() du fils !");
exit(1);
}
char* mot; // pointeur vers un caractère
char **saveptr2 = NULL;
mot = strtok_r(ligne, " ", saveptr2);
//printf("Fils : %s\n", ligne);
while(mot) {
paramsList[i] = mot;
mot = strtok_r(NULL, " ", saveptr2);
i++;
}
paramsList[i] = NULL; //les fonctions execv demandent que la liste de paramètres termine par NULL.
//printf(" params : %s %s %s \n", paramsList[0], paramsList[1], paramsList[2]);
// si pas d'erreur avec dup2 -- file numéro 0
if (dup2(pipefd[1], STDOUT_FILENO) == -1) { // rediriger tous ce qui est dans le STD-OUT dans pipeFd[1]
perror("Probleme avec dup2() !");
exit(1);
}
if (execvp(paramsList[0], paramsList) == -1) {
perror("Probleme avec Execvp() !");
exit(1);
}
if (close(pipefd[1]) == -1) { //on ferme le pipe côté fils
perror("Problème fermeture Pipe() du fils !");
exit(1);
}
exit(0);
}
}
et mon ShellScript (attention il faut lui donner la permission x pour être exécuter)
Bellaali Abderrachid
Bellaali Abderrachid