My program receives a string (a shell script's path) as input. Now I have to launch that shell script and find out the process id for it.
I'm using the system() function to launch a shell script and after that using popen() with ps -aef | grep "ShellScript" to get its PID.
It's being suggested to me that there's a better way to do it. The way I did it will give a wrong PID if multiple scripts are running at same time.
What is the correct way to get a PID for a given script name after launching it?
Firstly you should not use system().
A better approach would be using fork(), which returns a PID > 0 if you are in the parent process and return 0 if you are in the child.
Any other return satus is an error and errno is set accordingly.
When you are in the child process you should exec your command, while you should either wait for it in the parent one if you want to avoid to have a zombie process or handle SIGCHLD signal.
Always read man for better insight.
Here is a brief example
int pid = -1;
If((pid = fork()) > 0)
{
/* Parent process*/
wait(NULL);
}
else if(pid == 0)
{
/*Child process*/
execv(....);
exit (0);
}
else
{
/*Error*/
perror("fork()");
}
Related
I'm trying to run a series of commands through execv() and forking a new process in C to run each one, and yet for some reason they aren't running in parallel. The following code is run for each process, with "full" being the filepath and "args" being the arguments. I know that the execv() part isn't the issue, it has to do with the way I'm forking and waiting.
int status;
pid_t pid = fork();
if (pid == 0) {
execv(full, args);
//perror("execv");
} else if (pid < 0) {
printf("%s\n", "Failed to fork");
status = -1;
} else {
if (waitpid(pid, &status, 0) != pid) {
status = -1;
return status;
}
}
When running this code, the forked commands simply run one after the other. I don't know how this could be happening.
If you don't want to wait for each child process, don't call waitpid immediately; as written, you fork a child, then immediately stop all processing in the parent until the child process exits, preventing you from forking any further children. If you want to launch multiple children without leaving zombie processes lying around (and possibly monitoring them all at some point to figure out their exit status), you can do one of:
Store off the pids from each fork in an array, and call waitpid on them one by one after you've launched all the processes you need to launch
Store a count of successfully launched child processes and call wait that many times to wait on them in whatever order they complete.
Ignore the SIGCHLD from the child processes entirely, for when you don't care when they exit, don't need to know their status, etc.
I am working on a tiny shell(tsh) implemented in C(it's an assignment). One part of assignment belongs to PIPING. I have to pipe a command's output to another command. e.g:ls -l | sort
When I run the shell, every command that I execute on it, is processed by a child process that it spawns. After the child finishes the result is returned. For piping I wanted to implement a harcoded example first to check how it works. I wrote a method, that partially works. The problems is when I run the pipe command, after child process finishes, the whole program quits with it! Obviously I am not handling the child process signal properly(Method code below).
My Question:
How does process management with pipe() works? if i run a command ls -l | sort does it create a child process for ls -l and another process for sort ? From the piping examples that I have seen so far, only one process is created(fork()).
When the second command (sort from our example) is processed, how can i get its process ID?
EDIT: Also while running this code I get the result twice. don't know why it runs twice, there is no loop in there.
Here is my code:
pid_t pipeIt(void){
pid_t pid;
int pipefd[2];
if(pipe(pipefd)){
unix_error("pipe");
return -1;
}
if((pid = fork()) <0){
unix_error("fork");
return -1;
}
if(pid == 0){
close(pipefd[0]);
dup2(pipefd[1],1);
close(pipefd[1]);
if(execl("/bin/ls", "ls", (char *)NULL) < 0){
unix_error("/bin/ls");
return -1;
}// End of if command wasn't successful
}// End of pid == 0
else{
close(pipefd[1]);
dup2(pipefd[0],0);
close(pipefd[0]);
if(execl("/usr/bin/tr", "tr", "e", "f", (char *)NULL) < 0){
unix_error("/usr/bin/tr");
return -1;
}
}
return pid;
}// End of pipeIt
Yes, the shell must fork to exec each subprocess. Remember that when you call one of the execve() family of functions, it replaces the current process image with the exec'ed one. Your shell cannot continue to process further commands if it directly execs a subprocess, because thereafter it no longer exists (except as the subprocess).
To fix it, simply fork() again in the pid == 0 branch, and exec the ls command in that child. Remember to wait() for both (all) child processes if you don't mean the pipeline to be executed asynchronously.
Yes, you do need to call fork at least twice, once for each program in the pipeline. Remember that exec replaces the program image of the current process, so your shell stops existing the moment you start running sort or (tr).
I am working on a tiny shell(tsh) implemented in C(it's an assignment). One part of assignment belongs to PIPING. I have to pipe a command's output to another command. e.g:ls -l | sort
When I run the shell, every command that I execute on it, is processed by a child process that it spawns. After the child finishes the result is returned. For piping I wanted to implement a harcoded example first to check how it works. I wrote a method, that partially works. The problems is when I run the pipe command, after child process finishes, the whole program quits with it! Obviously I am not handling the child process signal properly(Method code below).
My Question:
How does process management with pipe() works? if i run a command ls -l | sort does it create a child process for ls -l and another process for sort ? From the piping examples that I have seen so far, only one process is created(fork()).
When the second command (sort from our example) is processed, how can i get its process ID?
EDIT: Also while running this code I get the result twice. don't know why it runs twice, there is no loop in there.
Here is my code:
pid_t pipeIt(void){
pid_t pid;
int pipefd[2];
if(pipe(pipefd)){
unix_error("pipe");
return -1;
}
if((pid = fork()) <0){
unix_error("fork");
return -1;
}
if(pid == 0){
close(pipefd[0]);
dup2(pipefd[1],1);
close(pipefd[1]);
if(execl("/bin/ls", "ls", (char *)NULL) < 0){
unix_error("/bin/ls");
return -1;
}// End of if command wasn't successful
}// End of pid == 0
else{
close(pipefd[1]);
dup2(pipefd[0],0);
close(pipefd[0]);
if(execl("/usr/bin/tr", "tr", "e", "f", (char *)NULL) < 0){
unix_error("/usr/bin/tr");
return -1;
}
}
return pid;
}// End of pipeIt
Yes, the shell must fork to exec each subprocess. Remember that when you call one of the execve() family of functions, it replaces the current process image with the exec'ed one. Your shell cannot continue to process further commands if it directly execs a subprocess, because thereafter it no longer exists (except as the subprocess).
To fix it, simply fork() again in the pid == 0 branch, and exec the ls command in that child. Remember to wait() for both (all) child processes if you don't mean the pipeline to be executed asynchronously.
Yes, you do need to call fork at least twice, once for each program in the pipeline. Remember that exec replaces the program image of the current process, so your shell stops existing the moment you start running sort or (tr).
I would like to create a new process using fork and then use excl to start a web browser with a url.
Im not too familiar with fork and excel so any help would be appreciated.
thanks
EDIT:
this is my code but i don't think its right
if(fork() == 0) {
execl (url,0);
printf("Route opened in brwoser\n");
} else {
printf("Route cannot be opened.\n");
}
Read the manual pages of these calls first:
man 2 fork
man 3 execl
The syscall fork() makes a copy of the process and returns in both, returning the child process ID in the parent and zero in the child. If it returns a negative number, it means it's failed.
pid_t pid = fork();
if (pid < 0)
printf("Fork failed\n");
else if (pid > 0) /* Here comes the parent process */
printf("Fork successful\n");
else /* Here comes the child process */
...
On the other hand execl() does not return at all. It throws away your program, and replaces it with image of the one specified in its arguments in the same process.
If execl() returns, it's an error. It probably did not find the program you specified.
Its arguments are the called program (an URL is not a program) and its arguments.
...
else { /* Here comes the child process */
execl("/usr/bin/firefox", "/usr/bin/firefox", "example.com", (char*)NULL);
printf("Could not execute Firefox\n");
}
The situation is the following: I fork the process to open an html file with the default browser. Here is how it looks in my case:
if ((pid=fork())==0) {
execlp("/usr/bin/xdg-open", "xdg-open", url, NULL);
/*if execlp failed, exit the child*/
exit(0);
}
However, I want to get hold of the PID of the process (opened browser), so that I could close it later too. But I do not seem to know how could I get it. Please let me know if you have any suggestions.
You should already have the PID of the child process, the man page of fork() says:
On success, the PID of the child process is returned in the parent,
and 0 is returned in the child.
So in the child process you detect the 0 and run your program, in the parent pid will be the actual PID of the child.
According to your comment what will then happen is that the xdg-open process - who's PID you now now will in turn start a browser and you have no direct access to the PID of that browser process.
At present the only thing I can think of doing is creating yet another child process that you run a command such as ps or pgrep in. You can then parse the output of that command to find the PID of the browser that is running as a child of the xdg-open. There is an example of reading the output of a child process here
fork() returns the pid of the child process to the parent.
In the child you can acquire it's own pid with the standard getpid().
pid_t child_pid = fork();
if (child_pid < 0) {
perror("fork");
// error handling
} else if (!child_pid) {
// child goes here
pid_t my_pid = getpid();
} else {
// parent continues here
}