int execute_complex_command(command *c) { if(c->scmd != NULL){ if(c->scmd->builtin == 0){ execute_nonbuiltin(c->scmd); } } if (!strcmp(c->oper, "|")) { int pfd[2]; if(pipe(pfd) == -1){ perror("pipe"); exit(EXIT_FAILURE); } pid_t pid1, pid2; int status; pid1 = fork(); if(pid1 < 0){ perror("fork"); exit(EXIT_FAILURE); } else if(pid1 == 0){ close(pfd[0]); close(fileno(stdout)); dup2(pfd[1], fileno(stdout)); execute_complex_command(c->cmd1); exit(0); } else{ pid2 = fork(); if(pid2 < 0){ perror("fork"); exit(EXIT_FAILURE); } else if(pid2 == 0) { close(pfd[1]); close(fileno(stdin)); dup2(pfd[0], fileno(stdin)); execute_complex_command(c->cmd2); exit(0); } else{ close(pfd[0]); close(pfd[1]); waitpid(pid1, &status, 0); waitpid(pid2, &status, 0); } } } return 0; }
/** * Executes a complex command. A complex command is two commands chained * together with a pipe operator. */ int execute_complex_command(command *c){ if (c->scmd){ execute_simple_command(c->scmd); }else{ int pfd[2]; if(pipe(pfd) == -1) { perror("Pipe failed"); exit(1); } if(fork() == 0) //first fork { close(1); //closing stdout dup(pfd[1]); //replacing stdout with pipe write close(pfd[0]); //closing pipe read close(pfd[1]); execute_complex_command(c->cmd1); exit(1); } if(fork() == 0) //creating 2nd child { close(0); //closing stdin dup(pfd[0]); //replacing stdin with pipe read close(pfd[1]); //closing pipe write close(pfd[0]); execute_complex_command(c->cmd2); exit(1); } close(pfd[0]); close(pfd[1]); wait(0); wait(0); return 0; } return 0; }
int main(int argc, char** argv) { char cwd[MAX_DIRNAME]; /* Current working directory */ char command_line[MAX_COMMAND]; /* The command */ char *tokens[MAX_TOKEN]; /* Command tokens (program name, * parameters, pipe, etc.) */ while (1) { /* Display prompt */ getcwd(cwd, MAX_DIRNAME-1); printf("%s> ", cwd); /* Read the command line */ fgets(command_line, MAX_COMMAND, stdin); /* Strip the new line character */ if (command_line[strlen(command_line) - 1] == '\n') { command_line[strlen(command_line) - 1] = '\0'; } /* Parse the command into tokens */ parse_line(command_line, tokens); /* Check for empty command */ if (!(*tokens)) { continue; } /* Construct chain of commands, if multiple commands */ command *cmd = construct_command(tokens); // print_command(cmd, 0); int exitcode = 0; if (cmd->scmd) { exitcode = execute_simple_command(cmd->scmd); if (exitcode == -1) { release_command(cmd); break; } } else { exitcode = execute_complex_command(cmd); if (exitcode == -1) { release_command(cmd); break; } } release_command(cmd); } return 0; }
int main(int argc, char** argv) { char cwd[MAX_DIRNAME]; /* Current working directory */ char command_line[MAX_COMMAND]; /* The command */ char *tokens[MAX_TOKEN]; /* Command tokens (program name, parameters, pipe, etc.) */ while (1) { /* Display prompt */ getcwd(cwd, MAX_DIRNAME-1); printf("%s> ", cwd); /* Read the command line */ gets(command_line); /* Parse the command into tokens */ parse_line(command_line, tokens); /* Empty command */ if (!(*tokens)) continue; /* Exit */ if (strcmp(tokens[0], "exit") == 0) exit(0); /* Construct chain of commands, if multiple commands */ command *cmd = construct_command(tokens); int exitcode = 0; if (cmd->scmd) { exitcode = execute_simple_command(cmd->scmd); if (exitcode == -1) break; } else { exitcode = execute_complex_command(cmd); if (exitcode == -1) break; } release_command(cmd); } return 0; }
/** * Executes a complex command. A complex command is two commands chained * together with a pipe operator. */ int execute_complex_command(command *c) { /** * Check if this is a simple command, using the scmd field. * Execute nonbuiltin commands only. If it's exit or cd, you should not * execute these in a piped context, so simply ignore builtin commands. */ if(c->scmd) { /* The exit status of the child process will be the return value * of execute_nonbuiltin (if there is an error), or the exit * status of the command exec'd. */ exit(execute_nonbuiltin(c->scmd)); // printf("%s\n", c->scmd->tokens[0]); return 0; } /** * Shell currently only supports | operator. */ if (!strcmp(c->oper, "|")) { /** * Create a pipe "pfd" that generates a pair of file * descriptors, to be used for communication between the * parent and the child. Make sure to check any errors in * creating the pipe. */ int pfd[2]; if(pipe(pfd) != 0) { perror("pipe"); return EXIT_FAILURE; } /** * Fork a new process. * In the child: * - close one end of the pipe pfd and close the stdout * file descriptor. * - connect the stdout to the other end of the pipe (the * one you didn't close). * - execute complex command cmd1 recursively. * In the parent: * - fork a new process to execute cmd2 recursively. * - In child 2: * - close one end of the pipe pfd (the other one than * the first child), and close the standard input file * descriptor. * - connect the stdin to the other end of the pipe (the * one you didn't close). * - execute complex command cmd2 recursively. * - In the parent: * - close both ends of the pipe. * - wait for both children to finish. */ int pid; if((pid = fork()) < 0) { perror("fork"); return EXIT_FAILURE; } else if (pid == 0) { //child close(pfd[0]); if(dup2(pfd[1], fileno(stdout)) < 0) { perror("dup2"); return -1; } /* The exit status of the child process will be the return value * of execute_nonbuiltin (if there is an error), or the exit * status of the command exec'd. */ exit(execute_complex_command(c->cmd1)); } else { //parent if((pid = fork()) < 0) { perror("fork"); return EXIT_FAILURE; } else if (pid == 0) { //child close(pfd[1]); if(dup2(pfd[0], fileno(stdin)) < 0) { perror("dup2"); return -1; } /* The exit status of the child process will be the return * value of execute_nonbuiltin (if there is an error), or * the exit status of the command exec'd. */ exit(execute_complex_command(c->cmd2)); } else { //parent close(pfd[0]); close(pfd[1]); int status; int exitcode = -1; int waitedPID; while ((waitedPID = wait(&status)) > 0) { if(WIFEXITED(status)) { /*exitcode should be the exit status of the *last command in the pipeline. */ if(waitedPID == pid) { exitcode = WEXITSTATUS(status); } } else { return EXIT_FAILURE; } } return exitcode; } } } return 0; }