Link to home
Start Free TrialLog in
Avatar of ALNMOO
ALNMOOFlag for Saudi Arabia

asked on

execvp and wiat BUG

Ive got this code:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/wait.h>
#define MAX_BUFFER 256
#define QUIT_STRING "q"

int makeargv(const char *s, const char *delimiters, char ***argvp);
 
int main (void) {
   char **chargv;
   char inbuf[MAX_BUFFER];
   char inbuf2[MAX_BUFFER];
   int  argnum;

   for( ; ; ) {
      printf(">>");
      gets(inbuf);
      strcpy(inbuf2,inbuf);
            
      if (strcmp(inbuf, QUIT_STRING) == 0)
         exit(0);/*return 0;*/
      
        argnum = makeargv(inbuf2, " ", &chargv);
        /*printf("%d\n",argnum);
      printf("%s\n",*(chargv+argnum-1));*/
      
       if( (argnum >0) && (strcmp(*(chargv+argnum-1),"&"))==0) {
                if ((fork() == 0) && (makeargv(inbuf, " ", &chargv) > 0)) {
                        strcpy(*(chargv+argnum-1),"\0");
                        execvp(chargv[0], chargv);
                  }
                  printf("Running in Background\n");
                  /*wait(NULL);*/
      }
       else if ( (argnum >0) && (strcmp(*(chargv+argnum-1),"&"))!=0) {
            if ((fork() == 0) && (makeargv(inbuf, " ", &chargv) > 0)) {
                  printf("%s\n",*(chargv+argnum-1));
                    execvp(chargv[0], chargv);
              }
          wait(NULL);
              printf("Running in Forgound\n");
      }
   }
}

int makeargv(const char *s, const char *delimiters, char ***argvp) {
   int error;
   int i;
   int numtokens;
   const char *snew;
   char *t;

   if ((s == NULL) || (delimiters == NULL) || (argvp == NULL)) {
      errno = EINVAL;
      return -1;
   }
   *argvp = NULL;                          
   snew = s + strspn(s, delimiters);         /* snew is real start of string */
   if ((t = malloc(strlen(snew) + 1)) == NULL)
      return -1;
   strcpy(t, snew);              
   numtokens = 0;
   if (strtok(t, delimiters) != NULL)     /* count the number of tokens in s */
      for (numtokens = 1; strtok(NULL, delimiters) != NULL; numtokens++) ;

                             /* create argument array for ptrs to the tokens */
   if ((*argvp = malloc((numtokens + 1)*sizeof(char *))) == NULL) {
      error = errno;
      free(t);
      errno = error;
      return -1;
   }
                        /* insert pointers to tokens into the argument array */
   if (numtokens == 0)
      free(t);
   else {
      strcpy(t, snew);
      **argvp = strtok(t, delimiters);
      for (i = 1; i < numtokens; i++)
          *((*argvp) + i) = strtok(NULL, delimiters);
    }
    *((*argvp) + numtokens) = NULL;             /* put in final NULL pointer */
    return numtokens;
}    

-----
the problem is when I execute a line with & for the first time
>>sleep 20 &
I can never execute one in forground again! any help

try this when u run the prog and u will know what I mean...

>>sleep 10
>>sleep 10 &
>>sleep 10

thanks :)
Avatar of ankuratvb
ankuratvb
Flag of United States of America image

the exec.. functions replace the memory image of the current program and dont return to the program that called them.

Avatar of ALNMOO

ASKER

I know that's why I fork a child to run it
If the exec*() call succedes, the new process image replaces the current process. I.e. successful calls to the exec functions do not return because the system overlays the calling process with the new process.

If the exec*() functions returns to the calling process image, an error has occurred; the return value is -1 , and the function sets errno to indicate the error.

Have a look, on your OS, at exec(2) (man exec, or man 2 exec) for complete reference.
Oh.Sorry.
Didnt see the fork call.

Avatar of ALNMOO

ASKER

take a look please :)
---
if ((fork() == 0) && (makeargv(inbuf, " ", &chargv) > 0)) {
                 printf("%s\n",*(chargv+argnum-1));
                  execvp(chargv[0], chargv);
            }
--------
noly a forked chiled calls exec*()
Avatar of ALNMOO

ASKER

:)
fine you've seen it :)
Thanx. :~)

My suggestions on this one would only be subjective as i dont have linux here.
Avatar of ALNMOO

ASKER

thanks any way
A few suggestions:

cast the return of malloc() in your makeargv function.


     if( (argnum >0) && (strcmp(*(chargv+argnum-1),"&"))==0) {
             if ((fork() == 0) && (makeargv(inbuf, " ", &chargv) > 0)) {
                   strcpy(*(chargv+argnum-1),"\0");
                   execvp(chargv[0], chargv);
              }
              printf("Running in Background\n");
              /*wait(NULL);*/
    }

//this part executed by parent
     else if ( (argnum >0) && (strcmp(*(chargv+argnum-1),"&"))!=0) {
//this part not executed as "&" has been chopped off to ""
          if ((fork() == 0) && (makeargv(inbuf, " ", &chargv) > 0)) {
                printf("%s\n",*(chargv+argnum-1));
                 execvp(chargv[0], chargv);
           }
         wait(NULL);//waits for child.
 
So,the parent wont execute anything as it is waiting on the child.
It wont execute the wait() also.
Ignore my prev. comment
Avatar of ALNMOO

ASKER

now imtrying to use

waitpid() insted of wait...

it's not working as well!
Avatar of sunnycoder
>gets(inbuf);

NEVER use gets ... replace it with fgets
fgets ( inbuf, MAX_LEN, stdin );

>the problem is when I execute a line with & for the first time
>>>sleep 20 &
>I can never execute one in forground again! any help
Do you mean the exec'ed process ? If yes, then I dont think you can bring it to foreground again ... well you can but it will be a bit difficult ... you will have to associate a controlling tty with that process ....

What exactly are you trying to achieve ?
Avatar of ALNMOO

ASKER

thanks sunny

I mean a now process...

can I know why I should not uses gets! :)

thanks
from gets man page

BUGS
       Never use gets().  Because it is impossible to tell without knowing the
       data in advance how many  characters  gets()  will  read,  and  because
       gets() will continue to store characters past the end of the buffer, it
       is extremely dangerous to use.  It has  been  used  to  break  computer
       security.  Use fgets() instead.
I am still not sure of what you are doing

pls take a step by step example of each and every step and each and every command that you execute on the command line

>the problem is when I execute a line with & for the first time
Is a bit unclear
ok, I get an idea

this is the output I receive
===========================================================

sleep: invalid time interval `&
'
Try `sleep --help' for more information.
Running in Forgound
>>^[[A

Running in Forgound
>>sleep 20&
20&

sleep: invalid time interval `20&
'
Try `sleep --help' for more information.

>>sleep 20 &
&

sleep: invalid time interval `&
'
Try `sleep --help' for more information.
Running in Forgound
>>sleep 10 &
&

sleep: invalid time interval `&
'
Try `sleep --help' for more information.
Running in Forgound
>>


Running in Forgound
>>
changing gets to fgets made some difference however things are a bit crazy still ... everything says running in foreground ...

command parsing needs a bit more efforts

What is the objective of the program ?
Avatar of ALNMOO

ASKER

leave a space b/w & and any char b4 it...

the objective is the to make a command interpriter :)...
After you type a command with an '&',

give the next command as "q" to quit the current process and see if you can run in foreground again or not.

Avatar of ALNMOO

ASKER

ankuratvb

it quits and returns to the shell!
Ok.

     if( (argnum >0) && (strcmp(*(chargv+argnum-1),"&"))==0) {
             if ((fork() == 0) && (makeargv(inbuf, " ", &chargv) > 0)) {
                   strcpy(*(chargv+argnum-1),"\0");
                   execvp(chargv[0], chargv);
              }
              printf("Running in Background\n");
              /*wait(NULL);*/
    }
     else if ( (argnum >0) && (strcmp(*(chargv+argnum-1),"&"))!=0) {
          if ((fork() == 0) && (makeargv(inbuf, " ", &chargv) > 0)) {
                printf("%s\n",*(chargv+argnum-1));
                 execvp(chargv[0], chargv);
           }
         wait(NULL);//try removing this wait call.I guess(i cant execute this) your parent process blocks here.
           printf("Running in Forgound\n");

Avatar of ALNMOO

ASKER

OH GOD

I did it finally

------------
the code

#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#define MAX_BUFFER 256
#define QUIT_STRING "q"

int makeargv(const char *s, const char *delimiters, char ***argvp);

int main (void) {
      char **chargv, *cmd;
      char inbuf[MAX_BUFFER];
      int FLAG, i;
      
      while(1) {
            printf("RBMax>>");
            gets(inbuf); /* gets user input */
            cmd = strtok(inbuf, ";"); /* tokinze input using ";" as delemeter */
            while(cmd != NULL) {
                  if (strcmp(cmd, QUIT_STRING) == 0) /* exit if q */
                        exit(0);
                  
                  FLAG = 0; /* sets the run in background to 0 */
                  for(i = 0; i < strlen(cmd); i++) /*search the input for "&" */
                        if (cmd[i] == '&') { /* if found */
                              FLAG = 1; /* sets the flag to 1 */
                              cmd[i] = ' '; /* replace & with ' ' */
                        } /* end if */
                  
                  
                  if ((fork() == 0) && (makeargv(cmd, " ", &chargv) > 0))
                  {
                        execvp(chargv[0], chargv);
                        printf("Bad command or file name.\n"); /* will be printed if execvp was not executed correctly */
                        exit(-77);
                  }
                  
                  cmd = strtok(NULL, ";"); /* get next token */
                  if (FLAG == 0) /* if to be run in forground */
                        wait(NULL);
            } /* end of while */
      } /* end of while */
}

int makeargv(const char *s, const char *delimiters, char ***argvp) {
      int error;
      int i;
      int numtokens;
      const char *snew;
      char *t;
      
      if ((s == NULL) || (delimiters == NULL) || (argvp == NULL)) {
            errno = EINVAL;
            return -1;
      }
      *argvp = NULL;                          
   snew = s + strspn(s, delimiters);         /* snew is real start of string */
      if ((t = malloc(strlen(snew) + 1)) == NULL)
      return -1;
      strcpy(t, snew);              
      numtokens = 0;
   if (strtok(t, delimiters) != NULL)     /* count the number of tokens in s */
      for (numtokens = 1; strtok(NULL, delimiters) != NULL; numtokens++) ;
      
      /* create argument array for ptrs to the tokens */
      if ((*argvp = malloc((numtokens + 1)*sizeof(char *))) == NULL) {
            error = errno;
            free(t);
            errno = error;
            return -1;
      }
      /* insert pointers to tokens into the argument array */
      if (numtokens == 0)
      free(t);
      else {
            strcpy(t, snew);
            **argvp = strtok(t, delimiters);
            for (i = 1; i < numtokens; i++)
            *((*argvp) + i) = strtok(NULL, delimiters);
      }
    *((*argvp) + numtokens) = NULL;             /* put in final NULL pointer */
      return numtokens;
}    

------

the problem was I did not make sure that a child is kill if exec* was not executed correctly....

WHAT A BUG :):)
Avatar of ALNMOO

ASKER

OH GOD

I did it finally

------------
the code

#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#define MAX_BUFFER 256
#define QUIT_STRING "q"

int makeargv(const char *s, const char *delimiters, char ***argvp);

int main (void) {
      char **chargv, *cmd;
      char inbuf[MAX_BUFFER];
      int FLAG, i;
      
      while(1) {
            printf(">>");
            gets(inbuf); /* gets user input */
            cmd = strtok(inbuf, ";"); /* tokinze input using ";" as delemeter */
            while(cmd != NULL) {
                  if (strcmp(cmd, QUIT_STRING) == 0) /* exit if q */
                        exit(0);
                  
                  FLAG = 0; /* sets the run in background to 0 */
                  for(i = 0; i < strlen(cmd); i++) /*search the input for "&" */
                        if (cmd[i] == '&') { /* if found */
                              FLAG = 1; /* sets the flag to 1 */
                              cmd[i] = ' '; /* replace & with ' ' */
                        } /* end if */
                  
                  
                  if ((fork() == 0) && (makeargv(cmd, " ", &chargv) > 0))
                  {
                        execvp(chargv[0], chargv);
                        printf("Bad command or file name.\n"); /* will be printed if execvp was not executed correctly */
                        exit(-77);
                  }
                  
                  cmd = strtok(NULL, ";"); /* get next token */
                  if (FLAG == 0) /* if to be run in forground */
                        wait(NULL);
            } /* end of while */
      } /* end of while */
}

int makeargv(const char *s, const char *delimiters, char ***argvp) {
      int error;
      int i;
      int numtokens;
      const char *snew;
      char *t;
      
      if ((s == NULL) || (delimiters == NULL) || (argvp == NULL)) {
            errno = EINVAL;
            return -1;
      }
      *argvp = NULL;                          
   snew = s + strspn(s, delimiters);         /* snew is real start of string */
      if ((t = malloc(strlen(snew) + 1)) == NULL)
      return -1;
      strcpy(t, snew);              
      numtokens = 0;
   if (strtok(t, delimiters) != NULL)     /* count the number of tokens in s */
      for (numtokens = 1; strtok(NULL, delimiters) != NULL; numtokens++) ;
      
      /* create argument array for ptrs to the tokens */
      if ((*argvp = malloc((numtokens + 1)*sizeof(char *))) == NULL) {
            error = errno;
            free(t);
            errno = error;
            return -1;
      }
      /* insert pointers to tokens into the argument array */
      if (numtokens == 0)
      free(t);
      else {
            strcpy(t, snew);
            **argvp = strtok(t, delimiters);
            for (i = 1; i < numtokens; i++)
            *((*argvp) + i) = strtok(NULL, delimiters);
      }
    *((*argvp) + numtokens) = NULL;             /* put in final NULL pointer */
      return numtokens;
}    

------

the problem was I did not make sure that a child is kill if exec* was not executed correctly....

WHAT A BUG :):)
Avatar of ALNMOO

ASKER

thanks all for the help :)
Can either be PAQ/Refund or a split ... There were some helpful suggestions but real problem was solved by the asker
ASKER CERTIFIED SOLUTION
Avatar of ee_ai_construct
ee_ai_construct
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial