void do_pipe(char *cmds[MAXCMDS][MAXARGS], int nbcmd, int bg) { int **fds; int i, j; int pgid, job; char cmdsNames[MAXLINE] = ""; if(verbose) printf("do_pipe: entering\n"); if((fds = malloc((nbcmd-1) * sizeof(int*))) == NULL){ if(verbose) printf("do_pipe: malloc of rows failed\n"); return; } for(i=0 ; i<nbcmd-1 ; i++){ if ((fds[i] = malloc(2 * sizeof(int))) == NULL){ if(verbose) printf("do_pipe: malloc of columns failed\n"); return; } } for(i=0 ; i<nbcmd-1 ; i++) pipe(fds[i]); if(verbose) printf("do_pipe: first case\n"); switch(pgid = fork()){ case -1: if(verbose) printf("do_pipe: fork failed\n"); return; case 0: setpgid(0, 0); if(dup2(fds[0][1], STDOUT_FILENO) == -1 && verbose) printf("do_pipe: dup2 failed\n"); for(i=0 ; i<nbcmd-1 ; i++){ close(fds[i][0]); close(fds[i][1]); } if(execvp(cmds[0][0], cmds[0]) != 0){ perror("execvp"); exit(EXIT_FAILURE); } } for(j=1 ; j<nbcmd-1 ; j++){ if(verbose){ printf("do_pipe: central case\n"); printf("do_pipe: pipe fds[%d]\n", j); } switch(fork()){ case -1: if(verbose) printf("do_pipe: fork failed\n"); return; case 0: setpgid(0, pgid); dup2(fds[j-1][0], STDIN_FILENO); dup2(fds[j][1], STDOUT_FILENO); for(i=0 ; i<nbcmd-1 ; i++){ close(fds[i][0]); close(fds[i][1]); } if(execvp(cmds[j][0], cmds[j]) != 0){ perror("execvp"); exit(EXIT_FAILURE); } } } if(verbose) printf("do_pipe: last case\n"); switch(fork()){ case -1: if(verbose) printf("do_pipe: fork failed\n"); return; case 0: setpgid(0, pgid); if(dup2(fds[nbcmd-2][0], STDIN_FILENO) == -1 && verbose) printf("do_pipe: dup2 failed\n"); for(i=0 ; i<nbcmd-1 ; i++){ close(fds[i][0]); close(fds[i][1]); } if(execvp(cmds[nbcmd-1][0], cmds[nbcmd-1]) != 0){ perror("execvp"); exit(EXIT_FAILURE); } } for(i=0 ; i<nbcmd-1 ; i++){ close(fds[i][0]); close(fds[i][1]); } for(i=0 ; i<nbcmd ; i++){ if(i!=0) strcat(cmdsNames, " | "); strcat(cmdsNames, cmds[i][0]); } if(bg) job = jobs_addjob(pgid, BG, cmdsNames); else job = jobs_addjob(pgid, FG, cmdsNames); if(!bg) waitfg(pgid); else printf("[%d] (%d) %s\n",job , pgid, cmdsNames); free(fds); if(verbose) printf("do_pipe: exiting\n"); return; }
void eval(char *cmdline) { char *token[MAXCMDS][MAXARGS]; /* token[i] is a command typed in the command line */ int nbcmd; /* number of commands typed in the command line */ int bg; /* should the job run in bg or fg? */ pid_t pid; /* process id */ sigset_t mask; /* signal mask */ char **argv; /* Parse command line */ bg = parseline(cmdline, token, &nbcmd); if (nbcmd > 1) /* a command pipeline has been typed in */ do_pipe(token, nbcmd, bg); else { /* no pipeline, only one command */ argv = token[0]; if (!builtin_cmd(argv)) { /* * This is a little tricky. Block SIGCHLD, SIGINT, and SIGTSTP * signals until we can add the job to the job list. This * eliminates some nasty races between adding a job to the job * list and the arrival of SIGCHLD, SIGINT, and SIGTSTP signals. */ if (sigemptyset(&mask) < 0) unix_error("sigemptyset error"); if (sigaddset(&mask, SIGCHLD)) unix_error("sigaddset error"); if (sigaddset(&mask, SIGINT)) unix_error("sigaddset error"); if (sigaddset(&mask, SIGTSTP)) unix_error("sigaddset error"); if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) unix_error("sigprocmask error"); /* Create a child process */ if ((pid = fork()) < 0) unix_error("fork error"); /* * Child process */ if (pid == 0) { /* Child unblocks signals */ sigprocmask(SIG_UNBLOCK, &mask, NULL); /* Each new job must get a new process group ID so that the kernel doesn't send ctrl-c and ctrl-z signals to all of the shell's jobs */ if (setpgid(0, 0) < 0) unix_error("setpgid error"); /* Now load and run the program in the new job */ if (execvp(argv[0], argv) < 0) { printf("%s: Command not found\n", argv[0]); exit(EXIT_FAILURE); } } /* * Parent process */ /* Parent adds the job, and then unblocks signals so that the signals handlers can run again */ jobs_addjob(pid, (bg == 1 ? BG : FG), cmdline); sigprocmask(SIG_UNBLOCK, &mask, NULL); if (!bg) waitfg(pid); else printf("[%d] (%d) %s\n", jobs_pid2jid(pid), (int) pid, cmdline); } } return; }
void do_pipe(char *cmds[MAXCMDS][MAXARGS], int nbcmd, int bg) { int fd[2][2], i; pid_t pid; if (verbose) printf("Entering pipe\n"); if (verbose) printf("Pipe creation\n"); if (pipe(fd[0]) == -1) { if (verbose) printf("Error in pipe creation\n"); } for (i = 0; i < nbcmd; i++) { if (i == 0) { switch(pid = fork()) { case -1 : if (verbose) unix_error("fork cmd 1 error"); case 0 : if (verbose) printf("First son process\n"); setpgid(0, 0); dup2(fd[0][1],STDOUT_FILENO); close(fd[0][0]); close(fd[0][1]); execvp(cmds[0][0],cmds[0]); printf("execvp error\n"); exit(EXIT_FAILURE); default : if (verbose) printf("Father process\n"); } } else if (i > 0 && i < nbcmd -1) { switch(pid = fork()) { case -1 : unix_error("fork cmd 2 error"); case 0 : if (verbose) printf("the %dth process\n",i); assert(pipe(fd[i%2]) != -1); setpgid(0, pid); dup2(fd[(i+1)%2][0], STDIN_FILENO); dup2(fd[i%2][1], STDOUT_FILENO); close(fd[0][0]); close(fd[0][1]); close(fd[1][1]); close(fd[1][0]); execvp(cmds[i][0],cmds[i]); printf("execvp 2 error\n"); exit(EXIT_FAILURE); default : close(fd[(i+1)%2][0]); close(fd[(i+1)%2][1]); } } else { switch(pid = fork()) { case -1 : unix_error("fork cmd 2 error"); case 0 : if (verbose) { printf("Last process\n"); } dup2(fd[(i+1)%2][0], STDIN_FILENO); close(fd[(i+1)%2][0]); close(fd[(i+1)%2][1]); execvp(cmds[i][0],cmds[i]); printf("execvp 2 error\n"); exit(EXIT_FAILURE); default: close(fd[(i+1)%2][0]); close(fd[(i+1)%2][1]); } } } jobs_addjob(pid, (bg == 1 ? BG : FG), cmds[0][0]); if (!bg) { if (verbose) printf("pipe waiting fg \n"); waitfg(pid); } return; }