Problemas para crear un shell en C (Seg-Fault y ferror)
-
13-12-2019 - |
Pregunta
He estado siguiendo un tutorial sobre cómo hacer mi propio caparazón, pero llevo un par de días estancado.
Dos cosas:
- Cuando este código se compila y ejecuta, tendrá fallas de segmentación aleatoriamente y no puedo entender por qué.
- La declaración if `if (ferror! = 0)` siempre parece ser cierta.lo cual es raro porque no entiendo por qué fget() está fallando en el principal() función.
Cualquier información sobre estos temas (u otros temas sobre la creación de este shell) será muy apreciada.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#define MAXSIZE 512
int parseCmd(char *cmd, char *args[])
{
printf("LOGGER: parseCmd(cmd=%s, args=%p)\n", cmd, args);
char cmdDelims[] = {' ','>'};
char *cmdReader;
cmdReader = strtok(cmd, cmdDelims);
int i = 0;
while (cmdReader != NULL)
{
args[i] = strdup(cmdReader);
printf("LOGGER: args[%d]=%s\n", i, args[i]);
cmdReader = strtok(NULL, cmdDelims);
i++;
}
return 0;
}
void printToLine(char *args[])
{
int length;
length = sizeof(args) / sizeof(char);
int i = 0;
while (i < length)
{
printf("%s\n", args[i]);
i++;
}
}
int main(int argc, char *argv[])
{
char *in;
in = malloc(MAXSIZE);
char *args[15];
char *cmd = NULL;
int errorBit = 0;
int terminationBit = 1;
char error_message[30] = "An error has occurred\n";
char inDelims[] = "\n";
while (terminationBit)
{
printf("mysh>");
// get input from command line
fgets(in, MAXSIZE, stdin);
if (ferror != 0)
{
perror(error_message);
}
// get pointer to command line input w/o the newline
cmd = strtok(in, inDelims);
// parse the command into separate arguments
errorBit = parseCmd(cmd, args);
if (errorBit)
{
perror(error_message);
exit(1);
}
printToLine(args);
// check if the user wants to exit the shell
if (strcmp(*args, "exit") == 0)
{
terminationBit = 0;
}
}
return 0;
}
A continuación se muestran algunos resultados:
**[ray@12] (6)$ mysh**
mysh>1 2 3
An error has occurred
: Success
LOGGER: parseCmd(cmd=1 2 3, args=0x7fff4a50b080)
LOGGER: args[0]=1
LOGGER: args[1]=2
LOGGER: args[2]=3
1
2
3
Segmentation fault (core dumped)
**[ray@12] (7)$ mysh**
mysh>1 2 3 4 5 6 7 8 9 10
An error has occurred
: Success
LOGGER: parseCmd(cmd=1 2 3 4 5 6 7 8 9 10, args=0x7fffba053d70)
LOGGER: args[0]=1
LOGGER: args[1]=2
LOGGER: args[2]=3
LOGGER: args[3]=4
LOGGER: args[4]=5
LOGGER: args[5]=6
LOGGER: args[6]=7
LOGGER: args[7]=8
LOGGER: args[8]=9
LOGGER: args[9]=10
1
2
3
4
5
6
7
8
mysh>1 2 3
An error has occurred
: Success
LOGGER: parseCmd(cmd=1 2 3, args=0x7fffba053d70)
LOGGER: args[0]=1
LOGGER: args[1]=2
LOGGER: args[2]=3
1
2
3
4
5
6
7
8
Solución
Para el ferror
error, necesitas probar ferror(stdin)
, no ferror
.Esta última es la dirección de la función, que nunca será cero:
if (ferror(stdin) != 0)
{
perror(error_message);
}
Al menos para algunos de los fallos de segmento, esto no hace lo que piensas:
length = sizeof(args) / sizeof(char);
esto te dira ¿Cuántos bytes se utilizan para almacenar el puntero?, que es 4 u 8 dependiendo, y no el número de argumentos.
Entonces, si tiene cuatro (u ocho) argumentos, será aparecer trabajar.Si tiene más, parecerá ignorar algunos argumentos.Y si tiene menos, buscará los argumentos que faltan a través del Vacío, lo que resultará en una falla de segmentación (casi segura).
necesitas calcular length
independientemente y pasarlo, o almacenar algún terminador en args
, por ejemplo agregando un argumento NULL después del último argumento válido que encuentre:
cmdReader = strtok(NULL, cmdDelims);
i++;
}
args[i] = NULL;
return 0;
}
void printToLine(char *args[])
{
int i = 0;
while (args[i])
{
printf("%s\n", args[i]);
i++;
}
}