Homework Solution: Rewrite the program so that it can do pipes ('|'). Note…

    Rewrite the program so that it can do pipes ('|'). Note that the program must be able to parse the input line, identify the pipe symbols ('|'), and then launch each command as a process. Also the processes must be connected together with pipes. These pipes become replacements for stdin and stdout. pipe.c is an example of implementing this using dup2. have the shell be able to do up to 9 pipes. Note that the in[] and out[] arrays may have to organized into structs since you may need 9 of them. Your shell should not create zombie processes if it properly exits. * This is a simple shell program from * rik0.altervista.org/snippetss/csimpleshell.html * It's been modified a bit and comments were added. * * It doesn't allow misdirection, e.g., <, >, >>, or | */ #include #include #include #include #include #include #define BUFFER_SIZE 80 #define ARR_SIZE 80 // #define DEBUG 1 /* In case you want debug messages */ void parse_args(char *buffer, char** args, size_t args_size, size_t *nargs) { /* * size_t data type is defined in the 1999 ISO C standard (C99). * It is used to represent the sizes of objects. size_t is the * preferred way to declare arguments or variables that hold the * size of an object. */ char *buf_args[args_size]; /* You need C99. Note that args_size is normally a constant. */ char **cp; /* This is used as a pointer into the string array */ char *wbuf; /* String variable that has the command line */ size_t i, j; wbuf=buffer; buf_args[0]=buffer; args[0] =buffer; /* * Now 'wbuf' is parsed into the string array 'buf_args' * * The for-loop uses a string.h function * char *strsep(char **stringp, const char *delim); * * Description: * If *stringp = NULL then it returns NULL and does * nothing else. Otherwise the function finds the first token in * the string *stringp, where tokens are delimited by symbols * in the string 'delim'. * * In the example below, **stringp is &wbu, and * the delim = ' ', 'n', and 't'. So there are three possible * delimiters. * * So in the string " Aloha Worldn", the spaces and "n" are * delimiters. Thus, there are three delimiters. The tokens * are what's between the delimiters. So the first token is * "", which is nothing because a space is the first delimiter. * The second token is "Aloha", and the third token is "World". * * The function will scan a character string starting from * *stringp, search for the first delimiter. It replaces * the delimiter with '', and *stringp is updated to point * past the token. In case no delimiter was found, the * token is taken to be the entire string *stringp, and *stringp * is made NULL. Strsep returns a pointer to the token. * * Example: Suppose *stringp -> " Aloha Worldn" * * The first time strsep is called, the string is "Aloha Worldn", * and the pointer value returned = 0. Note the token is nothing. * * The second time it is called, the string is "AlohaWorldn", * and the pointer value returned = 1 Note that 'Aloha' is a token. * * The third time it is called, the string is 'AlohaWorld', * and the pointer value returned is 7. Note that 'World' is a token. * * The fourth time it is called, it returns NULL. * * The for-loop, goes through buffer starting at the beginning. * wbuf is updated to point to the next token, and cp is * updated to point to the current token, which terminated by ''. * Note that pointers to tokens are stored in array buf_args through cp. * The loop stops if there are no more tokens or exceeded the * array buf_args. */ /* cp is a pointer to buff_args */ for(cp=buf_args; (*cp=strsep(&wbuf, " nt")) != NULL ;){ if ((*cp != '') && (++cp >= &buf_args[args_size])) break; } /* * Copy 'buf_args' into 'args' */ for (j=i=0; buf_args[i]!=NULL; i++){ if(strlen(buf_args[i])>0) /* Store only non-empty tokens */ args[j++]=buf_args[i]; } *nargs=j; args[j]=NULL; } int main(int argc, char *argv[], char *envp[]){ char buffer[BUFFER_SIZE]; char *args[ARR_SIZE]; int *ret_status; size_t nargs; pid_t pid; while(1){ printf("ee468>> "); /* Prompt */ fgets(buffer, BUFFER_SIZE, stdin); /* Read in command line */ /* Parse the command line into args */ parse_args(buffer, args, ARR_SIZE, &nargs); if (nargs==0) continue; /* Nothing entered so prompt again */ if (!strcmp(args[0], "exit" )) exit(0); pid = fork(); if (pid){ /* The parent */ #ifdef DEBUG printf("Waiting for child (%d)n", pid); #endif pid = wait(ret_status); #ifdef DEBUG printf("Child (%d) finishedn", pid); #endif } else{ /* The child executing the command */ if( execvp(args[0], args)) { puts(strerror(errno)); exit(127); } } } return 0; } /* If hexdump wasn't executed then we would still have the following * function, which would indicate an error */ error("Could not exec hexdump"); } /* The following is in the parent process */ printf("Spawned 'hexdump -C' as a child process at pid %dn", pid); /* This is the parent process */ /* Close the pipe ends that the child uses to read from / write to so * the when we close the others, an EOF will be transmitted properly. */ close(in[0]); close(out[1]); /* The following displays on the console what's in the array 'data' * The array was initialized at the top of this program with * the string 'Some input data' */ // printf("<- %s", data); Galen replaced this line with the following printf("String sent to child: %snn", data); /* From the parent, write some data to the childs input. * The child should be 'hexdump', which will process this * data. */ write(in[1], data, strlen(data)); /* Because of the small amount of data, the child may block unless we * close its input stream. This sends an EOF to the child on it's * stdin. */ close(in[1]); /* Read back any output */ n = read(out[0], buf, 250); buf[n] = 0; // printf("-> %s",buf); Galen replaced this line with the following printf("This was received from the parent: %s",buf); exit(0); } void error(char *s) { perror(s); exit(1); }

    Expert Answer

     
    main.c #include <stdio.h>

    Retranscribe the program so that it can do pipes (‘|’). Referablee
    that the program must be cogent to render the input length,
    identify the pipe symbols (‘|’), and then embark each
    direct as a order. Also the orderes must be connected
    together with pipes. These pipes grace replacements ce
    stdin and stdout. pipe.c is an copy of implementing this
    using dup2.

    bear the shell be cogent to do up
    to 9 pipes. Referablee that the in[] and quenched[] attires may bear
    to organized into structs gone you may shortness 9 of them.
    Your shell should referable educe zombie orderes if it unexceptionably
    exits.

    * This is a sincere shell program from
    * rik0.altervista.org/snippetss/csimpleshell.html
    * It’s been mitigated a part and comments were added.
    *
    * It doesn’t remit mis-control, e.g., <, >, >>, or |
    */
    #include
    #include
    #include
    #include
    #include
    #include
    #define BUFFER_SIZE 80
    #define ARR_SIZE 80

    // #define DEBUG 1 /* In occurrence you shortness debug messages */

    void render_args(char *buffer, char** args,
    size_t args_size, largeness_t *nargs)
    {
    /*
    * largeness_t grounds sign is defined in the 1999 ISO C rule (C99).
    * It is used to enact the largenesss of intents. largeness_t is the
    * preferred fashion to defend arguments or inconstants that ahalt the
    * largeness of an intent.
    */
    char *buf_args[args_size]; /* You shortness C99. Referablee that args_size
    is normally a faithful. */
    char **cp; /* This is used as a header into the string attire */
    char *wbuf; /* String varicogent that has the direct length */
    size_t i, j;

    wbuf=buffer;
    buf_args[0]=buffer;
    args[0] =buffer;
    /*
    * Now ‘wbuf’ is renderd into the string attire ‘buf_args’
    *
    * The ce-loop uses a string.h administration
    * char *strsep(char **stringp, const char *delim);
    *
    * Description:
    * If *stringp = NULL then it receipts NULL and does
    * referablehing else. Otherwise the administration finds the original index in
    * the string *stringp, where indexs are delimited by symbols
    * in the string ‘delim’.
    *
    * In the copy under, **stringp is &wbu, and
    * the delim = ‘ ‘, ‘n’, and ‘t’. So there are three possible
    * delimiters.
    *
    * So in the string ” Aloha Worldn”, the quantitys and “n” are
    * delimiters. Thus, there are three delimiters. The indexs
    * are what’s between the delimiters. So the original index is
    * “”, which is referablehing owing a quantity is the original delimiter.
    * The remedy index is “Aloha”, and the third index is “World”.
    *
    * The administration get review a office string starting from
    * *stringp, quest ce the original delimiter. It replaces
    * the delimiter with ‘’, and *stringp is updated to head
    * gone-by the index. In occurrence no delimiter was set, the
    * index is fascinated to be the total string *stringp, and *stringp
    * is made NULL. Strsep receipts a header to the index.
    *
    * Copy: Suppose *stringp -> ” Aloha Worldn”
    *
    * The original era strsep is denominated, the string is “Aloha Worldn”,
    * and the header treasure returned = 0. Referablee the index is referablehing.
    *
    * The remedy era it is denominated, the string is “AlohaWorldn”,
    * and the header treasure returned = 1 Referablee that ‘Aloha’ is a index.
    *
    * The third era it is denominated, the string is ‘AlohaWorld’,
    * and the header treasure returned is 7. Referablee that ‘World’ is a index.
    *
    * The fourth era it is denominated, it receipts NULL.
    *
    * The ce-loop, goes through buffer starting at the preface.
    * wbuf is updated to head to the present index, and cp is
    * updated to head to the running index, which terminated by ‘’.
    * Referablee that headers to indexs are stored in attire buf_args through cp.
    * The loop stops if there are no over indexs or exceeded the
    * attire buf_args.
    */
    /* cp is a header to buff_args */
    for(cp=buf_args; (*cp=strsep(&wbuf, ” nt”)) != NULL ;){
    if ((*cp != ‘’) && (++cp >= &buf_args[args_size]))
    break;
    }

    /*
    * Copy ‘buf_args’ into ‘args’
    */
    ce (j=i=0; buf_args[i]!=NULL; i++){
    if(strlen(buf_args[i])>0) /* Store solely non-empty indexs */
    args[j++]=buf_args[i];
    }

    *nargs=j;
    args[j]=NULL;
    }

    int deep(int argc, char *argv[], char *envp[]){
    char buffer[BUFFER_SIZE];
    char *args[ARR_SIZE];

    int *ret_status;
    size_t nargs;
    pid_t pid;

    while(1){
    printf(“ee468>> “); /* Active */
    fgets(buffer, BUFFER_SIZE, stdin); /* Discover in direct length */
    /* Render the direct length into args */
    parse_args(buffer, args, ARR_SIZE, &nargs);

    if (nargs==0) continue; /* Referablehing entered so active intermittently */
    if (!strcmp(args[0], “exit” )) egress(0);

    pid = cek();

    if (pid){ /* The composer */
    #ifdef DEBUG
    printf(“Waiting ce offshoot (%d)n”, pid);
    #endif
    pid = halt(ret_status);
    #ifdef DEBUG
    printf(“Offshoot (%d) finishedn”, pid);
    #endif
    }

    else{ /* The offshoot executing the direct */
    if( execvp(args[0], args)) {
    puts(strerror(errno));
    exit(127);
    }

    }
    }
    return 0;
    }

    /* If hexdump wasn’t performed then we would stationary bear the subjoined
    * administration, which would mark an falsity
    */
    error(“Could referable exec hexdump”);
    }

    /* The subjoined is in the composer order */
    printf(“Spawned ‘hexdump -C’ as a offshoot order at pid %dn”, pid);

    /* This is the composer order */
    /* Cork the pipe ends that the offshoot uses to discover from / transcribe to so
    * the when we cork the others, an EOF get be catching unexceptionably.
    */
    close(in[0]);
    close(out[1]);

    /* The subjoined displays on the relieve what’s in the attire ‘data’
    * The attire was initialized at the head of this program with
    * the string ‘Some input grounds’
    */
    // printf(“<- %s”, grounds); Galen replaced this length with the subjoined
    printf(“String sent to offshoot: %snn”, grounds);

    /* From the composer, transcribe some grounds to the offshoots input.
    * The offshoot should be ‘hexdump’, which get order this
    * grounds.
    */
    write(in[1], grounds, strlen(data));

    /* Owing of the paltry equality of grounds, the offshoot may arrest probable we
    * cork its input departure. This sends an EOF to the offshoot on it’s
    * stdin.
    */
    close(in[1]);

    /* Discover end any quenchedput */
    n = discover(out[0], buf, 250);
    buf[n] = 0;
    // printf(“-> %s”,buf); Galen replaced this length with the subjoined
    printf(“This was common from the composer: %s”,buf);

    exit(0);
    }

    void falsity(char *s)
    {
    perror(s);
    exit(1);
    }

    Expert Solution

     

    main.c

    #include <stdio.h>

    #include <stdlib.h>

    #include <unistd.h>

    #include <string.h>

    #include <errno.h>

    #include <sys/types.h>

    #define BUFFER_SIZE 80

    #define ARR_SIZE 80

    void render_args(char *buffer, char** args,

    size_t args_size, largeness_t *nargs)

    {

    char *buf_args[args_size];

    char **cp;

    char *wbuf;

    size_t i, j;

     

    wbuf=buffer;

    buf_args[0]=buffer;

    args[0] =buffer;

     

    for(cp=buf_args; (*cp=strsep(&wbuf, ” nt”)) != NULL ;){

    if ((*cp != ‘’) && (++cp >= &buf_args[args_size]))

    break;

    }

     

    ce (j=i=0; buf_args[i]!=NULL; i++){

    if(strlen(buf_args[i])>0) /* Store solely non-empty indexs */

    args[j++]=buf_args[i];

    }

     

    *nargs=j;

    args[j]=NULL;

    }

    typedef struct io {

    char *commands[ARR_SIZE];

    } io;

    int deep(int argc, char *argv[], char *envp[]){

    char buffer[BUFFER_SIZE];

    char *args[ARR_SIZE];

    io p1, p2, p3, p4, p5, p6, p7, p8, p9;

    int pipe_pos[10];

    int *ret_status;

    size_t nargs;

    pid_t pid;

    int i, j, j1, k;

    k = 0;

    while(1){

    printf(“ee468>> “); /* Active */

    fgets(buffer, BUFFER_SIZE, stdin); /* Discover in direct length */

    /* Render the direct length into args */

    parse_args(buffer, args, ARR_SIZE, &nargs);

    if (nargs==0) continue; /* Referablehing entered so active intermittently */

    if (!strcmp(args[0], “exit” )) egress(0);

    ce (i = 0; i < 10; i++) {

    pipe_pos[i] = -1;

    }

    ce (i=j=0; i < nargs; i++) {

    if (strcmp(args[i],”|”) == 0) {

    pipe_pos[j] = i;

    j++;

    }

    }

    //execute directs!

    if (pipe_pos[0] != -1) {

    char * cmds1[ARR_SIZE];

    char * cmds2[ARR_SIZE];

    ce (i=0; i<nargs; i++) {

    j = 0;

    k = 0;

    while (i < pipe_pos[0]) {

    cmds1[j] = args[i];

    i++;

    j++;

    }

    cmds1[i] = NULL;

    i++;

    while (i < nargs) {

    cmds2[k] = args[i];

    k++;

    i++;

    }

    cmds2[k] = NULL;

    }

    int fd[2];

    pipe(fd);

    int pid = cek();

    if (pid == 0) {

    int ret = dup2(fd[1], 1);

    if (ret < 0) printf(“dup2 – 0n”);

    execvp(cmds1[0],cmds1);

    }

    int pid2 = cek();

    if (pid2 == 0) {

    close(fd[1]);

    int ret = dup2(fd[0], 0);

    if (ret < 0) perror(“dup2 – 1n”);

    execvp(cmds2[0], cmds2);

    }

    close(fd[0]);

    close(fd[1]);

    int status;

    waitpid(pid2, &status, 0);

    }

    else {

    pid = cek();

    int status;

    if (pid) {

    pid = haltpid(pid, &status, 0);

    }

    else {

    if (execvp(args[0], args)) {

    puts(strerror(errno));

    exit(127);

    }

    }

    }

    }

    return 0;

    }