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%>

为什么父进程与 lire() 函数重叠并在第一次执行后直接进入 execProg 函数?

4

1 回答 1

1

你在一个while循环中。当你的execProgBg函数返回时,无论它返回什么,循环都会继续进行。如果您想停止,您break需要exitexecProgBg.

为什么父进程与lire()函数重叠,第一次执行后直接进入execProg函数

我不知道你是如何执行你的程序的,但看起来第二次fgets失败了,你没有注意到,因为你没有检查lire函数的返回码。所以你继续并重用上一次调用的缓冲区。您似乎很可能通过EOF了该程序 - 也许通过按 ctrl-d。


我决定运行代码并通过在第一个ls &.


这是题外话,但需要一些解释:

exit;

这将评估函数出口,将其转换为函数指针并丢弃结果。它不调用函数。更重要的是,将 exit 作为最后一个语句调用main是没有意义的,因为main无论如何都会退出。你应该只是return some_code表明失败的成功。

于 2014-02-11T01:06:50.323 回答