Search code examples
shellinputconcurrencyfork

Simple shell program of two parameters (concurrency problem)


I am trying to complete an assignment which consists in emulating a simple shell program, that gets only 2 parameters and it runs sequentially or concurrently, depending on the user input.

Alhough, I am having a hard time implementing the concurrent version, because when I type in the input sleep 1 & (the ampersan indicates concurrency), the parent does not wait for the child as expected and keeps iterating, but when it goes to the second iteration of the while loop the readSplit function, instead of pausing the program to wait to the user input, it takes the empty buff as input.

Nevertheless, if I write sleep 1 , ls or any command that only requires 2 parameters it works fine.

Some clarifications:

-readSplit just gets the input of the user. It works like the read() function, but it stops reading when it arrives to the separation character. (I know there is a better function that does the same, but this code was provided by the course).

int readSplit( int fin, char* buff, char* s, int maxlen ) {
   int i = 0;
   int oneread = 1;
   char c = *s+1;
   while(c != *s && c != '\n' && oneread == 1 && i < maxlen) {
       oneread = read( fin, &c, 1);
       if(c != *s && c != '\n' && oneread == 1) {
              buff[i] = c;
           i++;
       }
   }
   if(c=='\n') *s = c;
   if(i < maxlen) buff[i] = '\0';
   return i;
}

-startTimer and endTimer can be ignored, they are just measuring the execution time.

MAIN code:

#include <sys/types.h> /* pid_t */
#include <sys/wait.h>  /* waitpid */
#include <sys/types.h> /* pid_t */
#include <sys/wait.h>  /* waitpid */
#include <stdio.h>     /* printf, perror */
#include <stdlib.h>    /* exit */
#include <unistd.h>    /* _exit, fork */
#include <string.h>
#include "myutils.h"

int main(void) {
   int ret;
   int status;
   char buff[80];
   char buff_aux[80];
   char ampersan[1];
   long timer;
   int continueloop = 1;

while (continueloop == 1) {

    char s = ' '; //Separator
    /*Cleaning the information in each loop*/


    memset(buff, 0, sizeof (buff));
    memset(buff_aux, 0, sizeof (buff_aux));
    memset(ampersan, 0, sizeof (ampersan));
    write(1, ">", 1);
    /*Reading user input*/

        readSplit(0, buff, &s, 80);
        printf("%s its my buff string\n", buff);

    if (strcmp(buff, "exit") == 0)break; //If the user wants to exit


    /*If the user has one more parameter we read it and put it in the buff_aux*/
    if (s == ' ' ) {
        if (readSplit(0, buff_aux, &s, 80) == 0)
            exit(1);
    }
    printf("%s is my buff_aux string\n", buff_aux);

    if (s == ' ' ) {
        readSplit(0, ampersan, &s, 1);
        printf("%c is the letter read by ampersan\n", ampersan[0]);

    }
    startTimer();
    /*Creating child*/
    ret = fork();
    printf("ret %d\n", ret);
    printf("im checking if it is a child\n");
    if (ret == 0) {
        printf("im a child\n");
        if (buff[0] == 0) {
            printf("Son: shell program does not exist\n");
            exit(255);
        } else if (buff_aux[0] == 0 || buff_aux[0] == '&') {
            printf("Im about to execute 1\n");
            execlp(buff, buff, NULL);
            exit(2);
        } else {
            printf("Im about to execute 2\n");
            execlp(buff, buff, buff_aux, NULL);
            exit(2);

        }
    }
    if (ampersan[0] != '&') {
        wait(NULL);
        timer = endTimer();
        printf("The process finished and lasted ... %li miliseconds\n", timer);
    }


}
/*waiting to children to finish*/
while (wait(NULL) > 0);
timer=endTimer();

printf("Father waited for son\n");
if (WIFEXITED(status)) {
    status = WEXITSTATUS(status);
    if (status > 0) printf("Father: shell program does not exist\n");
}

return 0;
}

Thank you in advance!


Solution

  • if you input sleep 1 &, input buffer is sleep 1 &\n

    first while:

    1. call readSplit(0, buff, &s, 80);, buff is sleep, input buffer left 1 &\n
    2. call readSplit(0, buff_aux, &s, 80), buffer_aux is 1, input buffer left &\n
    3. call readSplit(0, ampersan, &s, 1); ampersan is &, input buffer left \n

    next while:

    input buffer left \n

    1. call readSplit(0, buff, &s, 80);, buff is empty, c is \n, in child process will call:
    if (buff[0] == 0) {
       printf("Son: shell program does not exist\n");
       exit(255);
    }
    

    you should handle \n in each while