• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 636
  • Last Modified:

exec fail

Hi all,
I was asked to write a program that will output each 'command' (separated by pipes) with a separate process along with its process id. While this program will compile together with the makeargv.c (token).
Here is what I have so far:

test.c
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include "ourhdr.h"

extern int makeargv(char *, char * , char ***);

int main()
{
        char **argp;    // THE POINTER TO THE ARRAY OF POINTERS TO BE FILLED BY
        int i,j,vpret;
        char buf[80];   // command line
        pid_t pid;      // process ids
        while(strcmp(fgets(buf, 80, stdin), "exit\n")!=0)  // USER COMMAND
        {
                j=makeargv(buf,"|",&argp); // J = NUMBER OF TOKENS

                for (i=0;i<j;i++)
                        printf("%s process id %d\n",argp[i], pid);
                argp[j]=(char *)0; // replace | with a null
                pid = fork();
                switch (pid) 
                {
                        case -1:
                                err_sys("fork failed");
                                break;
                        case 0: // child
                                execvp(argp[0],argp);
                                write(1,"exec fail\n",10);
                                exit(1);
                        default: // parent
                                waitpid(pid, NULL, 0);
                                write(1,"\nPrompt>",8);
                                break;
                }
        }
        printf(" make argv test exited\n"); //successfully exit
}

Open in new window


and here's the given makeargv.c
#include "makeargv.h"
#include <string.h>
#include <stdlib.h>
/*
* Make argv array (*arvp) for tokens in s which are separated by
* delimiters.   Return -1 on error or the number of tokens otherwise.
*/
int makeargv(char *s, char *delimiters, char ***argvp)
{
  char *t;
  char *snew;
  int numtokens;
  int i;
   /* snew is real start of string after skipping leading delimiters */
  snew = s + strspn(s, delimiters);
                             /* create space for a copy of snew in t */
  if ((t = calloc(strlen(snew) + 1, sizeof(char))) == NULL) {
     *argvp = NULL;
     numtokens = -1;
  } else {                     /* count the number of tokens in snew */
     strcpy(t, snew);
     if (strtok(t, delimiters) == NULL)
        numtokens = 0;
     else
        for (numtokens = 1; strtok(NULL, delimiters) != NULL;
             numtokens++)
             ;
               /* create an argument array to contain ptrs to tokens */
     if ((*argvp = calloc(numtokens + 1, sizeof(char *))) == NULL) {
        free(t);
        numtokens = -1;
     } else {            /* insert pointers to tokens into the array */
        if (numtokens > 0) {
           strcpy(t, snew);
           **argvp = strtok(t, delimiters);
           for (i = 1; i < numtokens + 1; i++)
              *((*argvp) + i) = strtok(NULL, delimiters);
        } else {
          **argvp = NULL;
          free(t);
        }
     }
  }
  return numtokens;
}

Open in new window


the output that I got:

bronco:~> gcc test.c makeargv.c error.c
bronco:~> ./a.out
ls -l | cat test.c | cat test2.c
ls -l  process id 0
 cat test.c  process id 0
 cat test2.c
 process id 0
exec fail

Prompt>ls -l
ls -l
 process id 8051
exec fail

Prompt>ls -l | cat test.c | cat test2.c
ls -l  process id 8052
 cat test.c  process id 8052
 cat test2.c
 process id 8052
exec fail

Prompt>exit
 make argv test exited

Can somebody help me why the process id are all the same and why do i get an "exec fail" at the end everytime? I think i need to use pipe() and dup2() in this program too but I'm not sure what should i do next, can somebody lead me?

Thanks for the help:)
0
crazy4s
Asked:
crazy4s
  • 112
  • 84
  • 7
2 Solutions
 
crazy4sAuthor Commented:
somehow i search through the net about the dup2 and pipe and i edited some of my code
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include "ourhdr.h"

extern int makeargv(char *, char * , char ***);

int main()
{
        char **argp;    // THE POINTER TO THE ARRAY OF POINTERS TO BE FILLED BY
        int i,j,vpret;
        char buf[80];   // command line
        pid_t pid;      // process ids
        int fd[2];

        if (pipe(fd)== -1)
                err_sys("pipe error");             // create a pipe

        while(strcmp(fgets(buf, 80, stdin), "exit\n")!=0)  // USER COMMAND
        {
                j=makeargv(buf,"|",&argp); // J = NUMBER OF TOKENS

                for (i=0;i<j;i++)
                        printf("%s process id %d\n",argp[i], pid);
                argp[j]=(char *)0;

                if((pid=fork())<0)
                        err_sys("forked badly");  // and now both parent and child have copies

                switch (pid)
                {
                        case -1:
                                err_sys("fork failed");
                                break;
                        case 0: // child
                                close(fd[0]);   // close read end of pipe
                                dup2(fd[1],1);  // make 1 same as write to end of pipe
                                close(fd[1]);   // close excess fd
                                execvp(argp[0],argp);
                                write(1,"exec fail\n",10);
                                exit(1);
                        default: // parent
                                close(fd[1]);   // close write end of pipe
                                dup2(fd[0],0);  // make 0 same as read from end of pipe
                                close(fd[0]);   // close excess fd
                                waitpid(pid, NULL, 0);
                                write(1,"\nPrompt>",8);
                                break;
                }
        }
        printf(" make argv test exited\n"); //successfully exit
}

Open in new window


but the output seems to be wrong somewhere as i get a segmentation fault and all the process ids are 0:(

bronco:~> gcc test.c test2.c error.c
bronco:~> ./a.out
ls -l | cat test.c | cat test2.c
ls -l  process id 0
 cat test.c  process id 0
 cat test2.c
 process id 0

Prompt>exec fail
 process id 8238
exec fail

Prompt>Segmentation fault
0
 
Infinity08Commented:
>> Can somebody help me why the process id are all the same

You print the process id (pid) before you assign a value to it (by calling fork).

Furthermore, you'll need to read up on how fork works : it returns the child's process id to the parent, and 0 to the child.


>> and why do i get an "exec fail" at the end everytime?

You need to read up on what pipes really do.

You can execute ONE command with an exec function, but you cannot use pipes in that call.

For example, "ls -l" is the command "ls" with the argument "-l", and you can use an exec function for it.



Suggested reading :

    http://www.yolinux.com/TUTORIALS/ForkExecProcesses.html
0
 
crazy4sAuthor Commented:
I've read through all the stuffs but I don't really understand how it works, like which one will be the parent process and which one will be the child process on the command line?

is there any possibility to not execute ONLY ONE command, like several command right before the pipe (|)?
let's say if i have smt like this on the command line
ls -l | cat test.c > file | file2

>>cannot use pipes in that call
hmmm what do you meant by this?

so for the process id, i'm not sure i'm doing in a right way, can i do smt like this
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include "ourhdr.h"

extern int makeargv(char *, char * , char ***);

int main()  
{
	char **argp; 	// THE POINTER TO THE ARRAY OF POINTERS TO BE FILLED BY
	int i,j,vpret;
	char buf[80]; 	// command line
	pid_t pid; 	// process ids
	int fd[2];

  	if (pipe(fd)== -1) 
		err_sys("pipe error");             // create a pipe 

	while(strcmp(fgets(buf, 80, stdin), "exit\n")!=0)  // USER COMMAND
	{
 		j=makeargv(buf,"|",&argp); // J = NUMBER OF TOKENS
		
  		for (i=0;i<j;i++)
    			printf("%s",argp[i]);	// command to execute
		argp[j]=(char *)0;	// replace | with null

       		pid=fork();

        	switch (pid)
        	{
        		case -1:
				err_sys("fork failed");
				break;
        		case 0: // child
				close(fd[0]);	// close read end of pipe
				dup2(fd[1],1);	// make 1 same as write to end of pipe
				close(fd[1]);	// close excess fd
 				execvp(argp[0],argp);
				write(1,"exec fail\n",10);
				exit(1);
        		default: // parent
				close(fd[1]);	// close write end of pipe
				dup2(fd[0],0);	// make 0 same as read from end of pipe
				close(fd[0]);	// close excess fd
                		waitpid(pid, NULL, 0);
				write(1,"\nPrompt>",8);
				break;
        	}
		printf(" Process ID: %d\n",pid);  // print the process id
	}
	printf(" make argv test exited\n"); //successfully exit
}

Open in new window


well I know is wrong as the output seems to be the same~
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
Infinity08Commented:
>> like which one will be the parent process and which one will be the child process on the command line?

If you call fork, then a new process (the child) is created. Both processes (the original, or the parent, and the new, or the child) are (for most intents and purposes) pretty much perfect copies. By checking the return value of fork, you can distinguish between what the child should do, and what the parent should do.


>> is there any possibility to not execute ONLY ONE command, like several command right before the pipe (|)?

If you mean forking off multiple children, and having each child execute different code, then sure, you can do that.


>> >>cannot use pipes in that call
>> hmmm what do you meant by this?

I mean that exec executes code in a process.
Pipes are a way to communicate between different processes, so exec cannot deal with that (since it only deals with one process).
To use pipes, you need to set them up separately. Please refer to the link I posted earlier - it contains an example of how you can do that.
0
 
crazy4sAuthor Commented:
so how do we determine which one is the parent process and child process?
is it the right most command will be the parent process and then forking every command to the left and that'll be the child process??? i'm confused~

>>If you mean forking off multiple children, and having each child execute different code, then sure, you can do that.
yes this is what i want, what should i do next?

i read through the fork and execvp func but it doesn't seems to have any pipe explanation there, did i missed out?
0
 
Infinity08Commented:
>> so how do we determine which one is the parent process and child process?
>> is it the right most command will be the parent process and then forking every command to the left and that'll be the child process??? i'm confused~

parent or child processes have nothing to do with pipes.

You use fork to create new (child) processes, and you can use pipes to communicate between those processes.



>> i read through the fork and execvp func but it doesn't seems to have any pipe explanation there, did i missed out?

You can do a search on that page for the word "pipe" ;)
0
 
crazy4sAuthor Commented:
r u referring to this?
if yes, so do you meant that after i fork i have to use pipes (below) but replace the command with argp[0]???
so basically the pipe does store the whole command (before the |)???
and we need to use pipe to access it???

#include <stdio.h>
main()
{
   FILE *fpipe;
   char *command="ls -l";
   char line[256];

   if ( !(fpipe = (FILE*)popen(command,"r")) )
   {  // If fpipe is NULL
      perror("Problems with pipe");
      exit(1);
   }

   while ( fgets( line, sizeof line, fpipe))
   {
     printf("%s", line);
   }
   pclose(fpipe);
}
                

Open in new window

0
 
Infinity08Commented:
Can you explain to me what you think a pipe is, and how you think it works ?
0
 
crazy4sAuthor Commented:
not too sure how it works basically but it creates file descriptor that fd[0] is to read from and fd[1] is to write to???
0
 
crazy4sAuthor Commented:
i know is somekind like read from the parent process and write to child process... but i still don't get it where you get the parent process as i know when you call fork that's how the child process (new process) came?
0
 
crazy4sAuthor Commented:
hmm i still don't get how is the procedure goes, can someone explain step by step like should I create the pipe first or not, and then when should i use fork, when should i use exec, when to should i use dup2, i'm getting confused around this few system call in my prog! as i know the func of this stuffs but when all come together i dunno which one should come first.

any help will be greatly appreciated:)
0
 
sarabandeCommented:
assuming you have

   
pid_t child;
    ...
    child = fork();

Open in new window


then in any following code you can determine whether it is the parent (or not the child) by


   
if (child != 0)
    {
          // the following code will be performed by the parent only

Open in new window


that is - as infinity08 has already told you - cause the fork() returns the child pid in case the call is made by the parent and returns 0 if fork() was called by the child.

Sara
0
 
crazy4sAuthor Commented:
but how do we know whether it is parent or child, hmm ok i know it determine by whether the return value is 0 or non 0, but is there other ways to determine that, because i don't quite understand?
0
 
crazy4sAuthor Commented:
one more thing  r we able to determine the parent and child based on the command line that the user input...
let's say
prompt>ls -l | cat test.c | cat test2.c
0
 
sarabandeCommented:
you already have the decision in the code you posted. look at the switch statement where it has three cases for the return value of fork. -1 is an error. 0 is the child. and != 0 is the parent.

the fork is made to be able to run two processes with one main and one executable file. it is an ambitious concept and not suitable for all purposes and you would need a little bit experience in multiprocessing and multithreading.

in my opinion you better would go with posix_spawn. it would create a new process and would return the pid of that process.

Sara
0
 
crazy4sAuthor Commented:
so that's the only way to determine whether it's parent or child.
well because i wanted to understand this and cont doing with the code that i have if possible and the posix_spawn is smt that I haven reach i meant in his lecture.

can somebody lead me on this code, where i did wrong and what should i do next?

#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include "ourhdr.h"

extern int makeargv(char *, char * , char ***);

int main()
{
        char **argp;    // THE POINTER TO THE ARRAY OF POINTERS TO BE FILLED BY
        int i,j,vpret;
        char buf[80];   // command line
        pid_t pid;      // process ids
        int fd[2];

        if (pipe(fd)== -1)
                err_sys("pipe error");             // create a pipe

        while(strcmp(fgets(buf, 80, stdin), "exit\n")!=0)  // USER COMMAND
        {
                j=makeargv(buf,"|",&argp); // J = NUMBER OF TOKENS

                pid=fork();

                for (i=0;i<j;i++)
                        printf("%s\n",argp[i]);

                switch (pid)
                {
                        case -1:
                                err_sys("fork failed");
                                break;
                        case 0: // child
                                close(fd[0]);   // close read end of pipe
                                dup2(fd[1],1);  // make 1 same as write to end of pipe
                                close(fd[1]);   // close excess fd
                                execvp(argp[0],argp);
                                exit(1);
                        default: // parent
                                close(fd[1]);   // close write end of pipe
                                dup2(fd[0],0);  // make 0 same as read from end of pipe
                                close(fd[0]);   // close excess fd
                                waitpid(pid, NULL, 0);
                                write(1,"\nPrompt>",8);
                                break;
                }
		printf("%s process id %d\n",argp[0], pid);
        }

        printf(" make argv test exited\n"); //successfully exit
}

Open in new window


here's the output with error
bronco:~> gcc test.c test2.c error.c
bronco:~> ./a.out
ls -l | cat test.c
ls -l
 cat test.c

ls -l
 cat test.c


Prompt>ls -l  process id 9974
Segmentation fault

0
 
sarabandeCommented:
your input is not more than a string. there are no processes involved. if you ask for input before fork the parent and child share the string variable. if you do it after fork each process has its own input (means the user must do input twice) and if you ask for input in a sequence exclusive for the parent (or child) the string is available only for the parent (or child).

you only would get more processes if you parsed the input for the three comands and spawn a new process for each to execute the individual command. for that the pthread_spawn would be much better than the fork.

Sara
0
 
crazy4sAuthor Commented:
so do you meant the pid=fork() should put before the while loop before the arguments?
but even if i tried to put it before the while loop, the output is still nothing difference so i'm sure i'm wrong somewhere else again...

bronco:~> gcc test.c test2.c error.c
bronco:~> ./a.out
ls -l | cat test.c
ls -l
 cat test.c


Prompt>ls -l  process id 10690
Segmentation fault

hmm can u give some example on the pthread_spawn , because it's something that i haven touch before!
0
 
crazy4sAuthor Commented:
hmm and what do you meant by inout not more than a string?
0
 
sarabandeCommented:
the function is called posix_spawn and not pthread_spawn. sorry for confusion.

i looked at the code (not very deeply) and i mean the fork is not necessary.

the makeargv does what i called 'parsing'. so it doesn't more than splitting the input into three commands. you see that each command will be executed via execvp . so the fork child process not really was used beside of that fd statements which i didn't understand til yet. in my opinion you simply could omit the fork and call the execvp from parent process for each command.

Sara
0
 
crazy4sAuthor Commented:
yes the makeargv is to break the command line into token and this test.c is to split the command by |.
hmm do you meant just like this
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include "ourhdr.h"

extern int makeargv(char *, char * , char ***);

int main()
{
        char **argp;    // THE POINTER TO THE ARRAY OF POINTERS TO BE FILLED BY
        int i,j,vpret;
        char buf[80];   // command line
        pid_t pid;      // process ids

	while(strcmp(fgets(buf, 80, stdin), "exit\n")!=0)  // USER COMMAND
        {
                j=makeargv(buf,"|",&argp); // J = NUMBER OF TOKENS

                for (i=0;i<j;i++)
                        printf("%s\n",argp[i]);

                switch (pid)
                {
                        case -1:
                                err_sys("fork failed");
                                break;
                        case 0: // child
				write (1,"exec fail\n", 10);
                                exit(1);
                        default: // parent
                                waitpid(pid, NULL, 0);
                                write(1,"\nPrompt>",8);
                                execvp(argp[0],argp);
                                break;
                }
		printf("%s process id %d\n",argp[0], pid);
        }

        printf(" make argv test exited\n"); //successfully exit
}

Open in new window


and the output

bronco:~> gcc test.c test2.c error.c
bronco:~> ./a.out
ls -l | cat test.c
ls -l
 cat test.c

exec fail
0
 
crazy4sAuthor Commented:
but i need to print the process id is it meant that i've to use the posix_spawn?? or can i do smt like pid_t pid; and then smt like pid = getppid()/getpid();
0
 
sarabandeCommented:
no, if you omit the fork you don't need the switch on pid either.

you only would use the token to execute a new command.

the problem with that is - and infinity08 already told you - that execvp cannot execute shell commands. you probably would need execute the command by calling

      system(command);

or probably

   execl(<shell path>, "sh", "-c", command, (char*)0);

for both i don't know how you could get the pid from the processes. and executing three commands isn't the same than executing one command with three piped subcommands.

Sara
0
 
crazy4sAuthor Commented:
so what should i do in order to execute numerals command with numerals pipes with their process ids? what should i need to do?
0
 
Infinity08Commented:
Heh, I'm absent for a bit, and the discussion takes on a different direction.

Anyway, let's get back to my question in http:#35188024

You said in response to that :

>> not too sure how it works basically but it creates file descriptor that fd[0] is to read from and fd[1] is to write to???

>> i know is somekind like read from the parent process and write to child process... but i still don't get it where you get the parent process as i know when you call fork that's how the child process (new process) came?


As I said before : pipes allow communication between two processes (any two processes). There is no parent or child - just two processes. The parent/child terminology is purely related to fork, not to pipes.

Now, a pipe allows one process to send data to another process (through a pipe, so to speak). In order to make this work, you need to create such a "pipe" between the processes, and allow one of the processes to write into the pipe (ie. send data through it), and the other process to read from it (ie. receive data from it).

The shell allows you to create such pipes between two processes by using the '|' character (conveniently named the pipe character). For example :

        ls -l | more

would create two processes (one for the ls command, and onr for the more command). Note that each of these processes can have their own command line arguments (in the example above, the ls command has a -l argument).
A pipe is set up between these processes that connects the standard output of the first command (the ls command) to the standard input of the second command (the more command). Or, in other words, the write end of the pipe is attached to the ls command's standard output, and the read end of the pipe is attached to the more command's standard input.

That way, any output generated by the ls command can be read by the more command.


Does that explain better what pipes are, and how they work ?

Please make sure to ask questions if there's something about this that you still don't understand, because there's no sense in continuing if you don't fully understand what pipes are and how they work.
0
 
sarabandeCommented:
i never did it myself (at linux), so i don't want to push you to a wrong direction.

but the trick could be to not execute the command directly but to execute the sh (as i posted with the execl call). if you would use the posix_spawn for that you should get returned the pid of the shell executed. i don't know if that is what you want.

Sara
0
 
crazy4sAuthor Commented:
ok u did give an example for ls -l | more but will that also works with other arguments (not likely to be related) like ls -l | cat test.c will it still works the same?
0
 
sarabandeCommented:
nice to have you back infinity08 :)

my knowledge about spawning commands at linux programmatically is a bit weak. so i hope you can help with that.

Sara
0
 
crazy4sAuthor Commented:
because i'm kind of new to this stuffs, so actually i don't really know which one should i use, but i think the lecturer's example would somehow related to the given assignments as he perform fork(), dup2() and execvp separately in different programs. and so now what he wants us to do  is to output each 'command' (separated by pipes) with a separate process along with its process id.
something like this
prompt> A B C | D E F
A B C process id 41
D E F process id 42

so any explanations and help will be greatly appreciated:)
0
 
Infinity08Commented:
>> ok u did give an example for ls -l | more but will that also works with other arguments (not likely to be related) like ls -l | cat test.c will it still works the same?

Semantically, what that is trying to do, works the same : ie. create two processes, with a pipe between them.

However, this one seems like it is not very useful. The ls command generates standard output - so far so good. But the cat command (as it is used in the example you give) doesn't read anything from standard input, so the pipe is useless.


That shouldn't hold you back though, because our first goal is to understand how pipes work. Do you have any questions about that part ?
0
 
crazy4sAuthor Commented:
so the pipe basically works after you've forked a process, am i right?
0
 
Infinity08Commented:
>>  so the pipe basically works after you've forked a process, am i right?

Forget about forking for now. It's unrelated to how pipes work.

Sure, you might use fork to create the processes that will then communicate through a pipe. But in order to understand pipes, you don't need to consider forking - just the existence of two processes.

Once you are confident that you understand pipes, we can move on from there.
0
 
crazy4sAuthor Commented:
then yes, as long as there're two or more processes then the pipe will be used to communicate through this processes!
0
 
Infinity08Commented:
Ok. So, say I have two applications. The first writes 2 lines of text on standard output, and when run on its own, would look like this :

        $ app1
        this is the first line
        this is the second line
        $

The second (app2) writes anything it reads from standard input to the file specified as its command-line argument.

Can you explain in your own words what would happen if I execute this on the shell ?

        $ app1 | app2 test.txt
0
 
crazy4sAuthor Commented:
it'll writes the two lines that you've entered in app1 into app2 test.txt?
0
 
Infinity08Commented:
>> it'll writes the two lines that you've entered in app1 into app2 test.txt?

The two lines output by app1 will be written into the test.txt file by app2, because the standard output of app1 was sent to the standard input of app2 through the pipe.

Ok, so far so good. We seem to have pipes covered.

Now, what else do we need in order to solve your assignment. You haven't posted the exact wording of your assignment (could you do so, please), but from the examples you gave, it seems like the pipes are used incorrectly. So, let's clarify that first : what is your exact assignment ?
0
 
crazy4sAuthor Commented:
because i'm kind of new to this stuffs, so actually i don't really know which one should i use, but i think the lecturer's example would somehow related to the given assignments as he perform fork(), dup2() and execvp separately in different programs. and so now what he wants us to do  is to output each 'command' (separated by pipes) with a separate process along with its process id.
something like this
prompt> A B C | D E F
A B C process id 41
D E F process id 42

So based on either the 1st/2nd post of my code I have what should I do next or what should I edit in order to get such output?
0
 
Infinity08Commented:
>> because i'm kind of new to this stuffs, so actually i don't really know which one should i use,

Note that I wasn't talking about your code, but rather about the examples of input you gave, like :

>> Prompt>ls -l | cat test.c | cat test2.c

This example does not seem useful when interpreting the pipes.


About your assignment, could you please post the exact text of the assignment ?
0
 
crazy4sAuthor Commented:
hmm what are the text that you need?
because he only gave us this
1)One shell, one forked processes, one pipe, two dup2s, two execl,
 ls -l      |       more
2)execvp a command in the middle of  multi-command user input
3)Write a program that will output each 'command' (separated by pipes) with a separate process along with its process id.
0
 
Infinity08Commented:
>> because he only gave us this

That's good enough, thanks (note that you hadn't posted that before).

Ok, so since we covered pipes, let's move on to how we create new processes.

We have the main process already (ie. the initial one), and we can use fork to "clone" this process, and create a second (almost identical) process. The former (the original) is called the parent process, and the latter (the forked) is called the child process.

If the fork call succeeded, there will be 2 processes, each executing the same code, starting right after the fork call. We can use the return value of fork to determine which is the parent, and which is the child (as mentioned earlier), so we can have both processes execute different code.

That gives us a way to create a second process.

Note that you can call fork as many times as you want, and each time you'll create a new process in the same way as described above.


Does that make sense ?

Could you write some code that forks off two child processes, and makes them print some output ? Just to get used to how fork works.
0
 
crazy4sAuthor Commented:
i'm not sure exactly how to forks off two child processes but do you meant something like that hmm since you want two child process, do we need to call fork twice?

pid_t pid = fork();
switch (pid)
        {
        case -1: printf("bad fork\n");break;
        case 0: // child
                write(1,"something",10);
                pid=fork(); // not sure whether to put here or not?
                break;
        default: // parent
        write(fd[0],"more\nstuff",10);break;
        }

Open in new window

0
 
crazy4sAuthor Commented:
oops hmm should be smt like this
pid_t pid = fork();
switch (pid)
        {
        case -1: printf("bad fork\n");break;
        case 0: // child
                write(1,"something",10);
                pid=fork(); // not sure whether to put here or not?
                break;
        default: // parent
                break;
        }

Open in new window

0
 
Infinity08Commented:
>>  i'm not sure exactly how to forks off two child processes but do you meant something like that

You seem to have copied that from somewhere, no ?

Could you write some of your own code that creates two child processes, and lets them print out something on standard output (like "This is child process 1" eg.) ?


>> hmm since you want two child process, do we need to call fork twice?

That's correct.
0
 
Infinity08Commented:
>> pid=fork(); // not sure whether to put here or not?

Think about it. If you want the original process to create two child processes, where do the two fork calls go ?
0
 
Infinity08Commented:
Btw, try actually running the code, to see if it does what you expect or not. Just experiment a bit with some test code for forking. Play around with it to get a feeling for it :)
0
 
crazy4sAuthor Commented:
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include "ourhdr.h"

int main()
{

        pid_t pid = fork();
        if (pid == 0)
        {
                printf("child process 1\n");
        }
        pid = fork();
        if (pid == 0)
        {
                printf("child process 2\n");
        }
}

Open in new window


output

child process 1
child process 2
child process 2

not sure why the 2nd time i fork it prints out twice?
0
 
crazy4sAuthor Commented:
hmm regarding why it printed twice is it because the 2nd time i forked, i'm actually forking two processes, the original and the one that it forks (the 1st time), that's why i have child process 2 printed twice?
0
 
Infinity08Commented:
>> not sure why the 2nd time i fork it prints out twice?

Remember that the child process is an exact copy of the parent process ?

So, it also executes the same code, starting from the line after the fork call.

Below is an overview of what each process does in that code.  Children starting with a P are started by the parent, children starting with a C are started by the first child. A * means that the code is executed in that process.

As you can see from the diagram, both the PARENT and CHILD P1 are executing the second fork, so each creates another child process. As such, the process tree becomes something like this :

        PARENT
              |---------> CHILD P1
              |                           \------------> CHILD C11
              |
              \---------> CHILD P2
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include "ourhdr.h"

int main()                                                 // PARENT        CHILD P1         CHILD P2         CHILD C11
{                                                          // ------        --------         --------         ---------

        pid_t pid = fork();                                //   *
        if (pid == 0)                                      //   *              *
        {                                                  //                  *
                printf("child process 1\n");               //                  *
        }                                                  //                  *
        pid = fork();                                      //   *              *
        if (pid == 0)                                      //   *              *                *                 *
        {                                                  //                                   *                 *
                printf("child process 2\n");               //                                   *                 *
        }                                                  //                                   *                 *
}

Open in new window

0
 
Infinity08Commented:
Or to look at the same code in a different light :
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include "ourhdr.h"

int main()
{

        pid_t pid = fork();                             // <--- PARENT starts executing from this line until the end of main
        if (pid == 0)                                   // <--- CHILD P1 starts executing from this line until the end of main
        {
                printf("child process 1\n");
        }
        pid = fork();
        if (pid == 0)                                   // <--- CHILD P2 and CHILD C11 start executing from this line until the end of main
        {
                printf("child process 2\n");
        }
}

Open in new window

0
 
crazy4sAuthor Commented:
So this means the child process 1 is P1 and child process 2 is P2 and C11... so what should I do so that the parent executes 2 children?
0
 
crazy4sAuthor Commented:
Is there any possibility to have the second fork place within here (remove lines starting from 2nd fork)
if (pid!=0)
{
    pid=fork();
    if (pid=0)
       printf("child process 2");
}
0
 
Infinity08Commented:
>> Is there any possibility to have the second fork place within here

You could do that (or have an else block for the parent part).

Or you could include an exit or return call as soon as you want the child to end.
0
 
crazy4sAuthor Commented:
so back to the question that you asked me to do, is it correct to do it like that:
but the prob is i'm not sure the output are child P1 and child P2 or not?
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

int main()
{

        pid_t pid = fork();
        if (pid == 0)
        {
                printf("child process 1\n");
        }
        if (pid != 0)
        {
                pid = fork();
                if (pid == 0)
                {
                        printf("child process 2\n");
                }
        }
 
}

Open in new window



cpfoo@csa04 as4$ gcc t.c
cpfoo@csa04 as4$ ./a.out
child process 1
child process 2
0
 
Infinity08Commented:
>> so back to the question that you asked me to do, is it correct to do it like that:

As in my previous post : yes.

You could also use else instead of if (pid != 0) :

        pid_t pid = fork();
        if (pid == 0) {
            /* the child */
        }
        else {
            /* the parent */
        }

or you could use exit or return to end the child when needed :

        pid_t pid = fork();
        if (pid == 0) {
            /* the child */
            exit(0);
        }
        /* the parent */

Note that you probably also want to check whether fork succeeded without error (in the parent), by checking the return value for -1.
0
 
crazy4sAuthor Commented:
yes i know that i should've assign an error msg for that just in case it returns negative value.
so to put an exit(0) at the child can actually exit the child and can it prevents not to being forked again?
0
 
Infinity08Commented:
exit(0) ends the process from which it's called from. If you call it from the child, then you end the child process, preventing it from doing anything else, including forking (it's no longer running after all).
0
 
crazy4sAuthor Commented:
okay i get what you meant, so what should we do next?
i really appreciate that you teaches me step by step:)
0
 
Infinity08Commented:
So, we've got forking now.

Let's talk about what the exec family of functions does.

execl (and consorts) replaces the current process (the process it's called from) with a new process specified by the arguments.

For example, if you do :

        execl("/bin/ls", "/bin/ls", 0);

you replace the current process with a process that runs /bin/ls

Try replacing one of the child printf's in your last code (from http:#35192693) with the above line to see what happens.
0
 
crazy4sAuthor Commented:
i tried to run it and the output is same as the command ls

child process 1
a.out     t.c       t.c.save

is there any possibility for the first 2 arguments in execl to be different? i read the link that you've provided earlier saying that the first argument is the path and the 2nd should be the argv that we input(i'm not sure for this?)
the current process u meant is after the 2nd time fork is it? so instead it forks another child from the parent it actually does the command ls?
0
 
Infinity08Commented:
>> i tried to run it and the output is same as the command ls

That's to be expected, because /bin/ls is one and the same as the ls command ;)

Notice how one of your child processes now runs /bin/ls instead of the printf ? You can experiment with this further by placing a printf before and after the execl call ... Try to guess what'll happen then, and then test it out to see if you were right.


>> is there any possibility for the first 2 arguments in execl to be different?

In the case of execl, that's not very useful, but we'll get to that later.


>> the current process u meant is after the 2nd time fork is it?

The current process I was referring to, is whatever process you call the exec from. It could be the first child, or the second child, or even the parent.
Whatever process you run exec from will be replaced by a process specified in the arguments.


>> so instead it forks another child from the parent it actually does the command ls?

The fork call is to create a new process.
The exec call is to replace that new process with another. The exec call doesn't create a new process, it just changes an already existing one.
0
 
crazy4sAuthor Commented:
before running i was expect it to be smt like this
child process 1
child process 2
a.out     t.c       t.c.save
a.out     t.c       t.c.save //as i thought the 3rd printf will be replaced by the ls command too

int main()
{

        pid_t pid = fork();
        if (pid == 0)
        {
                printf("child process 1\n");
        }
        if (pid != 0)
        {
                pid = fork();
                if (pid == 0)
                {
                        printf("child process 2\n");
                        execl("/bin/ls", "/bin/ls", 0);
                        printf("child process 3\n");
                }
        }

}

Open in new window


but it seems that i've guessed wrongly that it only prints out once for the execl
so is this happened because of the null terminated as the last argument in execl?
is the null terminated matters in this condition?

child process 1
child process 2
a.out     t.c       t.c.save
0
 
Infinity08Commented:
>> but it seems that i've guessed wrongly that it only prints out once for the execl

It happens because the moment you call exec, the whole process is replaced with whatever you specify as arguments to the exec call.

So, whatever comes after the exec call is no longer executed. It's no longer there (since it has been replaced by the /bin/ls code in this case).

The first printf is still executed, because it's before the exec call - ie. the original code hasn't been replaced yet.


Now, try moving the execl call to the first child process code. Can you guess what will happen ?
0
 
crazy4sAuthor Commented:
yes i guessed it correctly for this time
int main()
{

        pid_t pid = fork();
        if (pid == 0)
        {
                printf("child process 1\n");
                execl("/bin/ls", "/bin/ls", 0);
                printf("nothing\n");
        }
        if (pid != 0)
        {
                pid = fork();
                if (pid == 0)
                {
                        printf("child process 2\n");
                        printf("child process 3\n");
                }
        }
 
}

Open in new window


child process 1
a.out     t.c       t.c.save
child process 2
child process 3

as whatever comes after execl in that current loop only are not executed!
0
 
crazy4sAuthor Commented:
one more thing that i wanted to clarify....
so the above code is still works the same is it?
child process 1 and the execl are under P1
child process 2 and child process 3 are actually under P2
am i correct up to this point using the diagram that you've drew ealier?
0
 
Infinity08Commented:
>> child process 1 and the execl are under P1
>> child process 2 and child process 3 are actually under P2

That's correct. So :
int main()                                                 // PARENT        CHILD P1         CHILD P2
{                                                          // ------        --------         --------

        pid_t pid = fork();                                //   *
        if (pid == 0)                                      //   *              *
        {                                                  //                  *
                printf("child process 1\n");               //                  *
                execl("/bin/ls", "/bin/ls", 0);            //                  *
                printf("nothing\n");                       //                  *
        }                                                  //                  *
        if (pid != 0)                                      //   *              *
        {                                                  //   *
                pid = fork();                              //   *
                if (pid == 0)                              //   *                                *
                {                                          //                                    *
                        printf("child process 2\n");       //                                    *
                        printf("child process 3\n");       //                                    *
                }                                          //                                    *
        }                                                  //   *
 
}

Open in new window

0
 
crazy4sAuthor Commented:
okay done so what to do next?
0
 
Infinity08Commented:
Notice that I included the printf("nothing\n"); line in the P1 process. That is because there is one case in which it can get run. If all goes well, the exec call succeeds, and that printf is never run, but if the exec call fails, then the second printf is still run.
0
 
crazy4sAuthor Commented:
yes i know is only when the exec call success and so whatever comes after will be ignored but if it fails then whatever comes after will carry on, right?
0
 
crazy4sAuthor Commented:
btw in what case will the execl fails?
and for the 1st and 2nd argument in execl, is that a possibility to be different (currently in your ex both are the same)?
i know the 1st argument should be smt like a path and the 2nd argument is supposed to be some argv, but not really get how this works...
0
 
Infinity08Commented:
>> okay done so what to do next?

There is one more thing to say about exec, and that is that there are different functions in the exec family. All of them do the same thing (replace an existing process with one specified by the arguments), but they all do it in a slightly different way.

Have a look at the man page for exec :

        man exec

to see which ones are available on your platform.

For example, execv is very similar to execl, except that the arguments are passed as an array instead of separate arguments. So :

        execl("/bin/ls", "/bin/ls", 0);

is equivalent to :

        char* args[2] = { "/bin/ls", 0 };
        execv("/bin/ls", args);

Have a read through the man page, and try to understand why the first two arguments to execl are the same, and why there is a 0 as third argument.
Try to play with passing arguments to /bin/ls to see if you can get it to show the ls output differently (try the -l argument eg.).
0
 
crazy4sAuthor Commented:
>>The  pathname specified  in the interpreter file is passed as arg0 to the interpreter.
that's why the first and second argument are the same as the name for the file(command)?

and for the null at the end of the execl is to end the argument list....

i tried to replace ls with -l and the execl fails! because -l is not a command.
hmm can you give an example for execl if it has more than 2 arguments, how will it looks like?
and how does it differ from just using 2 arguments?
0
 
Infinity08Commented:
>> i tried to replace ls with -l and the execl fails! because -l is not a command.

ls is the command, and -l is the argument.

If you'd execute it on the command line, you'd use :

        ls -l

Try running that, and then try getting the same output using any exec function your prefer (just by passing it one extra argument "-l").
0
 
crazy4sAuthor Commented:
ahh that's what i was actually asking... i mistaken it at first
int main()
{

        pid_t pid = fork();
        if (pid == 0)
        {
                printf("child process 1\n");
                execl("/bin/ls", "/bin/ls","-l", 0);
                printf("nothing\n");
        }
        if (pid != 0)
        {
                pid = fork();
                if (pid == 0)
                {
                        printf("child process 2\n");
                        printf("child process 3\n");
                }
        }

}

Open in new window



child process 1
total 32
-rwxr-xr-x   1 cpfoo    ugrad       6280 Mar 22 16:23 a.out
-rw-r--r--   1 cpfoo    ugrad        384 Mar 22 16:23 t.c
-rw-------   1 cpfoo    ugrad        289 Mar 22 15:06 t.c.save
child process 2
child process 3

so the extra argument actually works together with the 1st argument, they compile it in 1 command!
0
 
crazy4sAuthor Commented:
hmm but i'm not really know how it works for execvp, can you give some explanations for it too?
0
 
Infinity08Commented:
>> so the extra argument actually works together with the 1st argument, they compile it in 1 command!

The arguments are arguments to the command. They are passed to exec together with the command itself.

If you want, you can experiment with the other types of exec functions (like execv eg.) to see how they work.

Once you feel comfortable with them, you should have enough information to complete your assignment. So, have a go at splitting up an input string in commands, forking a new child for each of them, and using exec to actually execute the command.
0
 
Infinity08Commented:
>> hmm but i'm not really know how it works for execvp, can you give some explanations for it too?

Sure. execvp works in the same way as execv (see my example earlier), except that it doesn't require a complete path for the executable.

Since the /bin directory is in your PATH, with execvp, you can just use "ls" instead of "/bin/ls". Other than that, the way it works is the same as execv.
0
 
crazy4sAuthor Commented:
yes i've tried for execv and execvp and it works the same!
btw since argument 1 and 2 have to be the same in execl for execv and execvp there's a null terminated at the end, does it meant to have the same meaning as why execl has a null terminated as the last argument too?
               
 char* args[2] = { "ls", 0 };
 execvp("ls", args);

and regarding my assignment, once i have separate each command by pipes, i need to use fork to fork each command (just like i fork the process but this time i only need to fork 1 child process for each command is it?) then only i execvp the command?
but how do i print out their process ids?
and in this assignment do i need to use dup2()?
0
 
Infinity08Commented:
>> does it meant to have the same meaning as why execl has a null terminated as the last argument too?

Yes. The NULL at the end indicates the end of the argument list, and it has to be there.


>> (just like i fork the process but this time i only need to fork 1 child process for each command is it?)

Correct.


>> then only i execvp the command?

Yep.


>> but how do i print out their process ids?

Remember that fork returns the child process id to the parent ? The parent can print the process id for every child it creates.


>> and in this assignment do i need to use dup2()?

Try getting it to work without involving pipes first.

You can then use pipe to create the pipe (see : man 2 pipe), and dup2 to redirect stdin and stdout as appropriate (see : man 2 dup2).
0
 
crazy4sAuthor Commented:
hmm can you tell what is this error meant to be (is in makeargv.c)
well at first i compiled this at another machine it was fine, but when i changed to another machine this error pops up???

In file included from /usr/include/string.h:18,
                 from as4b.c:2:
/usr/include/iso/string_iso.h:59: error: syntax error before "extern"
0
 
crazy4sAuthor Commented:
i used back the previous machine to compile this file
hmm although i understand how it works but i'm abit confused
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include "ourhdr.h"

extern int makeargv(char *, char * , char ***);

int main()
{
        char **argp;    // THE POINTER TO THE ARRAY OF POINTERS TO BE FILLED BY
        int i,j;
        char buf[80];   // command line
        pid_t pid;      // process ids
        
	while(strcmp(fgets(buf, 80, stdin), "exit\n")!=0)  // USER COMMAND
        {
                j=makeargv(buf,"|",&argp); // J = NUMBER OF TOKENS

                for (i=0;i<j;i++)
		{
                        printf("%s\n",argp[i]);
		}
        	pid=fork();
                switch (pid)
                {
                        case -1:
                                err_sys("fork failed");
                                break;
                        case 0: // child
                                execvp(argp[0],argp); //execute the command
				write (1,"exec fail\n", 10); //if execvp fails then print this message
                                exit(1);
                        default: // parent
                                write(1,"\nPrompt>",8);
				printf("%s process id %d\n",argp[0], pid);
                                break;
                }

        }

        printf(" make argv test exited\n"); //successfully exit
}

Open in new window


output:
bronco:~> ./a.out
ls -l | more
ls -l
 more


Prompt>ls -l  process id 13813
exec fail

so at first i've already output the command (separated by pipes) and each command is store in argp(i) so what i need to do next is to fork every command (in order to have a new child process for every command) i'm not sure is it correct to place before the switch pid but i think should be because right after calling the fork we are actually checking whether it is child or not if yes then we've to print the entire argument and then we print the process id at the parent?
but the thing coming out is a little weird... hmm so this>> Prompt>ls -l  process id 13813
is actually the parent id is it?
how can i do so that the Prompt will output right after i hit ./a.out then the user input command line and not input the command line first then only output the prompt (i know this shows that it's the parent) is there any possibility?? or should i just delete the prompt line (because is nothing)???
i hope you don't get confused what i'm asking... hahaha because i'm getting myself confused=P
0
 
Infinity08Commented:
>> hahaha because i'm getting myself confused=P

I can sense that :) So, let's take it a bit more slowly.


I notice that you used the same code as earlier - ie. the code that was causing you problems.

I recommend that you try writing it from scratch with the new knowledge you gained about using fork and exec. It'll work a lot better ;)


Another advice is to split your task up in sub-tasks, and work on each separately. For example :

1) first write some code that gets input from the user in a loop, and displays the input to the user (without doing anything with it).

2) as soon as that works, split up that input into commands, and display the separate commands to the user. Make sure there is no whitespace before and after the commands any more (that includes newline characters).

3) as soon as that works, try splitting up each of the commands into the executable and its arguments, and show them separately to the user (again making sure there's no whitespace).

4) as soon as that works, you can fork off a child for each of the commands, and print the child's process id in the parent.

5) as soon as that works, make the child execute the command (with its arguments).

Take it step by step like this, and don't move to the next step until you're sure that the code works for the current step.

When you encounter problems, just ask :)
0
 
crazy4sAuthor Commented:
now i was trying to do separate the commands by pipe but somehow i can only display the first command but not for those after pipes, is there any other ways to do the strtok automatically by not doing it one by one?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

int main()
{
	int i;
	char *command;
        char buf[80];   // command line
	while(strcmp(fgets(buf, 80, stdin), "exit\n")!=0)  // USER COMMAND
	{
		command = strtok(buf,"|\n");
		printf("%s\n",command);
	}
|

Open in new window


output:
ls -l | more
ls -l
0
 
crazy4sAuthor Commented:
hmm i was able to tokenize each of the command but i get a segmentation fault after printing the commands, and i think the problem was actually occur at the for loop, i'm not really sure what to put for the 2nd parameter
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

int main()
{
	int i, j;
	char *command;
        char buf[80];   // command line
	while(strcmp(fgets((char *)buf, 80, stdin), "exit\n")!=0)  // USER COMMAND
	{

		command = strtok(buf,"|\n");
		printf("%s\n", command);
		for ( i = 0; i < 80; i++) // NOT SURE WHAT TO PUT AT THE 2ND ONE
		{
			command = strtok(NULL, "|\n");
			printf("%s\n", command);
		}
		
	}
}

Open in new window


output:

cpfoo@csa04 as4$ gcc t.c
cpfoo@csa04 as4$ ./a.out
ls -l | more | more
ls -l
 more
 more
Segmentation Fault (core dumped)

and one more thing i don't really understand >> Make sure there is no whitespace before and after the commands any more
hmm where should this be???
0
 
crazy4sAuthor Commented:
the whitespace you meant here is it like in the command line we use to enter like this
ls -l | more << so there's a whitespace appear before the more so we need to eliminate that before and after the pipe, is this what you meant to be?
how can we eliminate those white space only for those that are before and after the pipe?
0
 
Infinity08Commented:
Sorry for the delay ...

>>             for ( i = 0; i < 80; i++) // NOT SURE WHAT TO PUT AT THE 2ND ONE

strtok will return NULL as soon as the last token has been read :

        http://www.cplusplus.com/reference/clibrary/cstring/strtok/

so you need to continue this loop until strtok returns NULL, not for a fixed 80 times.


>> ls -l | more << so there's a whitespace appear before the more so we need to eliminate that before and after the pipe, is this what you meant to be?

That is indeed what I meant.


>> how can we eliminate those white space only for those that are before and after the pipe?

When you split up the command into arguments, make sure to use whitespace (spaces, newlines, tabs, etc.) as delimiter for strtok. strtok will treat sequential delimiter characters as one single delimiter.
0
 
crazy4sAuthor Commented:
so did you meant to be something like this
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

int main()
{
	int i, j;
	char *command;
        char buf[80];   // command line
	while(strcmp(fgets((char *)buf, 80, stdin), "exit\n")!=0)  // USER COMMAND
	{

		command = strtok(buf,"| \t\n");
		while(command != NULL)
		{
			printf("%s\n",command);
			command = strtok(NULL,"| \t\n");
		}
		
	}
	return 0;
}

Open in new window


output :

bronco:~> ./a.out
ls -l | more than i want | that is
ls
-l
more
than
i
want
that
is

so this is doing what you want for step 2??? but do i need to include | as the delimiters too?
and about step 3 >>try splitting up each of the commands into the executable and its arguments???
how do split the commands again where there're already in token form, is this something to do with execvp???
0
 
Infinity08Commented:
It is somewhat what I want, but you still need two levels of strtoks :

The first splits up the line in commands by using | as a delimiter.
The second splits up each command by using whitespace as a delimiter.
0
 
Infinity08Commented:
>> It is somewhat what I want

typo : It is somewhat what I meant ;)
0
 
crazy4sAuthor Commented:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

int main()
{
	int i, j;
	char *command;
        char buf[80];   // command line
	while(strcmp(fgets((char *)buf, 80, stdin), "exit\n")!=0)  // USER COMMAND
	{

		command = strtok(buf,"|");
		printf("separate by |: \n");
		while(command != NULL)
		{
			printf("%s\n",command);
			command = strtok(NULL,"|");
		}
		command = strtok(buf," \t\n");
		printf("separate by space: \n");
		while(command != NULL)
		{
			printf("%s\n",command);
			command = strtok(NULL," \t\n");
		}	
	}
	return 0;
}

Open in new window


do you meant like this... btw what can i do so that when they do the 2nd time strtok for all the lines because it tends to appear only for the first line?

bronco:~> gcc t.c
bronco:~> ./a.out
ls -l | more than that | or lesser
separate by |:
ls -l
 more than that
 or lesser

separate by space:
ls
-l
0
 
Infinity08Commented:
The line :

>> printf("%s\n",command);

indicates the location where you have a command.

That is the location where you want to split up the command in arguments.
0
 
Infinity08Commented:
>> The line :

(the first line obviously)
0
 
crazy4sAuthor Commented:
hmm i don't quite get what you meant...
let me get this clear first.... so first you want me to output the command that's separated by | and then secondly you want me to further split the commands by space, is this what you meant?
hmm output should be smt like this????
ls -l | more than that | or lesser
separate by |:
ls -l
 more than that
 or lesser

separate by space:
ls
-l
more
than
that
or
lesser

	while(strcmp(fgets((char *)buf, 80, stdin), "exit\n")!=0)  // USER COMMAND
	{

		command = strtok(buf,"|");
		printf("separate by |: \n");
		while(command != NULL)
		{
			printf("%s\n",command);
                        // DO YOU MEANT TO PUT THE STRTOK FOR SPACE HERE??
			command = strtok(NULL,"|");
		}

	}

Open in new window

0
 
Infinity08Commented:
>> so first you want me to output the command that's separated by | and then secondly you want me to further split the commands by space, is this what you meant?

Yes. Do you understand why that needs to be done ?

Don't just blindly follow my instructions. Understand them first ;)


>>                         // DO YOU MEANT TO PUT THE STRTOK FOR SPACE HERE??

Not exactly. strtok is not re-entrant, so you cannot run multiple strtok loops at once.

What you can do however, is store the separate commands in an array, and when you have placed all commands in the array, you can iterate over it, and for each command use strtok to split it up in arguments using whitespace as a delimiter.
0
 
crazy4sAuthor Commented:
yes i understand but i'm just confused when you said to spilt the commands after the first printf...so that's why i want to double confirm....
btw i tried to put into array for the first strtok but i got an warning msg >> t.c:22: warning: assignment makes integer from pointer without a cast

the codes is it something like this...
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

int main()
{
	int i = 0;
	int j;
	char *command;
        char buf[80];   // command line
	char temp [80];
	while(strcmp(fgets((char *)buf, 80, stdin), "exit\n")!=0)  // USER COMMAND
	{

		command = strtok(buf,"|");
		printf("separate by |: \n");
		while(command != NULL)
		{
			printf("%s\n",command);
			temp [i] = &command;
			command = strtok(NULL,"|");
			i++;
		}
		while(fgets((char *)temp, 80, stdin)!=NULL) 
		{
			command = strtok(temp," \t\n");
			printf("separate by space: \n");
			for(j = 0; j < i; j++)
			{
				printf("%s\n",command);
				command = strtok(NULL," \t\n");

			}
		}

	}
	return 0;
}

Open in new window


0
 
Infinity08Commented:
>> yes i understand but i'm just confused when you said to spilt the commands after the first printf...

Ok. I'm sorry for that ;) I can see how my statement caused confusion, because I didn't put much care in its wording ...



>>                   temp [ i ] = &command;

temp is an array of char.

You probably want to make it an array of char* instead :

        char* temp[80] = { 0 };

Also, command is already a char*, so don't take the address of it :

        temp[ i ] = command;


Then :

>>             while(fgets((char *)temp, 80, stdin)!=NULL)

since temp is an array of char*, you just need to iterate over it, and use strtok for each of the char*'s in the array.
0
 
crazy4sAuthor Commented:
is ok:)
>>since temp is an array of char*, you just need to iterate over it, and use strtok for each of the char*'s in the array.
so do you meant what i'm doing is correct, i just need to repeat what i did strtok for the first time but i got an warning msg again:(
t.c:28: warning: passing argument 1 of 'strtok' from incompatible pointer type
>>                   command = strtok(temp," \t\n");

while(fgets((char *)temp, 80, stdin)!=NULL) 
		{
			command = strtok(temp," \t\n");
			printf("separate by space: \n");
			for(j = 0; j < i; j++)
			{
				printf("%s\n",command);
				command = strtok(NULL," \t\n");

			}
		}

Open in new window



0
 
crazy4sAuthor Commented:
hmm i solved the warning msg but it doesn't print out anything for second while loop
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

int main()
{
	int i = 0;
	int j;
	char *command;
        char buf[80];   // command line
        char* temp[80] = { 0 };
	while(strcmp(fgets((char *)buf, 80, stdin), "exit\n")!=0)  // USER COMMAND
	{

		command = strtok(buf,"|");
		printf("separate by |: \n");
		while(command != NULL)
		{
			printf("%s\n",command);
			temp [i] = command;
			command = strtok(NULL,"|");
			i++;
		}
		while(fgets((char *)temp, 80, stdin)!=NULL) 
		{
			command = strtok((char *)temp," \t\n");
			printf("separate by space: \n");
			for(j = 0; j < i; j++)
			{
				printf("%s\n",command);
				command = strtok(NULL," \t\n");

			}
		}

	}
	return 0;
}

Open in new window


output:

ls -l | more than that | or lesser
separate by |:
ls -l
 more than that
 or lesser
0
 
Infinity08Commented:
Why are you using fgets ?

fgets is used to read data from standard input (ie. have the user enter a string).
0
 
crazy4sAuthor Commented:
yeah you're right.
but what should i do to strtok the array?
can i do just like this, remove the fgets line??? but i know is wrong because it gives me a segmentation fault...
ls -l | more than that | or lesser
separate by |:
ls -l
 more than that
 or lesser

separate by space:
???????????
Segmentation fault

>>
            command1 = strtok((char *)temp," \t\n");
            printf("separate by space: \n");
            for(j = 0; j < i; j++)
            {
                  printf("%s\n",command1);
                  command1 = strtok(NULL," \t\n");

            }
0
 
Infinity08Commented:
>> but what should i do to strtok the array?

You don't strtok the array.

You iterate over each item in the array, and for each of them (which has the type char*), you can use strtok to tokenize it.
0
 
crazy4sAuthor Commented:
hmm i tried using like this but how can i do so that i can go numerous time for the 2nd strtok
            printf("separate by space: \n");
            for(j = 0; j < i; j++)
            {
                  command1 = strtok((char *)temp[j]," \t\n");
                  printf("%s\n",command1);

                  command1 = strtok(NULL," \t\n");
                  printf("%s\n",command1);

            }
currently the output is :

ls -l | more than that | or lesser
separate by |:
ls -l
 more than that
 or lesser

separate by space:
ls
-l
more
than  << that is missing because strtok only runs once after the first one
or
lesser
0
 
Infinity08Commented:
That looks better.

>> hmm i tried using like this but how can i do so that i can go numerous time for the 2nd strtok

Put it in a loop - just like you did for the command.

Btw, instead of using command1, why not use a more descriptive variable name, like argument ?
0
 
crazy4sAuthor Commented:
i tried to put in a while loop but i got a segmentation fault
ls -l | more than that | or lesser
separate by |:
ls -l
 more than that
 or lesser

separate by space:
ls
-l
Segmentation fault

		
printf("separate by space: \n");
	for(j = 0; j < i; j++)
	{
			argument = strtok((char *)temp[j]," \t\n");
			printf("%s\n",argument);
			while (argument != NULL)
			{

				argument = strtok(NULL," \t\n");
				printf("%s\n",argument);
			}

	}

Open in new window

0
 
Infinity08Commented:
Inside that while loop, the printf is supposed to come before the strtok.

Because you want to print the current token, not the newly returned that might be NULL.
0
 
crazy4sAuthor Commented:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

int main()
{
	int i = 0;
	int j;
	char *command;
	char *argument;
        char buf[80];   // command line
        char* temp[80] = { 0 };
	while(strcmp(fgets((char *)buf, 80, stdin), "exit\n")!=0)  // USER COMMAND
	{

		command = strtok(buf,"|");
		printf("separate by |: \n");
		while(command != NULL)
		{
			printf("%s\n",command);
			temp [i] = command;
			command = strtok(NULL,"|");
			i++;
		}

		printf("separate by space: \n");
		for(j = 0; j < i; j++)
		{
			argument = strtok((char *)temp[j]," \t\n");

			while (argument != NULL)
			{
				printf("%s\n",argument);
				argument = strtok(NULL," \t\n");
			}

		}
		

	}
	return 0;
}

Open in new window


output
ls -l | more than that | or lesser
separate by |:
ls -l
 more than that
 or lesser

separate by space:
ls
-l
more
than
that
or
lesser

arhh i missed that mistakes again...ok now i've successfully separate all the arguments... so what should i do next is it to fork the command... but i need to fork (ls -l) , (more than that), (or lesser) separately right? how do i so that i make sure these commands and it's argument are together?
0
 
Infinity08Commented:
So, now, you have split the input up in commands, and you have split each command up into its arguments.

You can now indeed fork off a child process for each of the commands. Don't do the exec just yet - just the forking (and show the process id together with the command).
0
 
crazy4sAuthor Commented:
i know in each array of the command we have those arguments in it hmm but how do i fork those arguments in the array together like ls -l??? i'm abit blur here...
0
 
Infinity08Commented:
>>  i know in each array of the command we have those arguments in it hmm but how do i fork those arguments in the array together like ls -l??? i'm abit blur here...

You don't fork arguments. Remember that forking creates a new process ? That's all it does. The arguments are not used for it. That's for later, when we will add exec.

Have a read back through this thread for the discussion we had on how forking works.
0
 
crazy4sAuthor Commented:
hmm yes i know when i do fork it creates a new process but how is it related to those commands??
do i just do the normal fork after all the strtok stuffs?? can you give some example so is easier for me to understand?
0
 
Infinity08Commented:
>> hmm yes i know when i do fork it creates a new process but how is it related to those commands??

For every command, we need to create a new child process.

So, we start by doing just that : create a new child process for every command. Don't try actually running (exec-ing) the command just yet - that's for later. For now, just create a new child process, and print the process id for it, (together with the command) to the screen to show that it works.
0
 
crazy4sAuthor Commented:
so do i just do the normal fork like what you call me to try earlier... hmm like that?
but since we have let's say more than one command does it meant that i've to fork numerous times too??
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

int main()
{
	int i = 0;
	int j;
	char *command;
	char *argument;
        char buf[80];   // command line
        char* temp[80] = { 0 };
	while(strcmp(fgets((char *)buf, 80, stdin), "exit\n")!=0)  // USER COMMAND
	{

		command = strtok(buf,"|");
		printf("separate by |: \n");
		while(command != NULL)
		{
			printf("%s\n",command);
			temp [i] = command;
			command = strtok(NULL,"|");
			i++;
		}

		printf("separate by space: \n");
		for(j = 0; j < i; j++)
		{
			argument = strtok((char *)temp[j]," \t\n");

			while (argument != NULL)
			{
				printf("%s\n",argument);
				argument = strtok(NULL," \t\n");
			}

		}
		

	}

	pid_t pid = fork();  //i'm not really sure how should i fork a command???
        switch (pid)
        {
        	case -1:
			printf("fork failed");
			break;
        	case 0: // child
			exit(0);
        	default: // parent
			printf("%s process id %d\n", command, pid);
			break;
        }
	return 0;
}

Open in new window

0
 
crazy4sAuthor Commented:
as earlier you want me to try to fork 2 child process, that's from one parent which is the original shell right? but when comes to commands i don't really know how should i fork every command so if we have to 2 commands so we'll have 2 new child process (ls -l | more)??
0
 
Infinity08Commented:
As I said before : don't just follow my instructions blindly. Try to understand them first.

You have been given an assignment. The goal of this thread is to help you complete that assignment.

Now, if you look at the assignment, what is it that needs to happen ? And how would you do that ? How do the steps I mentioned earlier fit into that goal ?
0
 
crazy4sAuthor Commented:
yes i was trying my best to understand but i just can't get it how it works to fork the commands, can you explain in more details or maybe like diagrams or examples will helps me to understand better because i'm quite weak in imagination?? hope you don't mind:)
0
 
Infinity08Commented:
You don't "fork commands". That doesn't make sense.

What you do is : for every command, you fork a child process. It doesn't mean that the child process depends on what the command is - it just means that you want as many child processes as there are commands. Nothing more, nothing less.
0
 
crazy4sAuthor Commented:
ahh so in this means i don't fork the commands but i fork the no of commands given???
is that right if i do it like this>>>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

int main()
{
	int i = 0;
	int j;
	char *command;
	char *argument;
        char buf[80];   // command line
        char* temp[80] = { 0 };
	while(strcmp(fgets((char *)buf, 80, stdin), "exit\n")!=0)  // USER COMMAND
	{

		command = strtok(buf,"|");
		printf("separate by |: \n");
		while(command != NULL)
		{
			printf("%s\n",command);
			temp [i] = command;
			command = strtok(NULL,"|");
			i++;
		}

		printf("separate by space: \n");
		for(j = 0; j < i; j++)
		{
			argument = strtok((char *)temp[j]," \t\n");

			while (argument != NULL)
			{
				printf("%s\n",argument);
				argument = strtok(NULL," \t\n");
			}

		}
		

	}

	pid_t pid;
	for (k = 0; k < i; k++)
	{
		pid = fork();
		if (pid == 0)
		{
			exit(0);
		}
		else if (pid < 0) 
		{
			printf("fork failed");
		}
		else
		{
			printf("%s process id %d\n", command, pid);
		}
	}
        
	return 0;
}

Open in new window

0
 
Infinity08Commented:
You're starting to get the idea.

Now, there are still a few problems. For example :

(a) you have an array of commands, but you don't use it when printing the process id of the forked process.

(b) you already have a loop that iterates over the array of commands. You probably want to place the fork code in that existing loop, rather than create a new one. That way you'll be able to use the tokenized arguments in the child process (in the next step).
0
 
crazy4sAuthor Commented:
i tried editing my code again and again and finally i get this result...hmm but the command is not displaying in full they just display the first one??
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

int main()
{
	int i = 0;
	int j, k;
	char *command;
	char *argument;
        char buf[80];   // command line
        char* temp[80] = { 0 };
	pid_t pid;
	while(strcmp(fgets((char *)buf, 80, stdin), "exit\n")!=0)  // USER COMMAND
	{

		command = strtok(buf,"|");
		printf("separate by |: \n");
		while(command != NULL)
		{
			printf("%s\n",command);
			temp [i] = command;
			command = strtok(NULL,"|");
			i++;
		}

		printf("separate by space: \n");
		for(j = 0; j < i; j++)
		{
			argument = strtok((char *)temp[j]," \t\n");

			while (argument != NULL)
			{
				printf("%s\n",argument);
				argument = strtok(NULL," \t\n");
			}

		}
		
	for (k = 0; k < i; k++)
	{
		pid = fork();
		if (pid == 0)
		{
			exit(0);
		}
		else if (pid < 0) 
		{
			printf("fork failed");
			exit(1);
		}
		else
		{
			printf("%s process id %d\n", temp[k], pid);
		}
	}
        }
	return 0;
}

Open in new window



ls -l | more
separate by |:
ls -l
 more

separate by space:
ls
-l
more
ls process id 22346
 more process id 22347
0
 
Infinity08Commented:
>> hmm but the command is not displaying in full they just display the first one??

See (a) in my previous post
0
 
Infinity08Commented:
Sorry - that's not right. I meant (b).

The "problem" you describe is because you've already used strtok on the command, so you've already split it up in tokens.

If you do the fork in the already existing loop, (before splitting up the command in arguments), you'll have better luck.
0
 
crazy4sAuthor Commented:
is getting better but i don't understand why the 2nd command tends to have a next line after it??
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

int main()
{
	int i = 0;
	int j, k;
	char *command;
	char *argument;
        char buf[80];   // command line
        char* temp[80] = { 0 };
	pid_t pid;
	while(strcmp(fgets((char *)buf, 80, stdin), "exit\n")!=0)  // USER COMMAND
	{

		command = strtok(buf,"|");
		printf("separate by |: \n");
		while(command != NULL)
		{
			printf("%s\n",command);
			temp [i] = command;
			command = strtok(NULL,"|");
			i++;
		}

		
		for (k = 0; k < i; k++)
		{
			pid = fork();
			if (pid == 0)
			{
				exit(0);
			}
			else if (pid < 0) 
			{
				printf("fork failed");
				exit(1);
			}
			else
			{
				printf("%s process id %d\n", temp[k], pid);
			}
		}

		printf("separate by space: \n");
		for(j = 0; j < i; j++)
		{
			argument = strtok((char *)temp[j]," \t\n");

			while (argument != NULL)
			{
				printf("%s\n",argument);
				argument = strtok(NULL," \t\n");
			}

		}

        }
	return 0;
}

Open in new window

ls -l | more
separate by |:
ls -l
 more

ls -l  process id 22412
 more
 process id 22413
separate by space:
ls
-l
more
0
 
crazy4sAuthor Commented:
and is there any ways to eliminate the space before "more" or just leave it?
0
 
crazy4sAuthor Commented:
cont the previous post .. because we're going to do the execvp later that will print out the commands and the process id
0
 
Infinity08Commented:
>> is getting better but i don't understand why the 2nd command tends to have a next line after it??

>> and is there any ways to eliminate the space before "more" or just leave it?

That is the reason I mentioned in step 2 to remove whitespace before and after the commands.

Don't do that with strtok though - take care of that by other means.

For leading whitespace, you can just increment the command pointer to point past it, and for trailing whitespace, you can set them to '\0'
0
 
Infinity08Commented:
Btw, you still have the fork in its own loop.

Why not include the fork in the already existing loop (the loop where you split up the commands into arguments) ?
0
 
crazy4sAuthor Commented:
you meant like this??
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

int main()
{
	int i = 0;
	int j, k;
	char *command;
	char *argument;
        char buf[80];   // command line
        char* temp[80] = { 0 };
	pid_t pid;
	while(strcmp(fgets((char *)buf, 80, stdin), "exit\n")!=0)  // USER COMMAND
	{

		command = strtok(buf,"|");
		printf("separate by |: \n");
		while(command != NULL)
		{
			printf("%s\n",command);
			temp [i] = command;
			command = strtok(NULL,"|");
			i++;
		}


		printf("separate by space: \n");
		for(j = 0; j < i; j++)
		{
			pid = fork();
			if (pid == 0)
			{
				exit(0);
			}
			else if (pid < 0) 
			{
				printf("fork failed");
				exit(1);
			}
			else
			{
				printf("%s process id %d\n", temp[j], pid);
			}
			argument = strtok((char *)temp[j]," \t\n");

			while (argument != NULL)
			{
				printf("%s\n",argument);
				argument = strtok(NULL," \t\n");
			}

		}

        }
	return 0;
}

Open in new window


because the output is kind of weird that's why i use another loop...

ls -l | more
separate by |:
ls -l
 more

separate by space:
ls -l  process id 22523
ls
-l
 more
 process id 22524
more

>>For leading whitespace, you can just increment the command pointer to point past it, and for trailing whitespace, you can set them to '\0'
i don't really get what this means, how do i increment the command pointer and for after replace with null?
0
 
crazy4sAuthor Commented:
>>Don't do that with strtok though - take care of that by other means.
hmm you meant which one the first(command) or the second one(arguments)??
0
 
Infinity08Commented:
>> because the output is kind of weird that's why i use another loop...

The output is only weird because there is still whitespace at the beginning and end of the commands.


>> >>Don't do that with strtok though - take care of that by other means.
>> hmm you meant which one the first(command) or the second one(arguments)??

We're talking about the whitespace in front and after the commands, not the arguments.



>> >>For leading whitespace, you can just increment the command pointer to point past it, and for trailing whitespace, you can set them to '\0'
>> i don't really get what this means, how do i increment the command pointer and for after replace with null?

If you have a pointer to the first character in a string, then incrementing that pointer will make it point to the second character in the string. Play around a bit with code like this in a separate project, and try to understand why you get that output :
char str[] = "Example string";

char* p = str;
ptintf("%s\n", p);

++p;
ptintf("%s\n", p);

p[6] = '\0';
ptintf("%s\n", p);

Open in new window

0
 
crazy4sAuthor Commented:
hmm i tried to play around with it, and try to add ++command in the command loop but i got a segmentation fault after it...
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

int main()
{
	int i = 0;
	int j, k;
	char *command;
	char *argument;
        char buf[80];   // command line
        char* temp[80] = { 0 };
	pid_t pid;
	while(strcmp(fgets((char *)buf, 80, stdin), "exit\n")!=0)  // USER COMMAND
	{

		command = strtok(buf,"|");
		printf("separate by |: \n");
		while(command != NULL)
		{
			printf("%s\n",command);
			temp [i] = command;
			command = strtok(NULL,"|");
			i++;
			++command;
		}


		printf("separate by space: \n");
		for(j = 0; j < i; j++)
		{
			pid = fork();
			if (pid == 0)
			{
				exit(0);
			}
			else if (pid < 0) 
			{
				printf("fork failed");
				exit(1);
			}
			else
			{
				printf("%s process id %d\n", temp[j], pid);
			}
			argument = strtok((char *)temp[j]," \t\n");

			while (argument != NULL)
			{
				printf("%s\n",argument);
				argument = strtok(NULL," \t\n");
			}

		}

        }
	return 0;
}

Open in new window


if i put before this line >> command = strtok(NULL,"|"); // nothing difference still have the white space
but if put after this line, yes it remove the white space but i got a segmentation fault.

ls -l | more
separate by |:
ls -l
more

Segmentation fault

0
 
crazy4sAuthor Commented:
here i added in the null at the end of each command but well i know the segmentation will still be there~
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

int main()
{
	int i = 0;
	int j, k;
	char *command;
	char *argument;
        char buf[80];   // command line
        char* temp[80] = { 0 };
	pid_t pid;
	while(strcmp(fgets((char *)buf, 80, stdin), "exit\n")!=0)  // USER COMMAND
	{

		command = strtok(buf,"|");
		printf("separate by |: \n");
		while(command != NULL)
		{
			command[strlen(command)-1] = '\0';
			printf("%s\n",command);
			temp [i] = command;
			command = strtok(NULL,"|");
			++command;
			i++;
		}

		printf("separate by space: \n");
		for(j = 0; j < i; j++)
		{
			pid = fork();
			if (pid == 0)
			{
				exit(0);
			}
			else if (pid < 0) 
			{
				printf("fork failed");
				exit(1);
			}
			else
			{
				printf("%s process id %d\n", temp[j], pid);
			}

			argument = strtok((char *)temp[j]," \t\n");

			while (argument != NULL)
			{
				printf("%s\n",argument);
				argument = strtok(NULL," \t\n");
			}

		}

        }
	return 0;
}

Open in new window



ls -l | more than that | or lesser
separate by |:
ls -l
more than that
or lesser
Segmentation fault
0
 
Infinity08Commented:
The segmentation fault is because you increment a NULL pointer.

Don't do that. Only increment a valid (non-NULL) pointer.

Also : don't just increment it blindly. Only increment it if there's actually a whitespace character in the beginning. And note that there might be more than one whitespace character, so you might have to increment more than once.
0
 
crazy4sAuthor Commented:
Hmm but I increment the pointer  after the strtok so right after the pipe should be a space right the null pointer that I put is at the end of each command??? Hmm maybe I mistaken smt...
ahhh then can I put a strcmp if given the char of the command is a space then we'll increment it??? Will that works?? This means that I'll compare till I get a non-space char????
0
 
Infinity08Commented:
>> Hmm but I increment the pointer  after the strtok

What if strtok returned NULL ?


>> so right after the pipe should be a space right

What if the user didn't type a space there ? What if he typed two spaces ? What if he typed a tab ?


>> ahhh then can I put a strcmp if given the char of the command is a space then we'll increment it??? Will that works?? This means that I'll compare till I get a non-space char????

Have a look at this function :

        http://www.cplusplus.com/reference/clibrary/cstring/strspn/
0
 
crazy4sAuthor Commented:
So do you intend to want me to compare the commands and the arguments...hmm but I don't really get it because the strspn only if they have the same char but how do they space in between those arguments???
sorry for my slowness...
0
 
Infinity08Commented:
Just think about it carefully. If you have a string that has whitespace at the beginning, you first need to know how many characters of whitespace there are at the beginning (you can use strspn for that), and then you skip that many characters, by incrementing the pointer.

Does that make sense ?
0
 
Infinity08Commented:
If it doesn't, please play around a bit with the sample code I provided in http:#35207322, and use strings that have whitespace at the start. Then see what you can do with strspn, and how you can make it display the string without the initial whitespace.
0
 
crazy4sAuthor Commented:
hmm i was trying to play around with this>>
char str[] = " Example string";

char str2[] = "Example string";
int i;
  i = strspn (str, str2);
  printf ("The length of initial number is %d.\n",i);

the output for i was 15, hmm i would like to ask one thing does this 15 includes the null byte at the end of the string, if yes that means is not calculating the space at the beginning?
and in my case which one do i use to compare with the command >> 
strspn (command, "not sure which one to compare");
0
 
crazy4sAuthor Commented:
is that possible to do like that>>

char space[]=" ";
while(command != NULL)
            {
                  command[strlen(command)-1] = '\0';
                  printf("%s\n",command);
                  temp (i)= command;
                  command = strtok(NULL,"|");
                  nos = strspn (command, space); // compare the command with space
                                                                              // and returns how many spaces before the 1st non-  
                                                                              // space character
                  for (s = 0; s < nos; s++)
                        ++command;
                  i++;
            }

output
ls -l |    more
separate by |:
ls -l
more

Segmentation fault

but it seems not working because i got a segmentation fault again this seems that the increment is a null pointer again... hmmm what can i do so that after the pipe is not a null??
0
 
crazy4sAuthor Commented:
this is the latest code that can removes any spaces or tabs before the command but i still can't solve the null pointer that the strtok returned at the end of the command line where no more commands are found?

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

int main()
{
	int i = 0;
	int j, k;
	int nos;
	int s;
	char *command;
	char *argument;	
        char buf[80];   // command line
        char* temp[80] = {0};	// an array to store the commands
	char space[] = " \t";	// remove space or tab before the command, if any

	pid_t pid;
	while(strcmp(fgets((char *)buf, 80, stdin), "exit\n")!=0)  // user command line
	{

		command = strtok(buf,"|");		// tokenize the command line by |
		printf("separate by |: \n");
		while(command != NULL)
		{
			//command[strlen(command)-1] = '\0';
			printf("%s\n",command);
			temp [i] = command;		// store each commands into the array
			command = strtok(NULL,"|");
			nos = strspn (command, space); 	// return the number of spaces or tab before the command
			for (s = 0; s < nos; s++)
				++command;		// increment the pointer of command to remove the spaces or tabs, if any

			i++;				// increment array
		}


		printf("separate by space: \n");
		for(j = 0; j < i; j++)
		{
			pid = fork();
			if (pid == 0)			// child
			{
				exit(0);
			}
			else if (pid < 0) 		// error
			{
				printf("fork failed");
				exit(1);
			}
			else				// parent
			{
				printf("%s process id %d\n", temp[j], pid);	// print the command and the process id 
			}

			argument = strtok((char *)temp[j]," \t\n");	// tokenize the command into arguments

			while (argument != NULL)
			{
				printf("%s\n",argument);
				argument = strtok(NULL," \t\n");
			}

		}

        }
	return 0;
}

Open in new window



ls -l |         more
separate by |:
ls -l
more

Segmentation fault
0
 
crazy4sAuthor Commented:
i'm not sure whether i can do smt like this >> nos = strspn (command[strlen(command)-1], space);       
so this will automatically eliminate the null terminated byte, but i was just making a guess... but is not working because there's a warning msg >> passing argument 1 of 'strspn' makes pointer from integer without a cast....
0
 
Infinity08Commented:
The segmentation fault is because strtok returns NULL when there are no more tokens, but you still try to use that NULL pointer.

Removing the whitespace has to happen for each token, so it has to happen at the location where you print the current token (probably before you print it), not after you get the next token.
0
 
crazy4sAuthor Commented:
yes i know the strtok will return a null pointer at the end of the command line where no more commands are found...
so are you saying that the prob actually is in this line >>command = strtok(NULL,"|"); // i shouldn't put a null there??? but if i don't put null what should i put??? hmmm
0
 
crazy4sAuthor Commented:
hmm i shifted the remove spaces to before printf and it compile with no segmentation fault is just that the same prob appear is when printing the id for the 2nd command it'll print it next line:

output:
ls -l | more
separate by |:
ls -l
more

separate by space:
ls -l  process id 25496
ls
-l
more
 process id 25497
more
/*
 * Chai Phei Foo
 * CS 2240
 * Assignment 4
 * March 24 2011
 * Purpose: To output each 'command' (separated by pipes) with a 
 *	   separate process along with its process id
 * Usage: $ gcc as4.c
 *        $ ./a.out
 *        ls -l | more (any commands that the user which to enter)
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

int main()
{
	int i = 0;
	int j, k;
	int nos;
	int s;
	char *command;
	char *argument;	
        char buf[80];   // command line
        char* temp[80] = {0};	// an array to store the commands
	char space[] = " \t";	// remove space or tab before the command, if any

	pid_t pid;
	while(strcmp(fgets((char *)buf, 80, stdin), "exit\n")!=0)  // user command line
	{
		//command[strlen(command)-1];
		command = strtok(buf,"|");		// tokenize the command line by |
		printf("separate by |: \n");
		while(command != NULL)
		{
			nos = strspn (command, space); 	// return the number of spaces or tab before the command
			for (s = 0; s < nos; s++)
				++command;		// increment the pointer of command to remove the spaces or tabs, if any
			printf("%s\n",command);
			temp [i] = command;		// store each commands into the array
			command = strtok(NULL,"|");
			i++;				// increment array
		}


		printf("separate by space: \n");
		for(j = 0; j < i; j++)
		{
			pid = fork();
			if (pid == 0)			// child
			{
				exit(0);
			}
			else if (pid < 0) 		// error
			{
				printf("fork failed");
				exit(1);
			}
			else				// parent
			{
				printf("%s process id %d\n", temp[j], pid);	// print the command and the process id 
			}

			argument = strtok((char *)temp[j]," \t\n");	// tokenize the command into arguments

			while (argument != NULL)
			{
				printf("%s\n",argument);
				argument = strtok(NULL," \t\n");
			}

		}

        }
	return 0;
}

Open in new window

0
 
crazy4sAuthor Commented:
so i think the problem is still revolving around the null pointer at the end of the command line that causes the last argument to printed like this, is it?
0
 
Infinity08Commented:
>> hmm i shifted the remove spaces to before printf and it compile with no segmentation fault

That was what I meant indeed ;)


>> is just that the same prob appear is when printing the id for the 2nd command it'll print it next line:

Because you have only removed the spaces and tabs at the beginning of the line. There could also be whitespace at the end of the line.
And spaces, and tabs aren't the only type of whitespace - there are also newlines etc.
0
 
Infinity08Commented:
>> at the beginning of the line.

typo : at the beginning of the command

and :

>> at the end of the line.

at the end of the command.
0
 
crazy4sAuthor Commented:
oh yeah i get what you meant, hmmm so i added this into it
		while(command != NULL)
		{
			nos = strspn (command, space); 	// return the number of spaces or tab before the command
			for (s = 0; s < nos; s++)
				++command;		// increment the pointer of command to remove the spaces or tabs, if any
			if (pos = strcspn (command, nl))// return the position of new line
				command[pos] = '\0';	// replace it with
			printf("%s\n",command);
			temp [i] = command;		// store each commands into the array
			command = strtok(NULL,"|");
			i++;				// increment array
		}

Open in new window


output

ls -l | more
separate by |:
ls -l
more
separate by space:
ls -l  process id 27244
ls
-l
more process id 27245
more

so what can i do for next?
0
 
crazy4sAuthor Commented:
i was trying to figure out to remove any extra spaces behind at the command but if i put a space into my char nl[] it automatically eliminates the -l when printing...what should i do?

	char nl[] = "\t\n"; // i only put tab and nl, if is found

		while(command != NULL)
		{
			nos = strspn (command, space); 	// return the number of spaces or tab before the command
			for (s = 0; s < nos; s++)
				++command;		// increment the pointer of command to remove the spaces or tabs, if any
			if (pos = strcspn (command, nl))// return the position of new line
				command[pos] = '\0';	// replace it with
			printf("%s\n",command);
			temp [i] = command;		// store each commands into the array
			command = strtok(NULL,"|");
			i++;				// increment array
		}

Open in new window


0
 
Infinity08Commented:
>>                   if (pos = strcspn (command, nl))// return the position of new line

That is only looking for newlines. What if there's other whitespace at the end ?

Note that in the more general case of whitespace, you can't use strcspn, because you only want to remove whitespace at the end.

That explains this :

>> but if i put a space into my char nl[] it automatically eliminates the -l when printing...what should i do?


So, instead of using strcspn, just look at the last character of the string and check if it's whitespace. If so, shorten the string, and check again.
0
 
crazy4sAuthor Commented:
hmm i tried to put smt like this but it doesn't work?? i know i missed smt out but just can't figure out what is it?
        int len;
	int no = 1;
	char * pos;
			nos = strspn (command, space); 	// return the number of spaces or tab before the command
			for (s = 0; s < nos; s++)
				++command;		// increment the pointer of command to remove the spaces or tabs, if any
			len = strlen(command);
			pos = command + len - no;	
			if (strcmp (pos, nl) == 0)	// return the position of new line
			{	
				no++;
				pos = command + len - no;
			}
				
			printf("%s\n",command);
			temp [i] = command;		// store each commands into the array
			command = strtok(NULL,"|");
			i++;

Open in new window

0
 
Infinity08Commented:
strcmp is for comparing strings.

You want to compare a single character.
0
 
crazy4sAuthor Commented:
so do you meant i have to use strrchr... but when i check on how to use this, i was a bit confuse and so i didn't use it, can you explain this? thanks.
0
 
Infinity08Commented:
You could simply compare the character without using a function :

        if (c == ' ') {  /* it's a space */  }

etc.
0
 
crazy4sAuthor Commented:
hmmm like this ....  but i got a warning msg for this line >> if (last == ' ')
t.c:50: warning: comparison between pointer and integer
not sure how can i solve this...
        int no = 1;
	int pos;
	char* last;
	char space[] = " \t";	// remove space or tab before the command, if any
	char nl[] = "\t\n"; //remove any new lines, if any

while(command != NULL)
		{
			nos = strspn (command, space); 	// return the number of spaces or tab before the command
			for (s = 0; s < nos; s++)
				++command;		// increment the pointer of command to remove the spaces or tabs, if any
			if (pos = strcspn (command, nl))// return the position of new line
				command[pos] = '\0';	// replace it with			
			len = strlen(command);
			last = command + len - no;	
			if (last == ' ')	// return the position of new line
			{	
				last = '\0';
				no++;
				last = command + len - no;
			}

			printf("%s\n",command);
			temp [i] = command;		// store each commands into the array
			command = strtok(NULL,"|");
			i++;				// increment array
		}

Open in new window

0
 
Infinity08Commented:
last is a char*, not a char.
0
 
crazy4sAuthor Commented:
hmm i added in char las; but there's no difference, how can i get the char that i'm pointing to?

                  nos = strspn (command, space);       // return the number of spaces or tab before the command
                  for (s = 0; s < nos; s++)
                        ++command;            // increment the pointer of command to remove the spaces or tabs, if any
                  if (pos = strcspn (command, nl))// return the position of new line
                        command[pos] = '\0';      // replace it with                  
                  len = strlen(command);
                  last = command + len - no;      
                  if (las == ' ')      // return the position of new line
                  {      
                        las = '\0';
                        no++;
                        last = command + len - no;
                  }
0
 
Infinity08Commented:
If you have a pointer, how do you get the object you're pointing to ?
0
 
crazy4sAuthor Commented:
hmm using command[ last position]???
0
 
Infinity08Commented:
You could use the [] operator with the index 0, yes, but more directly, you can simply dereference the pointer :
char str[] = "something";

char* ptr = str;

char c = *ptr;           /* <--- dereference the pointer to get the object it's pointing to (in this case a char) */

printf("%c\n", c);

Open in new window

0
 
Infinity08Commented:
Given that you seem to struggle with very basic things, it's probably a good idea to first get a good basis in C, before you try to tackle more complicated stuff, like your current assignment.

Have a read through these tutorials eg., and make sure you understand every little detail in them. Play around with some test code to get a good feeling for each of the subjects in the tutorial :

        http://www.cprogramming.com/tutorial.html#ctutorial
0
 
crazy4sAuthor Commented:
hmm i tried it but no difference they still prints out the space, is there still anything wrong with my code..
        char *command;
	char *argument;	
	char space[] = " \t";	// remove space or tab before the command, if any
	char nl[] = "\t\n"; //remove any new lines, if any
	char* last = command;
	char las = *last;

		while(command != NULL)
		{
			nos = strspn (command, space); 	// return the number of spaces or tab before the command
			for (s = 0; s < nos; s++)
				++command;		// increment the pointer of command to remove the spaces or tabs, if any
			if (pos = strcspn (command, nl))// return the position of new line
				command[pos] = '\0';	// replace it with			
			len = strlen(command);
			last = command + len - no;	
			if (las == ' ')	// return the position of new line
			{	
				las = '\0';
				no++;
				last = command + len - no;
			}

Open in new window

0
 
crazy4sAuthor Commented:
oh yeah i solve the problem!!! so what should i do next?
0
 
Infinity08Commented:
If you feel you don't need to go through the tutorials and learn some more of the basics (I really recommend you do), and if you feel that the result of the current step is acceptable, then you can move on to the next step :)
0
 
crazy4sAuthor Commented:
this is the result i got:
 A B C | D E F     | G H I      
separate by |:
A B C
D E F
G H I
Command and its process id:
A B C process id 19257
D E F process id 19258
G H I process id 19259

so what should i do next?
0
 
Infinity08Commented:
>> so what should i do next?

See my previous post ;)
0
 
crazy4sAuthor Commented:
>>make the child execute the command (with its arguments).
hmm do we use exec fun at the child?? can we print the pid at the child too?
0
 
Infinity08Commented:
>> hmm do we use exec fun at the child?? can we print the pid at the child too?

Do you remember our earlier discussion about how to use fork and exec ? Please read back through that if you have forgotten certain things.
0
 
crazy4sAuthor Commented:
i tried to put an execvp inside the for loop but id doesn't print out the command only the process id at the parent... did i use the execvp correctly???
for(j = 0; j < i; j++)			// fork each command
		{
			pid = fork();
			if (pid == 0)			// child
			{
				execvp(temp[j],temp);
				exit(0);
			}
			else if (pid < 0) 		// error
			{
				printf("fork failed");
				exit(1);
			}
			else				// parent
			{
				printf("process id %d\n", pid);	// print the command and the process id 
			}
			
			argument = strtok((char *)temp[j]," \t\n");	// tokenize the command into arguments

			while (argument != NULL)
			{
				printf("%s\n",argument);
				argument = strtok(NULL," \t\n");
			}


		}

Open in new window

0
 
Infinity08Commented:
Think about what you're trying to do here ... The arguments you're passing to execvp : what do they contain ? Is that what you want ?
0
 
crazy4sAuthor Commented:
hmm i was thinking why do we need the arguments as we already have the commands store in the temp array right, can't we straight away use the command?
0
 
Infinity08Commented:
These are things we already discussed back when we were talking about how to use exec. Each of the exec functions has very specific needs for its parameters.
0
 
crazy4sAuthor Commented:
hmm i got no idea what should i put into the execvp func, do i put the argument as the parameter of the execvp func?? execvp(argument,temp); //i'm just guessing around
can you lead me if this is wrong?
and btw the for loop for the strtok for argument is after the fork process, is that fine??
0
 
crazy4sAuthor Commented:
but somehow it prints the parent first... and the command is splitted into argument...is not printing together... is there any possibility to print the child first then the parent(for the process id)???

process id 19338
ls
-l
process id 19339
more
0
 
Infinity08Commented:
>> //i'm just guessing around

Don't guess.

Read the man page for execvp.


>> and btw the for loop for the strtok for argument is after the fork process, is that fine??

What do you think ?
0
 
crazy4sAuthor Commented:
well what i was thinking was the strtok for arguments should put before the fork because we're going to use execvp at the child to execute those arguments.... i read over the man execvp, and the first parameter should be the 1st argument in the command and for the 2nd parameter should be command (temp[0]) which contain the rest of the arguments but i'm not sure how should i put it??
some kind like when i split the command into arguments, i'll have ls and then -l, so what i want to do is to execvp (argument[which is ls], temp[0] (which is the command that stored in the array)... but i dunno how to put it in??
0
 
crazy4sAuthor Commented:
hmm one question... when we do the strtok for the arguments where will they store the arguments? will they store back in the same array as in temp(i)... before that we store commands in this temp(i) array and then we further tokenized each of the arguments in this command....
0
 
Infinity08Commented:
>> well what i was thinking was the strtok for arguments should put before the fork because we're going to use execvp at the child to execute those arguments....

What if you split the command in arguments in the child code ?
0
 
crazy4sAuthor Commented:
Hmm like how... do you meant to put the strtok argument inside here>> if (pid == 0) before doing execvp?? Can you explain in more detail?
0
 
crazy4sAuthor Commented:
i thought of using the 1st argument of the command as the first parameter and the array temp(i) that stored the command as the second parameter for execvp but it seems to be not working too..
can you help me to figure out where has gone wrong....

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

int main()
{
	int i = 0;
	int j;
	int nos;
	int no = 1;
	int pos, s;
	char *command;
	char *argument;	
        char buf[80];   	// command line
        char* temp[80]={0};	// an array to store the commands
	char* temp2[80] = {0};
	char space[] = " \t";	// remove space or tab before the command, if any
	char nl[] = "\t\n";	// remove any new lines, if any

	pid_t pid;
	while(strcmp(fgets((char *)buf, 80, stdin), "exit\n")!=0)  // user command line
	{
		command = strtok(buf,"|");		// tokenize the command line by |
		printf("separate by |: \n");
		while(command != NULL)
		{
			nos = strspn (command, space); 	// return the number of spaces or tab before the command
			for (s = 0; s < nos; s++)
				++command;		// increment the pointer of command to remove the spaces or tabs, if any
			if (pos = strcspn (command, nl))// find if there's any new line or tab after the command
				command[pos] = '\0';	// replace it with a null, if any			
			for (;;)				// make a loop
			{
				int n = strlen (command) - 1;	// last character position in command
				if (command[n] == ' ')		// if there's a space 
					command[n] = 0;		// makes the string shorter
				else 
					break;			// out of the loop, if any non-white space is found
			}			

			printf("%s\n",command);
			temp [i] = command;		// store each commands into the array
			temp2[i] = command;
			command = strtok(NULL,"|");
			i++;				// increment array
		}

		printf("Command and its process id: \n");
		int k = 0;
		for(j = 0; j < i; j++)			// fork each command
		{

			pid = fork();
			if (pid == 0)			// child
			{
				argument = strtok((char *)temp[j]," \t\n");	// get the first argument of the command
				execvp(argument,temp2[i]);
				write(1,"exec fail\n",10);      // print this msg if execvp fails
				exit(1);
				//while (argument != NULL)
				//{

					//argument = strtok(NULL," \t\n");
				//}

			}
			else if (pid < 0) 		// error
			{
				printf("fork failed");
				exit(1);
			}
			else				// parent
			{
				printf("process id %d\n", pid);	// print the command and the process id 
			}
		}

        }
	return 0;
}

Open in new window

outout:

ls -l | more
separate by |:
ls -l
more
Command and its process id:
process id 19832
more: No such file or directory   // not sure why this 2 lines appear???
more: No such file or directory
process id 19833
0
 
crazy4sAuthor Commented:
i tried to use another array to store the arguments but i got exec fail ... i know it won't work because the array argv have to reuse as many times as j... but i got no idea how to solve this:(
for(j = 0; j < i; j++)			// fork each command
		{
			char* argv[80];
			argument = strtok((char *)temp[j]," \t\n");	// tokenize the command into arguments
			while (argument != NULL)
			{
				argv[k] = argument;
				argument = strtok(NULL," \t\n");
				k++;
			}
			
			pid = fork();
			if (pid == 0)			// child
			{
				execvp(argv[0],argv);
				write(1,"exec fail\n",10);
				exit(1);
			}
			else if (pid < 0) 		// error
			{
				printf("fork failed");
				exit(1);
			}
			else				// parent
			{
				printf("process id %d\n", pid);	// print the command and the process id 
			}
			

Open in new window

0
 
Infinity08Commented:
>> do you meant to put the strtok argument inside here>> if (pid == 0) before doing execvp?? Can you explain in more detail?

That would help, wouldn't it ?
0
 
crazy4sAuthor Commented:
hmm but should i do the whole strtok like this? i was actually thinking that the 1st parameter of execvp needs the 1st argument so how to grab the 1st argument if i put like this, i was a bit confused here? can you explain this?

argument = strtok((char *)temp(j)," \t\n");      // get the first argument of the command
while (argument != NULL)
{
         argument = strtok(NULL," \t\n");
}
execvp(argument,temp2(i)); <--- i'm not sure what should i put for the 2nd parameter
                                                     but i was thinking should be the whole command that have already
                                                     tokenized?
write(1,"exec fail\n",10);      // print this msg if execvp fails
exit(1);

0
 
Infinity08Commented:
If you have split up the command into arguments, then the first argument is the first argument ... Not sure what you're confused about.

I get the feeling that you're depending too much on what I say. Try thinking for yourself, and reading up on things you don't understand.

Get a clear picture in your head of what needs to happen, and then make the code do that.
0
 
crazy4sAuthor Commented:
argument = strtok((char *)temp(j)," \t\n");      // get the first argument of the command eg ls
while (argument != NULL)
{
         argument = strtok(NULL," \t\n");           //and this will get the 2nd argument eg -l
}
so if i have did this will this argument still pointing at the first argument, won't right because i got the 2nd argument here? or did i mistaken anything... hmm did you get what i meant here?? i just want to know how can we know that the execvp first parameter is grabbing the 1st argument of the command???
0
 
Infinity08Commented:
>> i just want to know how can we know that the execvp first parameter is grabbing the 1st argument of the command???

As I said : if you split up the command in arguments, then the first one is the first one. There's nothing magical about it.
0
 
crazy4sAuthor Commented:
because command is stored in an array and now we did the strtok for every element in the array... the tokenized argument will still stored in that particular array is just now that it is in tokenized form, am i correct?
1st strtok
temp[0] = {ls -l}
temp[1] = (more)

after 2nd strtok
temp[0] = {ls}, {-l} // but how can i access only the first argument ls, because i can't write argument[0]
                                right? as execvp needs smt like this ecexvp("ls", temp[0]) ??
temp[1] = {more}
0
 
Infinity08Commented:
>> temp[0] = {ls}, {-l} // but how can i access only the first argument ls, because i can't write argument[0]

The same way you did it for the commands.
0
 
crazy4sAuthor Commented:
>>just like what i did for commands?
which one are you referring to???
do you meant to create another array in the commands to store the arguments just like what i did before??? http:#35219564 
or you meant to be smt like that execvp(temp[0], temp)??? well is not working but i don't understand where is the 2nd and 3rd line come from (from the execvp)????

Command and its process id:
process id 21194
more: No such file or directory
more: No such file or directory
process id 21195
0
 
Infinity08Commented:
>> which one are you referring to???

You used an array to keep track of all the commands.

You can also use an array to keep track of all arguments of a command.
0
 
crazy4sAuthor Commented:
yes that's what i'm thinking too but the problem now is i'm reusing the same array for multiple commands, hmm is there any possibility to create just one array for the arguments so after doing the strtok for arguments, store the arguments into an array argv, followed by execvp (argv[0], argv) and then remove all the elements in the array argv so that i can reuse the same array for the 2nd command??? if yes can you teach me how do i remove all the elements in an array???
0
 
Infinity08Commented:
>> but the problem now is i'm reusing the same array for multiple commands,

That shouldn't matter if you do it in the child code.


>> hmm is there any possibility to create just one array for the arguments so after doing the strtok for arguments, store the arguments into an array argv, followed by execvp (argv[0], argv

Of course.


>> and then remove all the elements in the array argv so that i can reuse the same array for the 2nd command???

You could, but I don't see the point of that ...
0
 
crazy4sAuthor Commented:
>> You could, but I don't see the point of that ...
so i don't need to do that, because the argument array was used in the child process so it doesn't matter so this means we can use the same name of array for different processes? but if so why do i get an exec fail at the ls -l : where is the problem actually occur?

ls -l | more
separate by |:
ls -l
more
Command and its process id:
???????? process id 22764 <-- it wasn't able to print to the command? why?
total 3232
-rwxr-xr-x   1 cpfoo    ugrad       7800 Mar 27 08:24 a.out
-rw-r--r--   1 cpfoo    ugrad       2438 Mar 27 08:23 as4.c
-rw-r--r--   1 cpfoo    ugrad       1430 Mar 22 17:15 as4b.c
-rw-------   1 cpfoo    ugrad    1603966 Mar 26 14:22 core
-rw-r--r--   1 cpfoo    ugrad       1837 Mar 22 17:16 error.c
-rw-r--r--   1 cpfoo    ugrad        121 Mar 22 17:14 makeargv.h
-rw-r--r--   1 cpfoo    ugrad       4128 Mar 22 17:15 ourhdr.h
-rw-r--r--   1 cpfoo    ugrad        783 Mar 23 17:29 t.c
-rw-r--r--   1 cpfoo    ugrad       4344 Mar 25 10:56 typescript
exec fail                    <-- why do i get an exec fail over here? where is the problem? (at the 'more')
?????????????77 process id 22765


int main()
{
	int i = 0;
	int k = 0;
	int j;
	int nos;
	int no = 1;
	int pos, s;
	char *command;
	char *argument;	
        char buf[80];   	// command line
        char* temp[80]={0};	// an array to store the commands
	char space[] = " \t";	// remove space or tab before the command, if any
	char nl[] = "\t\n";	// remove any new lines, if any
	char* argv[80];

	pid_t pid;
	while(strcmp(fgets((char *)buf, 80, stdin), "exit\n")!=0)  // user command line
	{
		command = strtok(buf,"|");		// tokenize the command line by |
		printf("separate by |: \n");
		while(command != NULL)
		{
			nos = strspn (command, space); 	// return the number of spaces or tab before the command
			for (s = 0; s < nos; s++)
				++command;		// increment the pointer of command to remove the spaces or tabs, if any
			if (pos = strcspn (command, nl))// find if there's any new line or tab after the command
				command[pos] = '\0';	// replace it with a null, if any			
			for (;;)				// make a loop
			{
				int n = strlen (command) - 1;	// last character position in command
				if (command[n] == ' ')		// if there's a space 
					command[n] = 0;		// makes the string shorter
				else 
					break;			// out of the loop, if any non-white space is found
			}			

			printf("%s\n",command);
			temp [i] = command;		// store each commands into the array
			command = strtok(NULL,"|");
			i++;				// increment array
		}

		printf("Command and its process id: \n");

		for(j = 0; j < i; j++)			// fork each command
		{
			argument = strtok((char *)temp[j]," \t\n");	// tokenize the command into arguments
			while (argument != NULL)
			{
				argv[k] = argument;
				argument = strtok(NULL," \t\n");
				k++;
			}
			
			pid = fork();
			if (pid == 0)			// child
			{
				execvp(argv[0],argv);
				write(1,"exec fail\n",10);
				exit(1);
			}
			else if (pid < 0) 		// error
			{
				printf("fork failed");
				exit(1);
			}
			else				// parent
			{
				printf("%s process id %d\n",argv, pid);	// print the command and the process id 
			}
			
		}

        }
	return 0;
}

Open in new window

0
 
crazy4sAuthor Commented:
the exec fail should be during the 2nd command 'more'
0
 
Infinity08Commented:
>> we can use the same name of array for different processes?

Of course. Each process has its own memory.


>> but if so why do i get an exec fail at the ls -l : where is the problem actually occur?

Because you're not splitting up the command in the child code, but rather in the parent code.

Remember http:#35191200 ?
0
 
crazy4sAuthor Commented:
ahh i thought i put that inside the child...haihhh
for(j = 0; j < i; j++)			// fork each command
		{
			
			pid = fork();
			if (pid == 0)			// child
			{
				argument = strtok((char *)temp[j]," \t\n");	// tokenize the command into arguments
				while (argument != NULL)
				{
					argv[k] = argument;
					argument = strtok(NULL," \t\n");
					k++;
				}
				execvp(argv[0],argv);
				write(1,"exec fail\n",10);
				exit(1);
			}
			else if (pid < 0) 		// error
			{
				printf("fork failed");
				exit(1);
			}
			else				// parent
			{
				printf("%s process id %d\n",temp[j], pid);	// print the command and the process id 
			}
			
		}

Open in new window


but i don'r really understand the output:

ls -l | more
separate by |:
ls -l
more
Command and its process id:
ls -l process id 23125
total 3232
-rwxr-xr-x   1 cpfoo    ugrad       7816 Mar 27 13:23 a.out
-rw-r--r--   1 cpfoo    ugrad       2448 Mar 27 13:23 as4.c
-rw-r--r--   1 cpfoo    ugrad       1430 Mar 22 17:15 as4b.c
-rw-------   1 cpfoo    ugrad    1603966 Mar 26 14:22 core
-rw-r--r--   1 cpfoo    ugrad       1837 Mar 22 17:16 error.c
-rw-r--r--   1 cpfoo    ugrad        121 Mar 22 17:14 makeargv.h
-rw-r--r--   1 cpfoo    ugrad       4128 Mar 22 17:15 ourhdr.h
-rw-r--r--   1 cpfoo    ugrad        783 Mar 23 17:29 t.c
-rw-r--r--   1 cpfoo    ugrad       4344 Mar 25 10:56 typescript
Usage: more [-cdflrsuw] [-lines] [+linenumber] [+/pattern] [filename ...]. <-- WHAT IS THIS LINE
                                                                                                                       MEANT TO BE?
more process id 23126
0
 
Infinity08Commented:
>> <-- WHAT IS THIS LINE
>>                                                                                                                        MEANT TO BE?

The output of the more command.


Try running more on the command line :)
0
 
crazy4sAuthor Commented:
ahh so what more actually does?
it gives me no difference for ls -l and ls -l | more on the command line?
and for 'more' why is it execute the child first before the parent?
0
 
Infinity08Commented:
>> ahh so what more actually does?

If you ever wonder what a command does, just check the manual page for it :

        man more


>> and for 'more' why is it execute the child first before the parent?

child and parent processes run in parallel ... there's no guarantee when each will run. For longer code, the output will even be interleaved because of this.
0
 
crazy4sAuthor Commented:
oh i thought they'll run the parent first before the child, tat's y sometimes i get confused with that!
so that's all for this assignment right.... hurray~ thanks for spending so much time in explaining stuffs to me, such a looooong discussion:D
0
 
Infinity08Commented:
Heh.

Well, I hope you got something out of it, and you'll have less trouble with future assignments ;)


Just remember : read the manual pages whenever you have a doubt about a function or program. And seriously consider working through a tutorial or book that covers the basics of C.

And the most important advice : just try out stuff - play around with the code to get a better feel for it.
0
 
crazy4sAuthor Commented:
yeah i was thinking of getting a book that covers the basics of C and is easy to understand, any recommendations for me? because i learnt the basic from a different country and the lecturer wasn't teach us much about this and there're alot of stuffs that we need to study our own from the net, and is hard for me to understand as i'm more to like visual learning... anyway really thanks alot as i get to understand how all these works not only for this assignment but for my future assignments too:)
0
 
Infinity08Commented:
I really like "A Book on C" by Al Kelley and Ira Pohl : http://users.soe.ucsc.edu/~pohl/abc4.html
0
 
crazy4sAuthor Commented:
thank you i'll take a look at this book:)
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

  • 112
  • 84
  • 7
Tackle projects and never again get stuck behind a technical roadblock.
Join Now