• C

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 :)
LVL 7
ALNMOOAsked:
Who is Participating?
 
ee_ai_constructConnect With a Mentor Commented:
PAQed, with points refunded (400)
ee_ai_construct - CS Mod
0
 
ankuratvbCommented:
the exec.. functions replace the memory image of the current program and dont return to the program that called them.

0
 
ALNMOOAuthor Commented:
I know that's why I fork a child to run it
0
What Kind of Coding Program is Right for You?

There are many ways to learn to code these days. From coding bootcamps like Flatiron School to online courses to totally free beginner resources. The best way to learn to code depends on many factors, but the most important one is you. See what course is best for you.

 
ankuratvbCommented:
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.
0
 
ankuratvbCommented:
Oh.Sorry.
Didnt see the fork call.

0
 
ALNMOOAuthor Commented:
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*()
0
 
ALNMOOAuthor Commented:
:)
fine you've seen it :)
0
 
ankuratvbCommented:
Thanx. :~)

My suggestions on this one would only be subjective as i dont have linux here.
0
 
ALNMOOAuthor Commented:
thanks any way
0
 
ankuratvbCommented:
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.
0
 
ankuratvbCommented:
It wont execute the wait() also.
Ignore my prev. comment
0
 
ALNMOOAuthor Commented:
now imtrying to use

waitpid() insted of wait...

it's not working as well!
0
 
sunnycoderCommented:
>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 ?
0
 
ALNMOOAuthor Commented:
thanks sunny

I mean a now process...

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

thanks
0
 
sunnycoderCommented:
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.
0
 
sunnycoderCommented:
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
0
 
sunnycoderCommented:
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
>>
0
 
sunnycoderCommented:
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 ?
0
 
ALNMOOAuthor Commented:
leave a space b/w & and any char b4 it...

the objective is the to make a command interpriter :)...
0
 
ankuratvbCommented:
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.

0
 
ALNMOOAuthor Commented:
ankuratvb

it quits and returns to the shell!
0
 
ankuratvbCommented:
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");

0
 
ALNMOOAuthor Commented:
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 :):)
0
 
ALNMOOAuthor Commented:
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 :):)
0
 
ALNMOOAuthor Commented:
thanks all for the help :)
0
 
sunnycoderCommented:
Can either be PAQ/Refund or a split ... There were some helpful suggestions but real problem was solved by the asker
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.