Solved

execvp and wiat BUG

Posted on 2004-04-29
28
687 Views
Last Modified: 2010-10-05
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 :)
0
Comment
Question by:ALNMOO
  • 11
  • 8
  • 6
  • +1
28 Comments
 
LVL 9

Expert Comment

by:ankuratvb
ID: 10949333
the exec.. functions replace the memory image of the current program and dont return to the program that called them.

0
 
LVL 7

Author Comment

by:ALNMOO
ID: 10949380
I know that's why I fork a child to run it
0
 
LVL 9

Expert Comment

by:ankuratvb
ID: 10949387
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
 
LVL 9

Expert Comment

by:ankuratvb
ID: 10949406
Oh.Sorry.
Didnt see the fork call.

0
 
LVL 7

Author Comment

by:ALNMOO
ID: 10949476
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
 
LVL 7

Author Comment

by:ALNMOO
ID: 10949484
:)
fine you've seen it :)
0
 
LVL 9

Expert Comment

by:ankuratvb
ID: 10949522
Thanx. :~)

My suggestions on this one would only be subjective as i dont have linux here.
0
 
LVL 7

Author Comment

by:ALNMOO
ID: 10949661
thanks any way
0
 
LVL 9

Expert Comment

by:ankuratvb
ID: 10949822
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
 
LVL 9

Expert Comment

by:ankuratvb
ID: 10949872
It wont execute the wait() also.
Ignore my prev. comment
0
 
LVL 7

Author Comment

by:ALNMOO
ID: 10950511
now imtrying to use

waitpid() insted of wait...

it's not working as well!
0
 
LVL 45

Expert Comment

by:sunnycoder
ID: 10950728
>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
 
LVL 7

Author Comment

by:ALNMOO
ID: 10950830
thanks sunny

I mean a now process...

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

thanks
0
What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 
LVL 45

Expert Comment

by:sunnycoder
ID: 10950844
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
 
LVL 45

Expert Comment

by:sunnycoder
ID: 10950888
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
 
LVL 45

Expert Comment

by:sunnycoder
ID: 10950930
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
 
LVL 45

Expert Comment

by:sunnycoder
ID: 10950990
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
 
LVL 7

Author Comment

by:ALNMOO
ID: 10951211
leave a space b/w & and any char b4 it...

the objective is the to make a command interpriter :)...
0
 
LVL 9

Expert Comment

by:ankuratvb
ID: 10951258
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
 
LVL 7

Author Comment

by:ALNMOO
ID: 10951662
ankuratvb

it quits and returns to the shell!
0
 
LVL 9

Expert Comment

by:ankuratvb
ID: 10951872
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
 
LVL 7

Author Comment

by:ALNMOO
ID: 10955186
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
 
LVL 7

Author Comment

by:ALNMOO
ID: 10955187
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
 
LVL 7

Author Comment

by:ALNMOO
ID: 10955215
thanks all for the help :)
0
 
LVL 45

Expert Comment

by:sunnycoder
ID: 11690860
Can either be PAQ/Refund or a split ... There were some helpful suggestions but real problem was solved by the asker
0
 

Accepted Solution

by:
ee_ai_construct earned 0 total points
ID: 11766266
PAQed, with points refunded (400)
ee_ai_construct - CS Mod
0

Featured Post

How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

Join & Write a Comment

Preface I don't like visual development tools that are supposed to write a program for me. Even if it is Xcode and I can use Interface Builder. Yes, it is a perfect tool and has helped me a lot, mainly, in the beginning, when my programs were small…
This is a short and sweet, but (hopefully) to the point article. There seems to be some fundamental misunderstanding about the function prototype for the "main" function in C and C++, more specifically what type this function should return. I see so…
The goal of this video is to provide viewers with basic examples to understand and use structures in the C programming language.
The goal of this video is to provide viewers with basic examples to understand and use conditional statements in the C programming language.

705 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now