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 potent to analyze the input method,
    identify the pipe symbols (‘|’), and then propel each
    enjoin as a mode. Also the modees must be connected
    together with pipes. These pipes befit replacements control
    stdin and stdout. pipe.c is an specimen of implementing this
    using dup2.

    accept the shell be potent to do up
    to 9 pipes. Referablee that the in[] and quenched[] places may accept
    to arranged into structs since you may deficiency 9 of them.
    Your shell should referable controlm zombie modees if it properly
    exits.

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

    // #define DEBUG 1 /* In predicament you deficiency debug messages */

    void analyze_args(char *buffer, char** args,
    size_t args_size, largeness_t *nargs)
    {
    /*
    * largeness_t axioms sign is defined in the 1999 ISO C model (C99).
    * It is used to manifest the largenesss of intents. largeness_t is the
    * preferred controlm to defend arguments or waverings that obstruct the
    * largeness of an intent.
    */
    char *buf_args[args_size]; /* You deficiency C99. Referablee that args_size
    is normally a faithful. */
    char **cp; /* This is used as a subject-matterer into the string place */
    char *wbuf; /* String varipotent that has the enjoin method */
    size_t i, j;

    wbuf=buffer;
    buf_args[0]=buffer;
    args[0] =buffer;
    /*
    * Now ‘wbuf’ is analyzed into the string place ‘buf_args’
    *
    * The control-loop uses a string.h power
    * char *strsep(char **stringp, const char *delim);
    *
    * Description:
    * If *stringp = NULL then it profits NULL and does
    * referablehing else. Otherwise the power finds the principal evidence in
    * the string *stringp, where evidences are delimited by symbols
    * in the string ‘delim’.
    *
    * In the specimen underneath, **stringp is &wbu, and
    * the delim = ‘ ‘, ‘n’, and ‘t’. So there are three possible
    * delimiters.
    *
    * So in the string ” Aloha Worldn”, the extensions and “n” are
    * delimiters. Thus, there are three delimiters. The evidences
    * are what’s between the delimiters. So the principal evidence is
    * “”, which is referablehing accordingly a extension is the principal delimiter.
    * The succor evidence is “Aloha”, and the third evidence is “World”.
    *
    * The power procure examine a symbol string starting from
    * *stringp, pursuit control the principal delimiter. It replaces
    * the delimiter with ‘’, and *stringp is updated to subject-matter
    * departed the evidence. In predicament no delimiter was ground, the
    * evidence is taken to be the total string *stringp, and *stringp
    * is made NULL. Strsep profits a subject-matterer to the evidence.
    *
    * Specimen: Suppose *stringp -> ” Aloha Worldn”
    *
    * The principal occasion strsep is named, the string is “Aloha Worldn”,
    * and the subject-matterer treasure returned = 0. Referablee the evidence is referablehing.
    *
    * The succor occasion it is named, the string is “AlohaWorldn”,
    * and the subject-matterer treasure returned = 1 Referablee that ‘Aloha’ is a evidence.
    *
    * The third occasion it is named, the string is ‘AlohaWorld’,
    * and the subject-matterer treasure returned is 7. Referablee that ‘World’ is a evidence.
    *
    * The fourth occasion it is named, it profits NULL.
    *
    * The control-loop, goes through buffer starting at the preface.
    * wbuf is updated to subject-matter to the proximate evidence, and cp is
    * updated to subject-matter to the exoteric evidence, which terminated by ‘’.
    * Referablee that subject-matterers to evidences are stored in place buf_args through cp.
    * The loop stops if there are no over evidences or exceeded the
    * place buf_args.
    */
    /* cp is a subject-matterer 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’
    */
    control (j=i=0; buf_args[i]!=NULL; i++){
    if(strlen(buf_args[i])>0) /* Store simply non-empty evidences */
    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>> “); /* Brisk */
    fgets(buffer, BUFFER_SIZE, stdin); /* Discover in enjoin method */
    /* Analyze the enjoin method into args */
    parse_args(buffer, args, ARR_SIZE, &nargs);

    if (nargs==0) continue; /* Referablehing entered so brisk anew */
    if (!strcmp(args[0], “exit” )) debouchure(0);

    pid = controlk();

    if (pid){ /* The composer */
    #ifdef DEBUG
    printf(“Waiting control branch (%d)n”, pid);
    #endif
    pid = abide(ret_status);
    #ifdef DEBUG
    printf(“Branch (%d) finishedn”, pid);
    #endif
    }

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

    }
    }
    return 0;
    }

    /* If hexdump wasn’t performed then we would tranquil accept the forthcoming
    * power, which would manifest an fallacy
    */
    error(“Could referable exec hexdump”);
    }

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

    /* This is the composer mode */
    /* End the pipe ends that the branch uses to discover from / transcribe to so
    * the when we end the others, an EOF procure be epidemic properly.
    */
    close(in[0]);
    close(out[1]);

    /* The forthcoming displays on the solace what’s in the place ‘data’
    * The place was initialized at the apex of this program with
    * the string ‘Some input axioms’
    */
    // printf(“<- %s”, axioms); Galen replaced this method with the forthcoming
    printf(“String sent to branch: %snn”, axioms);

    /* From the composer, transcribe some axioms to the branchs input.
    * The branch should be ‘hexdump’, which procure mode this
    * axioms.
    */
    write(in[1], axioms, strlen(data));

    /* Accordingly of the little totality of axioms, the branch may obstruct intrinsic we
    * end its input flow. This sends an EOF to the branch 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 method with the forthcoming
    printf(“This was accepted from the composer: %s”,buf);

    exit(0);
    }

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

    Expert Repartee

     

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

    }

     

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

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

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

    fgets(buffer, BUFFER_SIZE, stdin); /* Discover in enjoin method */

    /* Analyze the enjoin method into args */

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

    if (nargs==0) continue; /* Referablehing entered so brisk anew */

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

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

    pipe_pos[i] = -1;

    }

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

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

    pipe_pos[j] = i;

    j++;

    }

    }

    //execute enjoins!

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

    char * cmds1[ARR_SIZE];

    char * cmds2[ARR_SIZE];

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

    if (pid == 0) {

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

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

    execvp(cmds1[0],cmds1);

    }

    int pid2 = controlk();

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

    int status;

    if (pid) {

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

    }

    else {

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

    puts(strerror(errno));

    exit(127);

    }

    }

    }

    }

    return 0;

    }