title: C mini shell, problems with handling SIGCHLD
body: <p>So i am implementing a mini C shell, it's supporting background processes. My idea was that for the background mode, the parent process doesn't wait for its children process to finish but rather register them in a job list and when they are done, i capture the SIGCHLD sig to empty their entry on my job list. Here's the code.</p>
  
  <pre><code>#include &lt;stdlib.h&gt;
  #include &lt;errno.h&gt;
  #include &lt;stdio.h&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;string.h&gt;
  #include &lt;unistd.h&gt;
  #include &lt;sys/types.h&gt;
  #include &lt;sys/time.h&gt;
  #include &lt;sys/resource.h&gt;
  #include &lt;signal.h&gt;
  #include &lt;wait.h&gt;
  
  #define DEFAULT_PROMPT "\nLog710H2014%&gt;"
  #define EXIT_CMD "exit"
  #define CD_CMD "cd"
  #define JOB_LIST_CMD "aptaches"
  #define HOME_ENV_VAR "HOME"
  #define NEW_LINE "\n**************************************************\n"
  #define BCG_CMD_FLAG "&amp;"
  
  void cd_handler(int argc, char *argv[]);
  int lire(char *chaine, int longueur);
  char** init_command(int* size,char *str);
  int execProg(int *argc, char **argv);
  int execProgBg(int *argc, char **argv);
  void sigchldHandler(int sig_num);
  void aptachesHandler();
  void cleanJobList(pid_t *childpid);
  
  struct beanProcess {
      pid_t pid;
      int job_num;
      char *command;
  };
  void ajoutProcess(struct beanProcess bp);
  
  
  struct beanProcess beans[20];
  int jobCount = 1;
  
  int main() {
      signal(SIGCHLD, sigchldHandler);
  
      printf(NEW_LINE);
      printf("Bienvenue sur le shell de l'equipe 1");
      printf(NEW_LINE);
  
      while(1){
          char str[200]="";
          printf(DEFAULT_PROMPT);
  
          lire(str, 200);
  
          int commArgsC = 0, bg = 0;
          char** comms  = init_command(&amp;commArgsC, str);
  
          if(commArgsC == 0){
              //printf("Saisie vide, veuillez entrez une commande.");
              continue;
          }
  
          if(strcmp(comms[commArgsC-1], BCG_CMD_FLAG) == 0){
              bg = 1;
              comms[commArgsC-1] = 0;
          }
  
          if(strcmp(comms[0], CD_CMD) == 0){
              cd_handler(commArgsC, comms);
              commArgsC = commArgsC -1;
          }
  
          else if (strcmp(comms[0], JOB_LIST_CMD) == 0){
              aptachesHandler();
          }
  
          else if (strcmp(comms[0], EXIT_CMD) == 0){
              int beansVide = 1;
              for(int i = 0; i &lt; jobCount -1 ; i++){
                  if(beans[i].pid != 0){
                      beansVide = 0;
                  }
              }
              if(beansVide){
                  exit(0);
              }else{
                  printf("\nImpossible d'arreter le programme, des processus sont encore en cours d'éxécution\n");
              }
          }
          else {
              if(bg){
                  execProgBg(&amp;commArgsC, comms);
              }
              else{
                  execProg(&amp;commArgsC, comms);
              }
          }
      }
      return 0;
  }
  void cd_handler(int argc, char *argv[]){
      char buff[512];
      char * directory;
  
      if(argc &lt; 2){
          directory  = getenv(HOME_ENV_VAR);
      }else if (argc == 2){
          directory = argv[1];
      }else{
          exit(1);
      }
  
      if (chdir(directory) == -1) {
          printf ("Erreur de changement de repertoire actif", strerror (errno));
      }else{
          if (getcwd(buff, sizeof(buff)) == NULL)
              perror("Impossible d'afficher le repertoire courant");
          else
              printf("le repertoire courant est: %s\n", buff);
      }
  }
  //Cette fonction est adaptée a partir du code de refp sur http://stackoverflow.com/questions/11198604/c-split-string-into-an-array-of-strings
  char** init_command(int* size, char* str){
      char ** res  = NULL;
      char *  p    = strtok (str, " ");
      int n_spaces = 0;
  
      while (p) {
          res = realloc (res, sizeof (char*) * ++n_spaces);
  
          if (res == NULL){
              exit (-1);
          }
          res[n_spaces-1] = p;
          p = strtok (NULL, " ");
      }
      res = realloc (res, sizeof (char*) * (n_spaces+1));
      res[n_spaces] = 0;
      *size = n_spaces;
      return res;
  }
  //cette fonction est tirée d'un exemple de http://fr.openclassrooms.com/informatique/cours/apprenez-a-programmer-en-c/recuperer-une-chaine-de-caracteres
  int lire(char *chaine, int longueur)
  {
      char *positionEntree = NULL;
      //printf ("\nje suis avant fgets et char est %s", chaine);
      if (fgets(chaine, longueur, stdin) != NULL)
      {
          //printf ("\nje suis apres fgets");
          positionEntree = strchr(chaine, '\n');
          if (positionEntree != NULL)
          {
              *positionEntree = '\0';
          }
          return 1;
      }
      else
      {
          return 0;
      }
  }
  int execProg(int *argc, char **argv){
      char path[30] = "/bin/";
      strcat(path,argv[0]);
      //printf("\nThis is the %d process executing the code in non bg mode\n", getpid());
      printf("Voici le resultat de l'execution de votre commande\n");
      pid_t  pid;
      pid = fork();
  
      if (pid &lt; 0) {
          perror("Creation de processus avec fork echouee");
          exit(-1);
      }
      else if (pid == 0) {
          if(execvp(argv[0], argv) == -1){
              //printf("\nthis is the child process %d executing the command in non bg mode\n", getpid());
              perror("execv");
              return EXIT_FAILURE;
          }
      }
      else {
          //printf("\nthis is the parent process %d showing the stats in non bg mode\n", getpid());
          struct rusage rusg;
          long temp, tempCpu;
          wait (NULL);
          getrusage(RUSAGE_CHILDREN, &amp;rusg);
          printf("\nStatistique de la commande %s:\n", argv[0]);
  
          temp = (rusg.ru_utime.tv_sec * 1000) + (rusg.ru_utime.tv_usec / 1000);
          tempCpu = (rusg.ru_stime.tv_sec * 1000) + (rusg.ru_stime.tv_usec / 1000);
  
          printf("\nLe temps wall-clock (ms): %ld", temp);
          printf("\nLe temps CPU (ms) %ld", tempCpu);
          printf("\nNB interruptions volontaires: %ld", rusg.ru_nvcsw);
          printf("\nNB interruptions involontaires: %ld", rusg.ru_nivcsw);
          printf("\nNB defaults de pages: %ld", rusg.ru_majflt);
          printf("\nNB defaults de pages satifaits du noyau : %ld", rusg.ru_minflt);
      }
      return EXIT_SUCCESS;
  }
  int execProgBg(int *argc, char **argv){
  
      //printf("\nThis is the %d process executing the code in  bg mode\n", getpid());
  
      pid_t  pid;
      pid = fork();
  
      if (pid &lt; 0) {
          perror("Creation de processus avec fork echouee");
          return EXIT_FAILURE;
      }
      else if (pid == 0) {
          //printf("This is the pid %d", getpid());
          //printf("\nthis is the child process %d executing the command in  bg mode\n", getpid());
  
          if(execvp(argv[0], argv) == -1){
              perror("execvp");
              return EXIT_FAILURE;
          }
      }
      else {
          //printf("\nthis is the parent process %d showing the queue in bg mode\n", getpid());
  
          printf("[%d] %d", jobCount, pid);
  
          struct beanProcess bP;
          bP.pid = pid;
          bP.job_num = jobCount;
          bP.command = argv[0];
  
          ajoutProcess(bP);
      }
      return EXIT_SUCCESS;
  }
  void sigchldHandler(int sig_num)
  {
      int status;
      pid_t childPid;
      childPid = waitpid(-1, &amp;status, WNOHANG);
      cleanJobList(&amp;childPid);
  }
  void ajoutProcess(struct beanProcess bP){
      beans[jobCount-1] = bP;
      jobCount++;
  }
  void aptachesHandler(){
      for(int i = 0; i &lt; jobCount-1 ; i++){
          printf("[%d] %d %s\n", beans[i].job_num, beans[i].pid, beans[i].command) ;
  
      }
  }
  void cleanJobList(pid_t *childpid){
      printf("clean performed on %d", *childpid);
      for(int i = 0; i &lt; jobCount-1 ; i++){
          if(beans[i].pid == *childpid){
              beans[i].pid = 0;
              beans[i].job_num = 0;
              beans[i].command = NULL;
          }
      }
  }
  </code></pre>
  
  <p>With this code i have two problems, first the sigchldHandler works and clean the list only if the BG command (let's say "ls &amp;") is the very first one that was executed. second problem is that with my aptaches command (equivalent to shell jobs) the string of the command name for all processes always takes the last command value, why is that ? Here is a sample of execution so that you see what i am talking about.</p>
  
  <pre><code>**************************************************
  Bienvenue sur le shell de l'equipe 1
  **************************************************
  
  Log710H2014%&gt;ls &amp;
  [1] 10466
  Log710H2014%&gt;Debug  PARTIE3.c
  clean performed on 10466
  Log710H2014%&gt;pwd &amp;
  [2] 10467
  Log710H2014%&gt;/home/shong/workspace/TP1_PARTIE_3
  
  
  Log710H2014%&gt;aptaches
  [0] 0 (null)
  [2] 10467 aptaches
  
  Log710H2014%&gt;
  </code></pre>
  
  <p>and another one:</p>
  
  <pre><code>**************************************************
  Bienvenue sur le shell de l'equipe 1
  **************************************************
  
  Log710H2014%&gt;ls
  Voici le resultat de l'execution de votre commande
  Debug  PARTIE3.c
  clean performed on -1
  Statistique de la commande ls:
  
  Le temps wall-clock (ms): 1
  Le temps CPU (ms) 0
  NB interruptions volontaires: 1
  NB interruptions involontaires: 3
  NB defaults de pages: 0
  NB defaults de pages satifaits du noyau : 315
  Log710H2014%&gt; ls &amp;
  [1] 10483
  Log710H2014%&gt;Debug  PARTIE3.c
  
  
  Log710H2014%&gt;pwd &amp;
  [2] 10484
  Log710H2014%&gt;/home/shong/workspace/TP1_PARTIE_3
  
  
  Log710H2014%&gt;aptaches
  [1] 10483 ptaches
  [2] 10484 aptaches
  
  Log710H2014%&gt;
  </code></pre>