1. Este site usa cookies. Ao continuar a usar este site está a concordar com o nosso uso de cookies. Saber Mais.

Trouble with fork(), exec(), sigaction()...

Discussão em 'Programação' iniciada por The_True_Eue, 14 de Maio de 2008. (Respostas: 0; Visualizações: 929)

  1. The_True_Eue

    The_True_Eue Power Member

    Ok, estou a escrever uma pequena shell como um exercício para SO (Sistemas Operativos).
    Para já tenho este código:
    Código:
    [SIZE=2]#include <stdlib.h>[/SIZE]
    [SIZE=2]#include <stdio.h>[/SIZE]
    [SIZE=2]#include <readline/readline.h>[/SIZE]
    [SIZE=2]#include <readline/history.h>[/SIZE]
    [SIZE=2]#include <string.h>[/SIZE]
    [SIZE=2]#include <unistd.h>[/SIZE]
    [SIZE=2]#include <wordexp.h>[/SIZE]
    [SIZE=2]#include <sys/types.h>[/SIZE]
    [SIZE=2]#include <sys/wait.h>[/SIZE]
    [SIZE=2]#include <signal.h>[/SIZE]
    [SIZE=2]#include <errno.h>[/SIZE]
    [SIZE=2]#include "utility.h"[/SIZE]
    [SIZE=2][/SIZE] 
    [SIZE=2]// Builtins[/SIZE]
    [SIZE=2]#define CMD_EXIT 1[/SIZE]
    [SIZE=2]#define CMD_WHATEVER 2[/SIZE]
    [SIZE=2]static char *prompt;[/SIZE]
    [SIZE=2]static int chldfail = 0;[/SIZE]
     
    [SIZE=2]int init(void);[/SIZE]
    [SIZE=2]int processCmd(void);[/SIZE]
    [SIZE=2]char *readCmd(void);[/SIZE]
    [SIZE=2]int runCmd(wordexp_t * words);[/SIZE]
    [SIZE=2]int runBuiltin(int builtin);[/SIZE]
    [SIZE=2]void sighandle(int sig);[/SIZE]
    [SIZE=2][/SIZE] 
    [SIZE=2]int init()[/SIZE]
    [SIZE=2]{[/SIZE]
    [SIZE=2]}[/SIZE]
    [SIZE=2][/SIZE] 
    [SIZE=2]int processCmd()[/SIZE]
    [SIZE=2]{[/SIZE]
    [SIZE=2]  static int first = 1;[/SIZE]
    [SIZE=2]  char *cmd;[/SIZE]
    [SIZE=2]  static wordexp_t words;[/SIZE]
    [SIZE=2]  int flags;[/SIZE]
    [SIZE=2]  int exit_status;[/SIZE]
    [SIZE=2][/SIZE] 
    [SIZE=2]  cmd = readCmd();[/SIZE]
    [SIZE=2]  // TODO: Perform some preprocessing to process the following characters:[/SIZE]
    [SIZE=2]  // |&;<>[/SIZE]
    [SIZE=2]  if(first)[/SIZE]
    [SIZE=2]    flags = first = 0;[/SIZE]
    [SIZE=2]  else[/SIZE]
    [SIZE=2]    flags = WRDE_REUSE;[/SIZE]
    [SIZE=2]  if(wordexp(cmd, &words, flags))[/SIZE]
    [SIZE=2]  {[/SIZE]
    [SIZE=2]    puts("Syntax error");[/SIZE]
    [SIZE=2]  }[/SIZE]
    [SIZE=2]  else[/SIZE]
    [SIZE=2]  {[/SIZE]
    [SIZE=2]    if(strcmp(words.we_wordv[0], "exit") == 0)[/SIZE]
    [SIZE=2]    {[/SIZE]
    [SIZE=2]      wordfree(&words);[/SIZE]
    [SIZE=2]      return runBuiltin(CMD_EXIT);[/SIZE]
    [SIZE=2]    }[/SIZE]
    [SIZE=2]    exit_status = runCmd(&words);[/SIZE]
    [SIZE=2]  }[/SIZE]
    [SIZE=2]  return 0;[/SIZE]
    [SIZE=2]}[/SIZE]
     
    [SIZE=2]char *readCmd()[/SIZE]
    [SIZE=2]{[/SIZE]
    [SIZE=2]  char *cmd;[/SIZE]
    [SIZE=2]  cmd = readline(prompt);[/SIZE]
    [SIZE=2]  add_history(cmd);[/SIZE]
    [SIZE=2]  return cmd;[/SIZE]
    [SIZE=2]}[/SIZE]
    [SIZE=2][/SIZE] 
    [SIZE=2]int runCmd(wordexp_t * words)[/SIZE]
    [SIZE=2]{[/SIZE]
    [SIZE=2]  pid_t cpid;[/SIZE]
    [SIZE=2]  int i;[/SIZE]
    [SIZE=2]  TRACE("Command: %s", words->we_wordv[0]);[/SIZE]
    [SIZE=2]  TRACE("Args:");[/SIZE]
    [SIZE=2]  for(i = 1; i < words->we_wordc; i++)[/SIZE]
    [SIZE=2]    TRACE("%s", words->we_wordv[i]);[/SIZE]
    [SIZE=2]  cpid = fork();[/SIZE]
    [SIZE=2]  if(cpid == -1)[/SIZE]
    [SIZE=2]  {[/SIZE]
    [SIZE=2]    perror("fork");[/SIZE]
    [SIZE=2]  }[/SIZE]
    [SIZE=2]  else if(cpid == 0)[/SIZE]
    [SIZE=2]  {[/SIZE]
    [SIZE=2]    TRACE("Hello from child!");[/SIZE]
    [SIZE=2]    // I'm a new born child, let's build some personality![/SIZE]
    [SIZE=2]    execvp(words->we_wordv[0], words->we_wordv);[/SIZE]
    [SIZE=2]    TRACE("Ooops from child!");[/SIZE]
    [SIZE=2]    perror(words->we_wordv[0]);[/SIZE]
    [SIZE=2]    // How do I tell father something went wrong?[/SIZE]
    [SIZE=2]    // SIGUSR1[/SIZE]
    [SIZE=2]    kill(getppid(), SIGUSR1);[/SIZE]
    [SIZE=2]    exit(1);[/SIZE]
    [SIZE=2]  }[/SIZE]
    [SIZE=2]  else[/SIZE]
    [SIZE=2]  {[/SIZE]
    [SIZE=2]    pause();[/SIZE]
    [SIZE=2]    TRACE("Pause 1 done.");[/SIZE]
    [SIZE=2]    if(chldfail)[/SIZE]
    [SIZE=2]    {[/SIZE]
    [SIZE=2]      pause();[/SIZE]
    [SIZE=2]      TRACE("Pause 2 done.");[/SIZE]
    [SIZE=2]    }[/SIZE]
    [SIZE=2]  }[/SIZE]
    [SIZE=2]  TRACE("Leaving runCmd()");[/SIZE]
    [SIZE=2]  return 0;[/SIZE]
    [SIZE=2]}[/SIZE]
    [SIZE=2][/SIZE] 
    [SIZE=2]int runBuiltin(int builtin)[/SIZE]
    [SIZE=2]{[/SIZE]
    [SIZE=2]  switch (builtin)[/SIZE]
    [SIZE=2]  {[/SIZE]
    [SIZE=2]  case CMD_EXIT:[/SIZE]
    [SIZE=2]    return CMD_EXIT;[/SIZE]
    [SIZE=2]  default:[/SIZE]
    [SIZE=2]    return 0;[/SIZE]
    [SIZE=2]  }[/SIZE]
    [SIZE=2]}[/SIZE]
    [SIZE=2][/SIZE] 
    [SIZE=2]void sighandle(int sig)[/SIZE]
    [SIZE=2]{[/SIZE]
    [SIZE=2]  int status;[/SIZE]
    [SIZE=2]  switch (sig)[/SIZE]
    [SIZE=2]  {[/SIZE]
    [SIZE=2]  case SIGUSR1:[/SIZE]
    [SIZE=2]    // Child could not start[/SIZE]
    [SIZE=2]    TRACE("Got SIGUSR1");[/SIZE]
    [SIZE=2]    chldfail = 1;[/SIZE]
    [SIZE=2]    break;[/SIZE]
    [SIZE=2]  case SIGCHLD:[/SIZE]
    [SIZE=2]    // Child terminated[/SIZE]
    [SIZE=2]    TRACE("Got SIGCHLD");[/SIZE]
    [SIZE=2]    TRACE("Waiting for child to terminate...");[/SIZE]
    [SIZE=2]    waitpid(-1, &status, 0);[/SIZE]
    [SIZE=2]    if(chldfail)[/SIZE]
    [SIZE=2]    {[/SIZE]
    [SIZE=2]      TRACE("Failed child, ignoring...");[/SIZE]
    [SIZE=2]      chldfail = 0;[/SIZE]
    [SIZE=2]    }[/SIZE]
    [SIZE=2]    else if(WIFEXITED(status))[/SIZE]
    [SIZE=2]    {[/SIZE]
    [SIZE=2]      TRACE("Child terminated with code: %d", WEXITSTATUS(status));[/SIZE]
    [SIZE=2]    }[/SIZE]
    [SIZE=2]    else[/SIZE]
    [SIZE=2]    {[/SIZE]
    [SIZE=2]      TRACE("Child terminated abnormally.");[/SIZE]
    [SIZE=2]    }[/SIZE]
    [SIZE=2]    break;[/SIZE]
    [SIZE=2]  }[/SIZE]
    [SIZE=2]}[/SIZE]
    [SIZE=2][/SIZE] 
    [SIZE=2]int main(int argc, char *argv[])[/SIZE]
    [SIZE=2]{[/SIZE]
    [SIZE=2]  struct sigaction act;[/SIZE]
    [SIZE=2]  // Register signal handlers[/SIZE]
    [SIZE=2]  act.sa_handler = sighandle;[/SIZE]
    [SIZE=2]  sigemptyset(&act.sa_mask);[/SIZE]
    [SIZE=2]  sigaddset(&act.sa_mask, SIGUSR1);[/SIZE]
    [SIZE=2]  sigaddset(&act.sa_mask, SIGCHLD);[/SIZE]
    [SIZE=2]  act.sa_flags = 0;[/SIZE]
    [SIZE=2]  sigaction(SIGUSR1, &act, NULL);[/SIZE]
    [SIZE=2]  sigaction(SIGCHLD, &act, NULL);[/SIZE]
    [SIZE=2]  // TODO: Decent prompt[/SIZE]
    [SIZE=2]  prompt = strdup("vsh> ");[/SIZE]
    [SIZE=2]  // (Almost) infinite (almost) empty command processing loop[/SIZE]
    [SIZE=2]  while(processCmd() != CMD_EXIT)[/SIZE]
    [SIZE=2]    DO_NOTHING_ELSE;[/SIZE]
    [SIZE=2]  return 0;[/SIZE]
    [SIZE=2]}[/SIZE]
    [SIZE=2]// vim:ts=4:sw=4:nowrap:tw=78:[/SIZE]
    
    O problema é que, às vezes (mas só às vezes!), quando corro um comando, recebo o SIGCHLD, mas runCmd() nunca retorna. Também me acontece quando o comando não existe e recebo o SIGUSR1. O problema é que nem sempre acontece. Já consegui correr 5 ls seguidos sem problemas, mas também já tive problemas logo à primeira.
    Ajuda, anyone?
     
    Última edição: 14 de Maio de 2008

Partilhar esta Página