Quick actions

cmd+k|ctrl+k

Navigation

Languages

Lab13

Snippet info

Language

C

Visibility

public

Author

dk90897

Created

2023-04-23T02:44:09.222806Z

Updated

2023-04-23T02:44:43.762404Z

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>

#define UNUSED(x) (void)(x)

void execute_pipeline(
    char *commands[], 
    char **commands_args[], 
    int number_commands )
{
    int pipe_fd[number_commands - 1][2];

    // Create pipes in a for loop
    for (int i = 0; i < number_commands - 1; i++)
    {
        if (pipe(pipe_fd[i]) == -1)
        {
            perror("pipe");
            exit(EXIT_FAILURE);
        }
    }

    // Parent forks children in a for loop
    for (int i = 0; i < number_commands; i++)
    {
        pid_t pid = fork();
        int status;
        
        if (pid == 0) // Child process
        {
            // If not the first command, redirect stdin to read end of previous pipe
            if (i > 0)
            {
                if (dup2(pipe_fd[i-1][0], STDIN_FILENO) == -1)
                {
                    perror("dup2");
                    exit(EXIT_FAILURE);
                }
            }
            
            // If not the last command, redirect stdout to write end of pipe
            if (i < number_commands - 1)
            {
                if (dup2(pipe_fd[i][1], STDOUT_FILENO) == -1)
                {
                    perror("dup2");
                    exit(EXIT_FAILURE);
                }
            }

            // Close all pipe ends
            for (int j = 0; j < number_commands - 1; j++)
            {
                close(pipe_fd[j][0]);
                close(pipe_fd[j][1]);
            }

            // Execute the command with arguments
            execvp(commands[i], commands_args[i]);
            perror("execvp");
            exit(EXIT_FAILURE);
        }
            else if (pid < 0) {
            // error in fork
            perror("fork");
            exit(EXIT_FAILURE);
            }
        else
        {
            // parent process
            if (i > 0) {
                close(pipe_fd[i-1][0]); // close read end of previous pipe
                close(pipe_fd[i-1][1]); // close write end of previous pipe
            }
            if (i == number_commands - 1)
            {
                // last command, wait for all children to finish
                for (int j = 0; j < number_commands; j++)
                {
                    wait(&status);
                }
            }
        }
    }
    
    // Close all pipe ends
    for (int i = 0; i < number_commands - 1; i++)
    {
        close(pipe_fd[i][0]);
        close(pipe_fd[i][1]);
    }
}

int main()
{
    // List of available commands on a command line
    // You can add to it if you like
    char *commands[] =
        {
            "ls",
            "grep",
            "sort",
            "uniq",
            "head",
            "tail",
            "wc",
            "ps",
            "who",
            "find",
            "xargs",
            "awk",
            "cut",
            NULL};

    // Select commands from commands[]
    char *pipeline_commands[] = {commands[0], commands[1]};

    // Set arguments
    char *cmd1_args[] = {commands[0], NULL};
    char *cmd2_args[] = {commands[1], "c", NULL};

    // Pack arguments into an array
    char **pipeline_args[] = {cmd1_args, cmd2_args};

    int number_commands = sizeof(pipeline_commands) / sizeof(pipeline_commands[0]);

    printf("Executing the following pipeline:\n");

    for (int i = 0; i < number_commands; i++)
    {
        printf("%s", pipeline_commands[i]);
        for (int j = 1; pipeline_args[i][j]!= NULL; j++)
        {
            printf(" %s", pipeline_args[i][j]);
        }
        if (i != number_commands - 1)
        {
            printf(" | ");
        }
    }
    printf("\n");

    execute_pipeline( pipeline_commands, pipeline_args, number_commands );

    return 0;
}

INFO