2014-02-11 27 views
0

它是c中的一些linux shell的实现。由于我已经添加了后台进程支持,我有一些输出,我不明白。下面是代码:为什么我的流程表现得像这样?

#include <stdlib.h> 
#include <errno.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include <sys/time.h> 
#include <sys/resource.h> 
#include <signal.h> 
#include <wait.h> 

#define DEFAULT_PROMPT "\nLog710H2014%>" 
#define EXIT_CMD "exit" 
#define CD_CMD "cd" 
#define HOME_ENV_VAR "HOME" 
#define NEW_LINE "\n**************************************************\n" 
#define BCG_CMD_FLAG "&" 

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); 

struct beanProcess { 
    pid_t pid; 
    int job_num; 
    char *command; 
}; 

struct beanProcess *beans; 

int jobCount = 1; 

int main() { 

    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(&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], EXIT_CMD) == 0){ 
      exit(0); 
     } 
     else { 
      if(bg){ 
       execProgBg(&commArgsC, comms); 
      } 
      else{ 
       execProg(&commArgsC, comms); 
      } 
     } 
    } 
    exit; 
} 
void cd_handler(int argc, char *argv[]){ 
    char buff[512]; 
    char * directory; 

    if(argc < 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; 

    if (fgets(chaine, longueur, stdin) != NULL) 
    { 
     positionEntree = strchr(chaine, '\n'); 
     if (positionEntree != NULL) 
     { 
      *positionEntree = '\0'; 
     } 
     return 1; 
    } 
    else 
    { 
     return 0; 
    } 
} 
int execProg(int *argc, char **argv){ 
    char path[] = "/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 < 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, &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){ 

    signal(SIGCHLD, sigchldHandler); 
    printf("\nThis is the %d process executing the code in bg mode\n", getpid()); 

    pid_t pid; 
    pid = fork(); 

    if (pid < 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); 
     jobCount++; 
     //cleanJobList(childPid); 

     //ajoutProcess(); 
    } 
    return EXIT_SUCCESS; 
} 
void sigchldHandler(int sig_num) 
{ 
    int status; 
    int childPid; 
    childPid = waitpid(-1, &status, 1); 
    printf("Hello the process %d has died\n", childPid); 
    //cleanJobList(childPid); 
} 

当我执行如“ls &”一个bg命令,这里的输出:

************************************************** 
Bienvenue sur le shell de l'equipe 1 
************************************************** 

Log710H2014%>ls & 

This is the 23464 process executing the code in bg mode 

this is the parent process 23464 showing the queue in bg mode 
[1] 23472 
Log710H2014%> 
this is the child process 23472 executing the command in bg mode 
Debug PARTIE3.c 
Hello the process 23472 has died 

This is the 23464 process executing the code in non bg mode 
Voici le resultat de l'execution de votre commande 

this is the parent process 23464 showing the stats in non bg mode 
Debug PARTIE3.c 

Statistique de la commande ls: 

Le temps wall-clock (ms): 0 
Le temps CPU (ms) 2 
NB interruptions volontaires: 2 
NB interruptions involontaires: 9 
NB defaults de pages: 0 
NB defaults de pages satifaits du noyau : 644 
Log710H2014%> 

这是为什么父进程重叠里拉()函数和直接进入execProg函数在第一次执行后?

+0

'Debug PARTIE3.c'从哪里来? – Nabla

+0

命令ls& – user2966439

回答

1

您在while循环中。当你的函数返回时,无论它返回什么,循环都会继续。如果你想停止,你需要break或致电exitexecProgBg

这是为什么父进程重叠里拉()函数和 直接进入execProg函数的第一个执行后

我不知道你是如何执行你的程序,但它看起来像第二次fgets失败,您不会注意到,因为您不检查lire函数的返回码。所以你继续并重新使用之前调用的缓冲区。看起来你可能会通过EOF这个程序 - 也许是按ctrl-d。


我决定运行代码并获得与OP确实通过敲击第一ls &后CTRL-d相同的结果。


这是除了点,但值得一些解释:

exit; 

该评估函数退出其转换为一个函数指针和扔掉的结果。 它不会调用函数。更重要的是,由于main正在退出,所以将退出命令作为main的最后一个语句是毫无意义的。你应该只是return some_code表示失败的成功。

+0

我已经纠正了退出问题,但仍然为什么我的prog在循环的第二次迭代中不阻塞lire函数(其中包含来自stdin的fgets)? – user2966439

+0

@Nabla这个问题在此期间进行了编辑,第一次我没有看到第二部分。看着。 – cnicutar

+0

@Nabla'fgets'失败。它看起来像EOF,但可能是一些微妙的东西。 – cnicutar

相关问题