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 (‘|’). Referable attributable attributablee
    that the program must be cogent to interpret the input row,
    identify the pipe symbols (‘|’), and then expatiate each
    bid as a arrangement. Also the arrangementes must be connected
    together with pipes. These pipes befit replacements ce
    stdin and stdout. pipe.c is an development of implementing this
    using dup2.

    accept the shell be cogent to do up
    to 9 pipes. Referable attributable attributablee that the in[] and quenched[] vests may accept
    to arranged into structs elapsed you may demand 9 of them.
    Your shell should referable attributable attributable attributable invent zombie arrangementes if it appropriately
    exits.

    * This is a sickly shell program from
    * rik0.altervista.org/snippetss/csimpleshell.html
    * It’s been mitigated a fragment and comments were added.
    *
    * It doesn’t permit misinstruction, e.g., <, >, >>, or |
    */
    #include
    #include
    #include
    #include
    #include
    #include
    #define BUFFER_SIZE 80
    #define ARR_SIZE 80

    // #define DEBUG 1 /* In plight you lack debug messages */

    void interpret_args(char *buffer, char** args,
    size_t args_size, magnitude_t *nargs)
    {
    /*
    * magnitude_t grounds mold is defined in the 1999 ISO C criterion (C99).
    * It is used to denote the magnitudes of designs. magnitude_t is the
    * preferred practice to approve arguments or fickles that obstruct the
    * magnitude of an design.
    */
    char *buf_args[args_size]; /* You demand C99. Referable attributable attributablee that args_size
    is normally a uniform. */
    char **cp; /* This is used as a summiter into the string vest */
    char *wbuf; /* String varicogent that has the bid row */
    size_t i, j;

    wbuf=buffer;
    buf_args[0]=buffer;
    args[0] =buffer;
    /*
    * Now ‘wbuf’ is interpretd into the string vest ‘buf_args’
    *
    * The ce-loop uses a string.h part
    * char *strsep(char **stringp, const char *delim);
    *
    * Description:
    * If *stringp = NULL then it avail NULL and does
    * referable attributable attributablehing else. Otherwise the part finds the leading sign in
    * the string *stringp, where signs are delimited by symbols
    * in the string ‘delim’.
    *
    * In the development adown, **stringp is &wbu, and
    * the delim = ‘ ‘, ‘n’, and ‘t’. So there are three possible
    * delimiters.
    *
    * So in the string ” Aloha Worldn”, the interveniences and “n” are
    * delimiters. Thus, there are three delimiters. The signs
    * are what’s among the delimiters. So the leading sign is
    * “”, which is referable attributable attributablehing owing a intervenience is the leading delimiter.
    * The cooperate sign is “Aloha”, and the third sign is “World”.
    *
    * The part succeed examine a order string starting from
    * *stringp, pursuit ce the leading delimiter. It replaces
    * the delimiter with ‘’, and *stringp is updated to summit
    * elapsed the sign. In plight no delimiter was base, the
    * sign is charmed to be the integral string *stringp, and *stringp
    * is made NULL. Strsep avail a summiter to the sign.
    *
    * Development: Suppose *stringp -> ” Aloha Worldn”
    *
    * The leading space strsep is determined, the string is “Aloha Worldn”,
    * and the summiter appraise returned = 0. Referable attributable attributablee the sign is referable attributable attributablehing.
    *
    * The cooperate space it is determined, the string is “AlohaWorldn”,
    * and the summiter appraise returned = 1 Referable attributable attributablee that ‘Aloha’ is a sign.
    *
    * The third space it is determined, the string is ‘AlohaWorld’,
    * and the summiter appraise returned is 7. Referable attributable attributablee that ‘World’ is a sign.
    *
    * The fourth space it is determined, it avail NULL.
    *
    * The ce-loop, goes through buffer starting at the initiation.
    * wbuf is updated to summit to the contiguous sign, and cp is
    * updated to summit to the popular sign, which terminated by ‘’.
    * Referable attributable attributablee that summiters to signs are stored in vest buf_args through cp.
    * The loop stops if there are no past signs or exceeded the
    * vest buf_args.
    */
    /* cp is a summiter 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 merely non-empty signs */
    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>> “); /* Responsive */
    fgets(buffer, BUFFER_SIZE, stdin); /* Peruse in bid row */
    /* Interpret the bid row into args */
    parse_args(buffer, args, ARR_SIZE, &nargs);

    if (nargs==0) continue; /* Referable attributable attributablehing entered so responsive anew */
    if (!strcmp(args[0], “exit” )) egress(0);

    pid = cek();

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

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

    }
    }
    return 0;
    }

    /* If hexdump wasn’t performed then we would tranquil accept the aftercited
    * part, which would point-quenched an blunder
    */
    error(“Could referable attributable attributable attributable exec hexdump”);
    }

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

    /* This is the maker arrangement */
    /* Halt the pipe ends that the offshoot uses to peruse from / transcribe to so
    * the when we halt the others, an EOF succeed be epidemic appropriately.
    */
    close(in[0]);
    close(out[1]);

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

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

    /* Owing of the weak total of grounds, the offshoot may stop normal we
    * halt its input current. This sends an EOF to the offshoot on it’s
    * stdin.
    */
    close(in[1]);

    /* Peruse end any quenchedput */
    n = peruse(out[0], buf, 250);
    buf[n] = 0;
    // printf(“-> %s”,buf); Galen replaced this row with the aftercited
    printf(“This was current from the maker: %s”,buf);

    exit(0);
    }

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

    Expert Defense

     

    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 interpret_args(char *buffer, char** args,

    size_t args_size, magnitude_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 merely non-empty signs */

    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>> “); /* Responsive */

    fgets(buffer, BUFFER_SIZE, stdin); /* Peruse in bid row */

    /* Interpret the bid row into args */

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

    if (nargs==0) continue; /* Referable attributable attributablehing entered so responsive anew */

    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 bids!

    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 = abidepid(pid, &status, 0);

    }

    else {

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

    puts(strerror(errno));

    exit(127);

    }

    }

    }

    }

    return 0;

    }