I'm developing a shell
for my OS discipline. It was going well until some strange errors appeared! I can not give free(args)
because I get seg fault
, if I do not give this free
when executing several commands sometimes I find junk in the variable and also I get seg fault
because the behavior is unexpected!
Below is the main code:
void so_setup() {
rl_bind_key('\t', rl_complete);
read_history(HISTORY_FILE);
}
void so_dump(){
write_history(HISTORY_FILE);
}
/* Loop principal */
void so_loop(){
char *line,shell_prompt[1000];
char **args;
int status;
shell *s;
char *token;
char hostname[100];
/* Pega o caminho inicial */
s = (shell*) malloc(sizeof(shell));
s->caminho = (char*) malloc(sizeof(char)*1024);
getcwd(s->caminho,1024);
/* Pega o nome da maquina */
gethostname(hostname, sizeof(hostname));
do{
/* Encontra o ultimo valor do caminho para prompt */
token = strrchr(s->caminho,'/');
/* Imprime o prompt*/
snprintf(shell_prompt, sizeof(shell_prompt), "%s@%s> ",hostname,token+1);
/* Recebe a linha */
line = readline(shell_prompt);
if (!line)
break;
/* Adiciona a linha ao historico */
add_history(line);
/* Divide a linha em argumentos */
args = so_split_line(line);
/* Executa a linha */
status = so_execute(s,args);
free(line);
/****** ERRO AQUI *****/
// free(args);
}while(status);
}
/* Inicia um ou um grupo de processos */
int so_launch(shell *s,processo *p){
pid_t pid, wpid;
int status;
char comando[1014];
int fd[2], infile, outfile;
processo *aux;
/* Caso eu receba a entrada de outro arquivo usando < */
if(p->redirectIn){
infile = p->stdin;
}
else
infile = STDIN_FILENO;
/* Verifico o grupo de processos */
for(aux = p; aux; aux = aux->prox){
/* Se existir um proximo crio um pipe */
if(aux->prox){
if(pipe(fd) < 0){
perror("pipe");
exit(1);
}
outfile = fd[1];
}
else{
/* Caso nao exista um proximo eu verifico se a saida é padrao ou redirecionamento usando > */
if(aux->redirectOut){
outfile = aux->stdout;
}
else{
outfile = STDOUT_FILENO;
}
}
/* Dou o fork para criar o processo filho */
pid = fork();
if(pid == 0){
/* Caso estejamos no processo filho setamos os arquivos de entrada e saida */
if(infile != STDIN_FILENO){
dup2(infile,STDIN_FILENO);
close(infile);
}
if(outfile != STDOUT_FILENO){
dup2(outfile,STDOUT_FILENO);
close(outfile);
}
if(aux->args[0][0] == '.' && aux->args[0][1] == '/'){
sprintf(comando,"%s/%s",s->caminho,aux->args[0]);
if(execvp(comando, aux->args) == -1){
perror("shell");
}
}
else if(execvp(aux->args[0], aux->args) == -1){
perror("shell");
}
exit(1);
}
else if( pid < 0){
perror("shell");
}
else{
/* Caso estejamos no processo pai esperamos pro filho acabar */
do{
wpid = waitpid(pid, &status, WUNTRACED);
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
}
if(infile != STDIN_FILENO){
close(infile);
}
if(outfile != STDOUT_FILENO){
close(outfile);
}
infile = fd[0];
}
return 1;
}
/* Divide a linha em um vetor de argumentos */
char** so_split_line(char *line){
int buffsize = TOK_BUFFERSIZE;
int position = 0;
char **tokens = (char**) malloc(sizeof(char*) * buffsize);
char *token;
if(!tokens){
fprintf(stderr,"shell: erro de alocacao\n");
exit(EXIT_FAILURE);
}
/* Divide a linha em tokens */
token = strtok(line,TOK_DELIM);
while (token){
tokens[position] = token;
position++;
//fprintf(stdout,"********%s\n",tokens[position]);
/* Caso tenha estourado o tamanho dobra o mesmo */
if(position >= buffsize){
buffsize += TOK_BUFFERSIZE;
tokens = realloc(tokens, sizeof(char*) * buffsize);
if(!tokens){
fprintf(stderr,"shell: args = NULL;erro de alocacao");
exit(EXIT_FAILURE);
}
}
token = strtok(NULL,TOK_DELIM);
}
tokens[position] = NULL;
return tokens;
}
/* Verificando se nao possui nenhum redirecionamento */
void new_filenos(processo *p){
int i = 0;
int out = 0; // free(args);
FILE *new_stdout;
FILE *new_stdin;
processo *aux;
/* Caso seja um grupo de processos eu so verifico o ultimo */
if(p->prox){
aux = p->prox;
while(aux->prox) aux = aux->prox;
while(aux->args[i]){
if(aux->args[i] && !strcmp(aux->args[i],">")){
out = 1;
if(aux->args[i+1]){
new_stdout = fopen(aux->args[i+1],"w");
aux->stdout = fileno(new_stdout); // pego o numero do descritor do arquivo
aux->args[i+1] = NULL;
aux->redirectOut = 1; //aviso que esse processo tem redirecionamento pra saida
}
else{
fprintf(stderr,"Escreva um nome para o arquivo de saida, enviando para o padrao!\n");
}
aux->args[i] = NULL;
}
i++;
}
}
/* Caso não eu verifico se ele recebe uma entrada ou saida */
else{
while(p->args[i]){
if(!strcmp(p->args[i],"<") && !out){
if(p->args[i+1]){
new_stdin = fopen(p->args[i+1],"r");
p->stdin = fileno(new_stdin);
p->args[i+1] = NULL;
p->redirectIn = 1; // aviso que esse processo tem redirecionamento pra entrada
}
else{
fprintf(stderr,"Escreva um nome para o arquivo de entrada, enviando para o padrao!\n");
}
p->args[i] = NULL;
i++;
}
if(p->args[i] && !strcmp(p->args[i],">")){
out = 1;
if(p->args[i+1]){
new_stdout = fopen(p->args[i+1],"w");
p->stdout = fileno(new_stdout);
p->args[i+1] = NULL;
p->redirectOut = 1;
}
else{
fprintf(stderr,"Escreva um nome para o arquivo de saida, enviando para o padrao!\n");
}
p->args[i] = NULL;
}
i++;
}
}
}
/* Aloco recursivamente o grupo de processos */
processo* pipes(char **args,int index){
processo *p;
int i = index+1;
int j = 0;
p = (processo*) malloc(sizeof(p));
p->args = (char**) malloc(sizeof(char*)*sizeof(args));
/* Até meu grupo acabar ou eu encontrar um pipe | eu crio um processo com os argumentos */
while(args[i] && strcmp(args[i],"|")){
p->args[j] = (char*) malloc(sizeof(char)*(sizeof(args[i])));
strcpy(p->args[j],args[i]);
i++;
j++;
}
p->redirectOut = p->redirectIn = 0;
p->args[i] = NULL;
/* Caso eu ainda possua um proximo eu crio um outro processo na lista */
if(args[i+1]){
p->prox = pipes(args,i);
}
else{
/* Caso seja o ultimo eu finalizo */
p->prox = NULL;
}
return p;
}
/* Função para executar um comando */
int so_execute(shell *s,char **args){
processo *p;
if(args[0] == NULL){
return 1;
}
/* Crio o grupo de processos */
p = pipes(args,-1);
/* Verifico redirecionamentos */
new_filenos(p);
// fprintf(stderr,args[0]);
/* Verifico se não é alguma função builtIn */
if(!strcmp(args[0],"cd")){
return so_cd(s,args);
}
else if(!strcmp(args[0],"pwd")){
return so_pwd(s,args);
}
else if(!strcmp(args[0],"help")){
return so_help(args);
}
else if(!strcmp(args[0],"exit")){
return so_exit();
}
/* Caso nao seja executo o processo */
else{
return so_launch(s,p);
}
}
I believe the problem is in so_split_line()
but I can not find it!
Any help thank you !!
Edit:
The error is not in so_split_line()
, I tested it in isolation and there was no problem with deallocation.