• Viernes 8 de Noviembre de 2024, 12:33

Autor Tema:  Problema Al Programar Una Minishell  (Leído 1333 veces)

Zambullo

  • Nuevo Miembro
  • *
  • Mensajes: 2
    • Ver Perfil
Problema Al Programar Una Minishell
« en: Lunes 26 de Mayo de 2008, 21:16 »
0
¡Buenas!

Estoy un pelín desesperado. El caso es que estoy haciendo una minishell, que puede ejecutar funciones internas (se me pide que programe cd, pwd y algunos más) y las que no, que las ejecute el SO.

Tengo que usar tuberías y redirecciones. El problema que tengo es que cuando pongo cualquier orden con una tubería (hola | hola, por ejemplo), y según veo al ejecutar con strace, el programa hace bien las dos primeras vueltas del bucle (una redireccionando la entrada y otra redireccionando la salida) pero después, en vez de volverme a imprimir el prompt y esperar, lo escribe y sigue dando vueltas al bucle hasta que un SIGSEGV lo termina todo. Yo diría que tanto las tuberías como las señales están bien utilizadas, pero tampoco estoy seguro.

Este es el código de la parte de la que os hablo. Está en C y sobre Linux:

Código: Text
  1.  
  2. //Ejecuta lo que hay entre tuberías
  3. void ejecutar_orden(char *orden, int entrada, int salida , int background){
  4.  
  5.   int indentrada, indsalida, pid, descriptor;
  6.   int *hijos;
  7.   int hijo = 0, estado, i;
  8.   char **array;
  9.   //printf("ejecutar_orden\n");
  10.  
  11.   //parser_orden devuelve un array con la orden diseccionada. Ej. ls en la posicion 0, -l en la 1...
  12.   //También devuelve indentrada, indsalida por si hay < ó > y background 1 ó 0 si hay &
  13.   array = (char **)parser_orden(orden,&indentrada,&indsalida,&background);
  14.   //printf("indentrada %d\n",indentrada);
  15.  
  16.   if (indentrada > -1) {
  17.     printf("entra en indentrada\n");
  18.     if ((descriptor = open(array[indentrada+1], O_RDONLY)) == -1) {
  19.       printf("[Error] al redireccionar la entrada\n");
  20.       exit(-1);
  21.     }
  22.     else
  23.       redirec_entrada(descriptor);
  24.   }
  25.   if (indsalida > -1) {
  26.     if ((descriptor = open(array[indentrada+1], O_WRONLY)) == -1) {
  27.       printf("[Error] al redireccionar la salida\n");
  28.       exit(-1);
  29.     }
  30.     else
  31.       redirec_salida(descriptor);
  32.   }
  33.   if (ord_interna(array) != 0) { //Si no es una orden interna, ejecuta el SO
  34.     printf("No es orden interna\n");
  35.     if ((pid = fork()) == 0) { //Es hijo
  36.       if (execvp(array[0],array) == -1) {
  37.         printf("Error al ejecutar %s\n",array[0]);
  38.         exit(-1);
  39.       }
  40.       //Almaceno los pid de los hijos para que el padre los espere
  41.       hijos[hijo] = (int)malloc(sizeof(int));
  42.       hijos[hijo] = pid;
  43.       hijo++;
  44.     }
  45.     else { //Es padre
  46.       if (background) { //No espera a los hijos
  47.         printf("[Sistema] Ejecutando en segundo plano el proceso %d...\n",pid);
  48.         if(signal(SIGCHLD,manejar_sigchild)==SIG_ERR){
  49.           perror("Error en signal SIGCHLD.\n");
  50.           exit(-1);
  51.         }
  52.       }
  53.       else {  //Espera por los hijos
  54.         for (i = 0; i < hijo; i++) {
  55.           wait(&estado);
  56.         }
  57.       }
  58.     }
  59.   }
  60.        
  61.      
  62. }
  63. //Analiza la entrada a la shell
  64. void ejecutar_linea_ordenes(const char *orden) {
  65.  
  66.   char **lista_ordenes;
  67.   int **pipes;
  68.   int i = 0, total,entrada,salida,background;
  69.   //Disecciona la linea metida por teclado, con un array con las órdenes separadas según las tuberías
  70.   lista_ordenes = (char **)parser_pipes(orden, &total);
  71.   printf("total %d\n",total);
  72.   //crear_pipes crea tantas tuberías como diga total
  73.   pipes = (int **)crear_pipes(total);
  74.   while (i < total) {
  75.     printf("entra en el for\n");
  76.     entrada = 0;
  77.     salida = 0;
  78.     if (total == 1) { //No hay tubería
  79.       printf("entra en el if de total = 1\n");}
  80.     else { //Al menos hay una tubería
  81.       if (i == 0) { //Primera tubería
  82.         printf("entra en el if de i = 0\n");
  83.         salida = pipes[i][1];
  84.         //redirecciona la salida estandar
  85.         redirec_salida(salida);
  86.       }
  87.       else { //Tubería intermedia
  88.         if (i != total - 1) {
  89.           printf("entra en el if intermedio\n");
  90.           entrada = pipes[i-1][0];
  91.           salida = pipes[i][1];
  92.           //Redirecciona la entrada estandar
  93.           redirec_entrada(entrada);
  94.           redirec_salida(salida);
  95.         }
  96.         else { //Última tubería
  97.           printf("entra en el if final\n");
  98.           entrada = pipes[i-1][0];
  99.           redirec_entrada(entrada);
  100.         }
  101.       }
  102.     }
  103.     printf("antes de ejecutar_orden\n");
  104.     ejecutar_orden(lista_ordenes[i],entrada,salida,background);
  105.     i ++;
  106.   }
  107.   printf("Borrar cosas\n");
  108.   for(i=(total-1);i>=0;i--)  free(lista_ordenes[i]);
  109.     free(lista_ordenes); //Liberamos memoria del vector
  110.   destruir_pipes(pipes,total); //Borramos las tuberías
  111. }
  112.  

La función main y el manejador de señal son estos:

Código: Text
  1. void manejar_sigchild(){
  2.   //El hijo ha muerto y eliminamos su PCB
  3.   printf("Ojú\n");
  4.   int estado;  
  5.   wait(&estado);  
  6.   if(signal(SIGCHLD,manejar_sigchild)==SIG_ERR){
  7.     perror("[Sistema] Error, tratamiento de señal SIGCLD");
  8.     exit(0);
  9.   }
  10. }
  11.  
  12. int main(int argc,char* argv[]) {
  13.     char *buf;
  14.     int i = 1;
  15.     signal(SIGCHLD,&manejar_sigchild); //Inicia el manejador de señal
  16.     //signal(SIGINT,manejar_sigkill);
  17.     while (i!=0) {
  18.     buf = (char *)malloc(1024*sizeof(char));
  19.     free(buf);
  20.     imprimir_prompt();
  21.     leer_linea_ordenes(buf);
  22.     if (((strcmp(buf,"exit\0"))==0) || ((strcmp(buf,"quit\0"))== 0))
  23.        i = 0;
  24.     else {
  25.     printf("Entra en el else antes de ejecutarlineaordenes\n");
  26.        ejecutar_linea_ordenes(buf);}
  27.     }
  28.     return 0;
  29. }
  30.  

Si alguno teneis paciencia para mirarlo, os lo agradecería mucho.  :)

Zambullo

  • Nuevo Miembro
  • *
  • Mensajes: 2
    • Ver Perfil
Re: Problema Al Programar Una Minishell
« Respuesta #1 en: Martes 27 de Mayo de 2008, 19:28 »
0
Sé que mirar el código de otro es un tostón. Voy a intentar acotar la duda, porque hay una cosa que está mal y seguro que como poco es parte del problema, pero no sé solucionarlo.

En la funcion ejecutar_orden, cojo el pid con fork, y si es hijo ejecuta la orden. El caso es que cuando pongo órdenes con tuberías,el pid nunca vale 0, y por tanto no entra en el if y no se ejecuta nada. Pero si pongo una orden suelta sin tuberías ni redirecciones, sí funciona correctamente. ¿Cómo lo soluciono? Gracias de antemano.