URL: https://linuxfr.org/forums/programmation-c--2/posts/ma-j-galere-sur-un-simple-free-sur-un-string Title: ma j'galère sur un simple free sur un string Authors: gunsailor Date: 2019年08月28日T20:06:26+02:00 License: CC By-SA Tags: Score: 0 Salut à tous, j'ai acheté le livre de Christophe Blaess ( en personne ) sur la programmation système. Je suis tombé sur un truc intéressant page 695-696-697 du bouquin dans le chapitre 23 intitulé "Communication classique entre processus" concernant une "possibilité rarement proposée par les shell". Selon moi, à première vue, il s'agissait seulement de ce à quoi pourrait faire face un simple fichier ".sh". Mais en me penchant un peu sur la question, je me suis rendu compte des facultés d'un tel algorithme. Pipé des commandes pré-enregistrées dans une bdd au format ".json", créées à partir d'autres programmes, afin de les faire communiquer etc... Tu rends compte? Faire fonctionner la modularité du "c", en "c" même, ce sur un système basé sur ce procédé, j'ai nommé LINUX... Je vous présente, ci-après, comment je procède. En attendant voici le code disposé dans trois fichier: - fichier "process.h": #ifndef PROCESS_H #define PROCESS_H #include #include #include #include #include #include #include #include #include"file.h" typedef struct { char ***commands; int **args; char **result; int len; int size; int execcount; } process_datas; int process_pipe(char** commands, int fd[2], pid_t *son); int process_popen(char ** result, char** commands, int args, int *size); int process_finished(pid_t pid); int process_datas_internal(process_datas *p, char **result, int *size, int i); int process_append_cmd(char * param, process_datas * datas, int new_command); int process_exec(process_datas *p); int process_datas_destroy(process_datas *p); int process_datas_init(process_datas *p); #endif - fichier "process.c": #define _GNU_SOURCE #include"process.h" #include"file.h" extern char **environ; int process_pipe(char** commands, int fd[2], pid_t *son) { int tube_1[2]; int tube_2[2]; if ((pipe(tube_1) != 0) || (pipe(tube_2) != 0)) return EXIT_FAILURE; switch(*son = fork()) { case -1: close(tube_1[0]); close(tube_1[1]); close(tube_2[0]); close(tube_2[1]); fprintf(stderr, "fail to fork in process_pipe\n"); return errno; break; case 0: ; setpgid(0, 0); close(tube_1[1]); close(tube_2[0]); dup2(tube_1[0], STDIN_FILENO); dup2(tube_2[1], STDOUT_FILENO); execve(commands[0], commands, environ); perror("execve in process_pipe"); return errno; break; default: ; setpgid(*son, *son); close(tube_1[0]); close(tube_2[1]); fd[0] = tube_2[0]; fd[1] = tube_1[1]; } return EXIT_SUCCESS; } int process_popen(char ** result, char** commands, int args, int *size) { FILE* fd; int len = 0; for(int i = 0; i < args - 1; i++) { len += strlen(commands[i]) + 2; } char *command = malloc(len); char *c = command; for(int i = 0; i < args - 1; i++) { sprintf(command, "%s ", commands[i]); command += strlen(commands[i]) + 1; } if((fd = popen(c, "r")) != NULL) { if(file_fgetsn(result, fd, size)) { free(command - strlen(c)); pclose(fd); perror("fgetsn in process_popen"); return EXIT_FAILURE; } }else{ free(command - strlen(c)); perror("popen in process_popen"); return EXIT_FAILURE; } free(command - strlen(c)); pclose(fd); return EXIT_SUCCESS; } int process_append_cmd(char *param, process_datas *datas, int new_command) { if(!new_command) { if(datas->size) { int args = datas->args[datas->size - 1][1]++; if(args> datas->args[datas->size - 1][0]) { datas->args[datas->size - 1][0] += 1; datas->commands[datas->size - 1] = (char**)realloc(datas->commands[datas->size - 1], datas->args[datas->size - 1][0] * sizeof(char*)); } datas->commands[datas->size - 1][datas->args[datas->size - 1][1] - 1] = (char*) NULL; } datas->size++; if(!datas->len) { datas->len = datas->size; datas->args = (int **) calloc(datas->len, sizeof(int*)); datas->args[0] = (int*) calloc(2, sizeof(int)); datas->args[0][0] = 7; datas->args[0][1] = 1; datas->commands = (char***) calloc(datas->len, sizeof(char**)); datas->commands[0] = (char**) calloc(7, sizeof(char*)); }else if(datas->size> datas->len) { datas->len = datas->size; datas->args = (int **)realloc(datas->args, datas->len * sizeof(int*)); datas->args[datas->size - 1] = (int *)calloc(2, sizeof(int)); datas->args[datas->size - 1][0] = 7; datas->args[datas->size - 1][1] = 1; datas->commands = (char***) realloc(datas->commands, datas->len * sizeof(char**)); datas->commands[datas->size - 1] = (char **) calloc(7, sizeof(char*)); } }else{ int args = datas->args[datas->size - 1][1]++; if(!(args - datas->args[datas->size - 1][0])) { datas->args[datas->size - 1][0] += 7; datas->commands[datas->size - 1] = (char**) realloc(datas->commands[datas->size - 1], datas->args[datas->size - 1][0] * sizeof(char*)); } } datas->commands[datas->size - 1][datas->args[datas->size - 1][1] - 1] = strdup((char *)param); return EXIT_SUCCESS; } int process_finished(pid_t pid) { errno = 0; int status; while(1) { usleep(2000); pid_t check; if((check = waitpid(pid, &status, WNOHANG|WUNTRACED))> 0) { if(WIFEXITED(status)) { printf("%ld terminated successfully : %s\n", (long) pid, "signal OK !"); return EXIT_SUCCESS; }else if(WIFSIGNALED(status)) { printf("%ld terminated by signal : %s\n", (long) pid, strsignal(WTERMSIG(status))); }else if(WIFSTOPPED(status)) { printf("%ld stopped by signal : %s\n", (long) pid, strsignal(WSTOPSIG(status))); }else if(WIFCONTINUED(status)) { printf("%ld continued\n", (long) pid); } }else if(check == -1){ return errno; } } return EXIT_FAILURE; } int process_exec(process_datas *p) { int ret = 0; char * result = NULL; int size= 0; int args = p->args[p->size - 1][1]++; if(args> p->args[p->size - 1][0]) { p->args[p->size - 1][0] += 1; p->commands[p->size - 1] = realloc(p->commands[p->size - 1], p->args[p->size - 1][0] * sizeof(char*)); } p->commands[p->size - 1][p->args[p->size - 1][1] - 1] = (char*) NULL; p->execcount++; p->result = realloc(p->result, p->execcount * sizeof(char*)); if((ret = process_datas_internal(p, &result, &size, 0)) == EXIT_FAILURE) { free(result); fprintf(stderr, "Error in first command in process_exec: not / or bad internal process"); return EXIT_FAILURE; }else if(ret == 254 || ret == 255 || ret == EXIT_SUCCESS){ if((ret = process_popen(&result, p->commands[0], p->args[0][1], &size)) == EXIT_FAILURE) { if(result != NULL) free(result); fprintf(stderr, "Error in first command in process_exec from process_popen\n"); return EXIT_FAILURE; } } if(p->size == 1) { p->result[p->execcount - 1] = strdup(result); free(result); process_datas_init(p); return EXIT_SUCCESS; } int tube[2]; pid_t son; int error; for(int i = 1; i < p->size; i++) { if((ret = process_datas_internal(p, &result, &size, i)) == EXIT_FAILURE) { free(result); fprintf(stderr, "Bad internal process"); return EXIT_FAILURE; }else if(ret != EXIT_SUCCESS && ( i + 1 ) < p->size) ++i; if((ret = process_pipe(p->commands[i], tube, &son))) { free(result); fprintf(stderr, "fail to process_pipe in process_exec"); return errno; } if(fd_writen(tube[1], result, strlen(result), 1)) { free(result); fprintf(stderr, "fail to write in fd in process_exec"); return EXIT_FAILURE; } close(tube[1]); if((error = process_finished(son)) != EXIT_SUCCESS) { free(result); return error; } if(fd_readn(&result, tube[0], &size)) { free(result); fprintf(stderr, "fail to read from fd in process_exec"); return EXIT_FAILURE; } close(tube[0]); } p->result[p->execcount - 1] = strdup(result); free(result); process_datas_init(p); return EXIT_SUCCESS; } int process_datas_internal(process_datas *p, char **result, int *size, int i) { if(!strcmp(p->commands[i][0], "file")) { FILE *f = fopen(p->commands[i][1], "w+"); if (f == NULL) { free(*result); fprintf(stderr, "Error opening file in process_exec\n"); return EXIT_FAILURE; } fprintf(f, *result); fclose(f); return 254; }else if(!strcmp(p->commands[i][0], "cd")){ chdir(p->commands[i][1]); return 255; }else if(!strcmp(p->commands[i][0], "concat")){ int len = 0; for(int l = 1; l < p->args[i][1] - 1; l++) len += strlen(p->commands[i][l]) + 2; if(*size < len) *result = calloc(len, sizeof(char)); for(int l = 1; l < p->args[i][1] - 1; l++) { if(l == 1) strcpy(*result, p->commands[i][l]); else strcat(*result, p->commands[i][l]); } return 256; } return EXIT_SUCCESS; } int process_datas_init(process_datas *p) { for(int i = 0; i < p->size; i++) { for(int j = 0; j < p->args[i][1]; j++) { free(p->commands[i][j]); p->commands[i][j] = NULL; } p->args[i][1] = 1; } p->size = 0; return EXIT_SUCCESS; } int process_datas_destroy(process_datas *p) { for(int i = 0; i < p->len; i++) { for(int j = 0; j < p->args[i][1]; j++) { if(p->commands[i][j] != NULL) { free(p->commands[i][j]); p->commands[i][j] = NULL; } } free(p->commands[i]); p->commands[i] = NULL; } free(p->commands); p->commands = NULL; for(int i = 0; i < p->len; i++) { free(p->args[i]); p->args[i] = NULL; } free(p->args); p->args = NULL; p->len = 0; p->size = 0; for(int i = 0; i < p->execcount; i++) { free(p->result[i]); p->result[i] = NULL; } free(p->result); p->result = NULL; p->execcount = 0; return EXIT_SUCCESS; } - fichier "file.c" #include"file.h" int file_read(char **result, int *size) { FILE * file = (void*) NULL; struct stat status; char * content = (void*) NULL; if (stat(*result, & status) != 0) { perror("stat"); return EXIT_FAILURE; } if ((content = malloc(status.st_size)) == NULL) { perror("malloc"); return EXIT_FAILURE; } if ((file = fopen(*result, "r")) == NULL) { free(content); perror("fopen"); return EXIT_FAILURE; } if ((signed int)fread(content, 1, status.st_size, file) != status.st_size) { free(content); perror("fread"); return EXIT_FAILURE; } *size = status.st_size; *result = content; fclose(file); return EXIT_SUCCESS; } int file_fgetsn(char **result, FILE* fd, int *size) { int i = 0, j = 0; char buffer[64] = {'0円'}; if(!(*size>= 128)) { j = 128; *result = calloc(j, sizeof(char)); }else{ j = *size; } if(*result) { while(fgets(buffer, 64, fd) != NULL) { if(!i) strcpy(*result, buffer); else strcat(*result, buffer); i += strlen(buffer); if((j - i) < 64) { j = i + 128; *result = realloc(*result, j); if(*result == NULL) { perror("realloc in file_fgetsn"); return EXIT_FAILURE; } } } }else{ perror("malloc in file_fgetsn"); return EXIT_FAILURE; } *size = j; return EXIT_SUCCESS; } int fd_writen(const int sd, const char * b, const size_t s, const int retry_on_interrupt) { size_t n = s; while (0 < n) { ssize_t result = write(sd, b, n); if (-1 == result) { if ((retry_on_interrupt && (errno == EINTR)) || (errno == EWOULDBLOCK) || (errno == EAGAIN)) { continue; } else { break; } } n -= result; b += result; } if(0 < n){ perror("write in fd_writen"); return EXIT_FAILURE; }else{ return EXIT_SUCCESS; } } int fd_readn(char** result, int fd, int *size) { int m = 0; char buffer[2] = {'0円'}; while(read(fd, buffer, sizeof(char))) { if(!m) strcpy(*result, buffer); else strcat(*result, buffer); m += strlen(buffer); if((*size - m) < 64) { *size = m + 128; *result = realloc(*result, *size); } if(*result == NULL) { perror("realloc in file_read"); return EXIT_FAILURE; } } return EXIT_SUCCESS; } exemple "test.c": #define _DEFAULT_SOURCE #include #include #include #include #include"process.h" int main(int argc, char **argv) { int ret; process_datas p = {NULL, NULL, NULL, 0, 0, 0}; char *cwd = calloc(1,256); getcwd(cwd, 256); process_append_cmd("concat", &p, 0); process_append_cmd("j'adore ", &p, 1); process_append_cmd("windows", &p, 1); process_append_cmd("/bin/sed", &p, 0); process_append_cmd("-es;windows;linux;g", &p, 1); if(!(ret = process_exec(&p))) { printf("%s\n", p.result[0]); process_append_cmd("concat", &p, 0); process_append_cmd(p.result[0], &p, 1); process_append_cmd(" avec", &p, 1); process_append_cmd(" enthousiasme !!", &p, 1); if(!(ret = process_exec(&p))) { printf("%s\n", p.result[1]); }else{ free(cwd); process_datas_destroy(&p); fprintf(stderr, "failed: %s \n", strerror(ret)); exit(EXIT_FAILURE); } }else{ free(cwd); process_datas_destroy(&p); fprintf(stderr, "failed: %s \n", strerror(ret)); exit(EXIT_FAILURE); } process_datas_destroy(&p); free(cwd); return EXIT_SUCCESS; } Alors je sais que c'est un peu imbuvable question longueur, mais imaginez le potentiel en récursif... Alors mon problème, qui ne représente rien face à la tâche à accomplir, est que je n'arrive pas à libérer les variables concaténées ( d'où l'utilisation qui fonctionne dans le programme "test.c" ci-dessus ) lorsqu'il s'agit de simples caractères au niveau de l'appel à "process_datas_init" dans "process_exec". Si quelqu'un pouvait m'aider cela me permettrait de gagner du temps sur mon projet qui est largement entamé ( sous d'autres perspectives ) et en même temps de rendre hommage à un édifice du monde linuxien. Merci d'avance. PS: L'interface finale est destinée à être programmée en ncurses

AltStyle によって変換されたページ (->オリジナル) /