2016-04-13 18 views
0

Wo in meinem Code sollte ich "warten, bis Kinder fertig sind"? Ich habe ein C-Programm, das einer benutzerdefinierten Shell ähnelt. Jetzt habe ich eine eingebaute Funktion checkEnv, die die sortierten Umgebungsvariablen drucken kann. So kann ich meine Shell starten und die Liste meiner Umgebungsvariablen:Welches Signal soll ich behandeln und wie?

$ ./a.out 
miniShell>> checkEnv 
"'><;|&(: 
_=./a.out 
CLUTTER_IM_MODULE=xim 
COMPIZ_CONFIG_PROFILE=ubuntu 
COMP_WORDBREAKS=   
DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-mh5oMhyCI6 
DEFAULTS_PATH=/usr/share/gconf/ubuntu.default.path 
DESKTOP_SESSION=ubuntu 

Der Code hinter das bedeutet dies folgendes:

if(StartsWith(line, "checkEnv")) { 
    built_in_command=1; 
    pagerValue = getenv ("PAGER"); 
    if (! pagerValue) { 
     if (ret == 0) { 
     pager_cmd[0]="less"; 
     } else { 
     pager_cmd[0]="more"; 
     } 
    } 
    else { 
    pager_cmd[0]=pagerValue; 
    } 


    if(i==1) { 
     cmd[0].argv= printenv; 
     cmd[1].argv= sort; 
     cmd[2].argv= pager_cmd; 
     fork_pipes(3, cmd); 


    } 
    else { 

    for (k = 1; k < i; k++) 
    { 
     len += strlen(argv2[k]) + 2; 
    } 
    tmp = (char *) malloc(len); 
    tmp[0] = '\0'; 
    for (k = 1; k < i; k++) 
    { 
     pos += sprintf(tmp + pos, "%s%s", (k == 1 ? "" : "|"), argv2[k]); 
    } 
    grep[0]="grep"; 
    grep[1]="-E"; 
    grep[2]= tmp; 
    grep[3]= NULL; 
    cmd2[0].argv= printenv; 
    cmd2[1].argv= grep; 
    cmd2[2].argv= sort; 
    cmd2[3].argv= pager_cmd; 
    fork_pipes(4, cmd2); 
    free(tmp); 

      } 

Jetzt möchte ich die Ausgangsabschlußsignal zu fangen, wenn die Umgebungsvariablen listing Verwenden des Pagers, damit das Programm zur benutzerdefinierten Shell zurückkehrt, statt das gesamte Programm zu beenden. Also nehme ich an, dass ich etwas Signalverarbeitung verwenden sollte, aber wie und welches Signal?

Die eigentliche Gabel ist von dieser Funktion.

/* Helper function that forks pipes */ 
void fork_pipes(int n, struct command *cmd) { 
    int i; 
    int in = 0; 
    int fd[2]; 
    /** loop and fork() */ 
    for (i = 0; i < n - 1; ++i) { 

     if (pipe(fd) == -1) { 
      err_syserr("Failed creating pipe"); 
     } 

     spawn_proc(in, fd[1], cmd + i); 
     close(fd[1]); 
     in = fd[0]; 
    } 
    if (dup2(in, 0) < 0) { 
     err_syserr("dup2() failed on stdin for %s: ", cmd[i].argv[0]); 
    } 
    fprintf(stderr, "%d: executing %s\n", (int) getpid(), cmd[i].argv[0]); 
    execvp(cmd[i].argv[0], cmd[i].argv); 
    err_syserr("failed to execute %s: ", cmd[i].argv[0]); 
} 

Wohin soll die Signalverarbeitung gehen? Wo ist ein minimales Arbeitsbeispiel von dem, was ich versuche zu tun? Ich sehe kein Beispiel, das dies tut, und ich denke, die Dokumentation ist schrecklich, nur Schnipsel und kein vollständiges Beispiel.

Meine Hilfsfunktion ist

/* Helper function that spawns processes */ 
int spawn_proc(int in, int out, struct command *cmd) { 
    pid_t pid; 
    pid = fork(); 
    if (pid == 0) { 
     if (in != 0) { 
      if (dup2(in, 0) < 0) 
       err_syserr("dup2() failed on stdin for %s: ", cmd->argv[0]); 
      close(in); 
     } 
     if (out != 1) { 
      if (dup2(out, 1) < 0) 
       err_syserr("dup2() failed on stdout for %s: ", cmd->argv[0]); 
      close(out); 
     } 
     printf("** we are executing parent ***"); 
     fprintf(stderr, "%d: executing %s\n", (int) getpid(), cmd->argv[0]); 
     execvp(cmd->argv[0], cmd->argv); 
     err_syserr("failed to execute %s: ", cmd->argv[0]); 
    } 
    else if (pid < 0) { 
     err_syserr("fork failed: "); 
    } else { 
     /* */ 
     printf("** we are the parent ***"); 
    } 
    return pid; 
} 

Meine main() nun wie folgt aussieht:

int main(int argc, char *argv[]) { 

    sourceCount = 0; 
    const char *commandFile; 

    commandFile = NULL; 
    char *pathValue; 
/* struct sigaction sa, osa; 
    struct sigaction sa2;*/ 
    int errflag; 
    int cOption; 
    struct sigaction action; 
    /* use getopt_long() */ 
    char *argv1[] = {"version", "par2", 0}; 
/* char *argv2[] = {"help", "-m", "arg1", 0};*/ 

    /* use sigaction */ 

    sigemptyset(&action.sa_mask); 
    action.sa_handler = handle_sigchld; 
    action.sa_flags = 0; 

    sigaction(SIGPIPE, &action, NULL); //Not work with kill -13 process_id 
    //works well 
    sigaction(SIGINT, &action, NULL); //work with kill -2 process_id 

    errflag = 0; 

    /* use getopt_long() */ 
    while ((cOption = getopt(2, argv1, "m:t:n:fs?")) != -1) { 

     switch (cOption) { 
      case 'a': 
       printf("apples\n"); 
       break; 
      case 'b': 
       printf("bananas\n"); 
       break; 
      case 't': 
       printf("tree = %s\n", optarg); 
       break; 
      case '?': 
       ++errflag; 
       break; 
     } 
    } 
/* 
    while ((cOption = getopt (3, argv2, "m:t:n:fs?")) != -1) { 
     switch (cOption) { 
      case 'm': 
       printf("\n Help msg : %s \n", optarg); 
       exit(0); 
      case '?': 
       printf("\n -? Arg : %s \n", optarg); 
       break; 
      case 'n': 
       printf("\n -n Arg : %s \n", optarg); 
       break; 
     } 
    } 
*/ 


    /* get the PATH environment to find if less is installed */ 
    pathValue = getenv("PATH"); 
    if (!pathValue || getenv("PATH") == NULL) { 
     printf("'%s' is not set.\n", "PATH"); 

     /* Default our path if it is not set. */ 

     putenv("PATH=/bin:/usr/bin:/sbin:/usr/sbin:/etc"); 
    } 
    else { 
     printf("'%s' is set to %s.\n", "PATH", pathValue); 
    } 
    exec_program(commandFile); 
    return (0); 
} 

Wenn ich meine Shell laufen in gdb ich einen normalen Ausgang.

(gdb) run 
Starting program: /home/dac/ClionProjects/shell2/openshell/shell 
'PATH' is set to /home/dac/proj/google-cloud-sdk/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin. 
dac:/home/dac/ClionProjects/shell2/openshell $ checkenv 
7429: executing printenv 
7430: executing grep 
7417: executing less 
7431: executing sort 
process 7417 is executing new program: /bin/less 
[Inferior 1 (process 7417) exited normally] 
(gdb) 
+1

Was ist Ihr Programmsignal zu beenden verursacht? SIGPIPE? Deine reale Shell sollte es dir sagen. –

Antwort

1

Im Eltern sollten Sie kein Signal empfangen müssen, rufen Sie warten nur(), bis er zurückkehrt, dass Ihr Kind gestorben ist und jetzt geerntet wird. Ihre Shell ist jetzt bereit, eine neue Aufgabe auszuführen.

Ihr Code in der ursprünglichen Anfrage, wenn sehr unvollständig ist, kommt also hier ein Beispiel:

#include <stdio.h> 
#include <unistd.h> 
#include <wait.h> 

void foobar() 
{ 
    int pipe_fd[2]; 
    pid_t pid1, pid2; 

    pipe(pipe_fd); 

    pid1=fork(); 
    if (pid1 == 0) 
    { 
    /* child1 - let us pretend that we wanted to replace stdin and this child */ 
    close (0); 
    dup(pipe_fd[0]); 
    close(pipe_fd[0]); 
    close(pipe_fd[1]); 
    execlp("wc", "wc", NULL); 
    perror ("execlp(wc)"); 
    _exit(0); 
    } 

    pid2=fork(); 
    if (pid2 == 0) 
    { 
    /* child - let us pretent that we wanted to replace stdout */ 
    close (1); 
    dup(pipe_fd[1]); 
    close(pipe_fd[0]); 
    close(pipe_fd[1]); 
    execlp("ls", "ls", "-l", NULL); 
    perror ("execlp(ls)"); 
    _exit(0); 
    } 

    close(pipe_fd[0]); 
    close(pipe_fd[1]); 

    /* wait until children are finished */ 
    while ((pid1 >= 0) || (pid2 >= 0)) 
    { 
    pid_t pid; 
    int status; 
    pid = wait(&status); 
    if (pid < 0) 
    { 
     continue; 
    } 
    if (pid == pid1) 
    { 
     pid1 = -1; 
    } 
    if (pid == pid2) 
    { 
     pid2 = -1; 
    } 
    } 
} 

int main(int argc, char *argv[]) 
{ 
     foobar(); 
     return 0; 
} 
+0

Danke. Ich musste einfach "fork" und warte jetzt, dass ich weiß, was ich mache. –

1

Sie wollen SIGCHLD, fangen und das Kind Status mit einem der wait() Funktionen ernten.

Die folgenden Informationen stammen von einer online tutorial.

void handle_sigchld(int sig) { 
    int saved_errno = errno; 
    while (waitpid((pid_t)(-1), 0, WNOHANG) > 0) {} 
    errno = saved_errno; 
} 

struct sigaction sa; 
sa.sa_handler = &handle_sigchld; 
sigemptyset(&sa.sa_mask); 
sa.sa_flags = SA_RESTART | SA_NOCLDSTOP; 
if (sigaction(SIGCHLD, &sa, 0) == -1) { 
    perror(0); 
    exit(1); 
} 

Auch werden Sie wahrscheinlich wollen SIGPIPE ignorieren.

struct sigaction sa; 
sa.sa_handler = SIG_IGN; 
sigemptyset(&sa.sa_mask); 
sa.sa_flags = 0; 
if (sigaction(SIGPIPE, &sa, 0) == -1) { 
    perror(0); 
    exit(1); 
} 
+0

Danke für die Antwort. Bitte können Sie ein wenig ausarbeiten? Ich habe das vorher noch nicht gemacht und bin kein C-Experte. –

+1

@ Programmer400 Es gibt einen Link zum Tutorial. Ich glaube nicht, dass es einen Sinn hat, hier mehr davon zu kopieren ... –

+0

@EugeneSh. Ich verstehe nicht, wo ich im Code "wait"() warten sollte, also vergebe ich auf Details. –