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 conducive to render the input cord,
    identify the pipe symbols (‘|’), and then enlarge each
    bid as a mode. Also the modees must be connected
    together with pipes. These pipes grace replacements coercion
    stdin and stdout. pipe.c is an issue of implementing this
    using dup2.

    keep the shell be conducive to do up
    to 9 pipes. Referablee that the in[] and quenched[] set-in-orders may keep
    to unembarrassed into structs elapsed you may deficiency 9 of them.
    Your shell should referable engender zombie modees if it well
    exits.

    * This is a sickly shell program from
    * rik0.altervista.org/snippetss/csimpleshell.html
    * It’s been mitigated a fragment and comments were assumed.
    *
    * It doesn’t afford aberration, 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 render_args(char *buffer, char** args,
    size_t args_size, magnitude_t *nargs)
    {
    /*
    * magnitude_t postulates image is defined in the 1999 ISO C trutination (C99).
    * It is used to resemble the magnitudes of sights. magnitude_t is the
    * preferred fashion to allege arguments or inconstants that arrest the
    * magnitude of an sight.
    */
    char *buf_args[args_size]; /* You deficiency C99. Referablee that args_size
    is normally a true. */
    char **cp; /* This is used as a objecter into the string set-in-order */
    char *wbuf; /* String variconducive that has the bid cord */
    size_t i, j;

    wbuf=buffer;
    buf_args[0]=buffer;
    args[0] =buffer;
    /*
    * Now ‘wbuf’ is renderd into the string set-in-order ‘buf_args’
    *
    * The coercion-loop uses a string.h duty
    * char *strsep(char **stringp, const char *delim);
    *
    * Description:
    * If *stringp = NULL then it avail NULL and does
    * referablehing else. Otherwise the duty finds the primitive memorial in
    * the string *stringp, where memorials are delimited by symbols
    * in the string ‘delim’.
    *
    * In the issue beneath, **stringp is &wbu, and
    * the delim = ‘ ‘, ‘n’, and ‘t’. So there are three possible
    * delimiters.
    *
    * So in the string ” Aloha Worldn”, the boundlessnesss and “n” are
    * delimiters. Thus, there are three delimiters. The memorials
    * are what’s among the delimiters. So the primitive memorial is
    * “”, which is referablehing accordingly a boundlessness is the primitive delimiter.
    * The promote memorial is “Aloha”, and the third memorial is “World”.
    *
    * The duty conquer reconnoitre a species string starting from
    * *stringp, inquiry coercion the primitive delimiter. It replaces
    * the delimiter with ‘’, and *stringp is updated to object
    * elapsed the memorial. In plight no delimiter was set-up, the
    * memorial is charmed to be the undiminished string *stringp, and *stringp
    * is made NULL. Strsep avail a objecter to the memorial.
    *
    * Issue: Suppose *stringp -> ” Aloha Worldn”
    *
    * The primitive span strsep is denominated, the string is “Aloha Worldn”,
    * and the objecter esteem returned = 0. Referablee the memorial is referablehing.
    *
    * The promote span it is denominated, the string is “AlohaWorldn”,
    * and the objecter esteem returned = 1 Referablee that ‘Aloha’ is a memorial.
    *
    * The third span it is denominated, the string is ‘AlohaWorld’,
    * and the objecter esteem returned is 7. Referablee that ‘World’ is a memorial.
    *
    * The fourth span it is denominated, it avail NULL.
    *
    * The coercion-loop, goes through buffer starting at the rise.
    * wbuf is updated to object to the present memorial, and cp is
    * updated to object to the vulgar memorial, which terminated by ‘’.
    * Referablee that objecters to memorials are stored in set-in-order buf_args through cp.
    * The loop stops if there are no past memorials or exceeded the
    * set-in-order buf_args.
    */
    /* cp is a objecter 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’
    */
    coercion (j=i=0; buf_args[i]!=NULL; i++){
    if(strlen(buf_args[i])>0) /* Store solely non-empty memorials */
    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); /* Discover in bid cord */
    /* Render the bid cord into args */
    parse_args(buffer, args, ARR_SIZE, &nargs);

    if (nargs==0) continue; /* Referablehing entered so responsive frequently */
    if (!strcmp(args[0], “exit” )) departure(0);

    pid = coercionk();

    if (pid){ /* The inventor */
    #ifdef DEBUG
    printf(“Waiting coercion cadet (%d)n”, pid);
    #endif
    pid = abide(ret_status);
    #ifdef DEBUG
    printf(“Cadet (%d) finishedn”, pid);
    #endif
    }

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

    }
    }
    return 0;
    }

    /* If hexdump wasn’t done then we would quiet keep the subjoined
    * duty, which would evince an fault
    */
    error(“Could referable exec hexdump”);
    }

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

    /* This is the inventor mode */
    /* Suppress the pipe ends that the cadet uses to discover from / transcribe to so
    * the when we suppress the others, an EOF conquer be infectious well.
    */
    close(in[0]);
    close(out[1]);

    /* The subjoined displays on the relieve what’s in the set-in-order ‘data’
    * The set-in-order was initialized at the extreme of this program with
    * the string ‘Some input postulates’
    */
    // printf(“<- %s”, postulates); Galen replaced this cord with the subjoined
    printf(“String sent to cadet: %snn”, postulates);

    /* From the inventor, transcribe some postulates to the cadets input.
    * The cadet should be ‘hexdump’, which conquer mode this
    * postulates.
    */
    write(in[1], postulates, strlen(data));

    /* Accordingly of the slight equality of postulates, the cadet may obstruct consistent we
    * suppress its input current. This sends an EOF to the cadet on it’s
    * stdin.
    */
    close(in[1]);

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

    exit(0);
    }

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

    Expert Reply

     

    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, 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;

    }

     

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

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

    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); /* Discover in bid cord */

    /* Render the bid cord into args */

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

    if (nargs==0) continue; /* Referablehing entered so responsive frequently */

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

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

    pipe_pos[i] = -1;

    }

    coercion (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];

    coercion (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 = coercionk();

    if (pid == 0) {

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

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

    execvp(cmds1[0],cmds1);

    }

    int pid2 = coercionk();

    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 = coercionk();

    int status;

    if (pid) {

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

    }

    else {

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

    puts(strerror(errno));

    exit(127);

    }

    }

    }

    }

    return 0;

    }