How to take execlp's exit code - c

The following code works like this:
I create a pipe to connect two processes. One process will be the command who, in order to know which users are logged on. The other process will be the command grep, which takes who's command output and looks for "user" into this output. Main program's exit code must be 1 if the user is logged on, and 0 if the user's not logged on. Where do I have to take exit code?
Here's the code:
int fd[2];
pipe(fd);
int pid1,pid2;
pid1 = fork();
if (pid1 != 0) {
pid2 = fork();
if(pid2 == 0) {
close(0); dup(fd[0]); close(fd[0]), close(fd[1]);
execlp("grep","grep ","user",NULL);
} else {
close(fd[0]); close(fd[1]);
}
} else {
close(1);
dup(fd[1]);
close(fd[0]);
close(fd[1]);
execlp("who","who",NULL);
}

exec* calls usually do not return. If they return then only because exec failed to load the new process image. In that case the error is returned in errno.
If you are interested in the exit status of your child process then you have to either install a signal handler for SIGCHLD or wait for your child in the parent and retrieve the exit status that way.
For your own convenience you may want to consider using system instead:
int exit_status = system("who | grep user");

execlp() overwrites the address space with the executable command and runs it. So it will return only if there is some error in executing the command. In this case return value is -1.

Related

fork() - have parent process do work without waiting for child process

I'm making a shell in C for a school project that is capable of running processes in parallel if it is commanded to do so.
This is the loop of the shell application that waits for commands:
while (1) {
action = parseShellArgs();
if (action == 1) {
printf("Exiting...\n");
break;
} else if (action == 0) {
int pid = fork();
if (pid < 0) {
printf("Failed to fork\n");
} else if (pid == 0) {
(*NUM_PROCESSES_RUNNING)++;
printf("There are %d processes running\n", *NUM_PROCESSES_RUNNING);
char * solverArgs[] = {"a", shellArgs[1], NULL}; // first element is placeholder for argv[0]
execv("CircuitRouter-SeqSolver", solverArgs);
exit(0);
} else if (pid > 0) {
if (*NUM_PROCESSES_RUNNING >= MAXCHILDREN) {
printf("All processes are busy\n");
continue;
}
int status, childpid;
wait(&status);
childpid = WEXITSTATUS(status);
(*NUM_PROCESSES_RUNNING)--;
printf("There are %d processes running\n", *NUM_PROCESSES_RUNNING);
(void)childpid; // suppress "unused variable" warning
} else {
printf("Wait what\n");
}
} else {
printf("Oops, bad input\n");
}
}
Please do disregard the constants being incremented and decremented.
Now, this only works partially. Whenever I give it a command to create another process and run another program (condition action == 0, this has been tested and works), the fork happens and the program is correctly executed.
However, I cannot fork multiple times. What I mean by this is: the program forks and the child executes as instructed in the execv call. The problem is that instead of the parent process then goes back to expecting input to possibly fork again, it waits for the child process to finish.
What I am trying to make this cycle do is for the parent to always be expecting input and forking as commanded, having multiple children if necessary. But as I explained above, the parent gets "stuck" waiting for the single child to finish and only then resumes activity.
Thank you in advance.
Edit: I have experimented multiple combinations of not waiting for the child process, using extra forks to expect input etc.
From man wait.2
The wait() system call suspends execution of the calling process until
one of its children terminates.
Your program gets stuck because that's what wait does. Use waitpid instead with WNOHANG.
waitpid(pid_child, &status, WNOHANG);
doesn't suspend execution of the calling process. You can read the waitpid man page to find out the return values and how to know if a child terminated.

finding process id using program name

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()");
}

How can i use fork to open a new process and use execl to start a web browser in c

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");
}

How to kill a process tree programmatically on Linux using C

I am trying to write a function that spawns a child process, lets it run for a certain amount of time and then kills it if it hasn't finished:
int sysExecTimeout(const char * exePath, int timeoutSec);
In the function, I use fork and execl to spawn the child, and, when it times out, I use kill(pid, SIGTERM) and kill(pid, SIGKILL) after 2 seconds, to ensure the child dies:
pid_t pid = fork();
if(pid == 0) {
execl("/bin/sh", "sh", "-c", exePath);
exit(127);
} else if(pid != -1) {
// timeout code
if(timeout) {
kill(pid, SIGTERM);
sleep(2);
kill(pid, SIGKILL);
}
}
I am using Linux, and it seems that when a parent process dies, the child is not killed automatically. So the two kill calls will just kill the /bin/sh process and leave the exePath command running, since it is a child process of /bin/sh.
I am trying to write the sysExecTimeout function such that it kills the entire process tree rooted at pid, where pid is the PID from pid = fork()
I need this because the exePath command will spawn other commands, which can also spawn other commands, which could get stuck and consume resources.
I do not have control over the exePath binaries/scripts that get executed, so I cannot write my own parent-dies-so-kill-the-children logic in them.
I tried using kill(0, SIGTERM), which almost did the job, except it also killed my own process :)
I am wondering if there is a flag I can turn on programatically in C that says "hey man, when I die, take all my children and kill them, and repeat recursively for their children" such that the entire process tree started from that program dies (assuming the PID/PPID chain can be followed).
I could use that flag here:
if(pid == 0) {
turnOnRecursiveDeathFlag();
system(exePath);
//execl("/bin/sh", "sh", "-c", exePath);
exit(127);
}
Is there a way to do that? I've been searching for a while, but all I can find are hacks using ps -ef, or modifying the children processes that you are running etc.
Use setpgid in the child to set its GPID equal to its own PID. The parent then can kill(-pid,...) to signal the entire group.
pid_t pid = fork();
if(pid == 0) {
setpgid(0, 0);
execl("/bin/sh", "sh", "-c", exePath);
exit(127);
} else if(pid == -1) {
// timeout code
if(timeout) {
kill(-pid, SIGTERM);
sleep(2);
kill(-pid, SIGKILL);
}
}
That should do it.
One more thing, when you spawn a shell, make sure it doesn't enable job control. Otherwise, it will create its own process groups. Your "/bin/sh -c" is fine.

Persistent execvp on pipe?

I am working on an assignment for my Operating System class (Posix & C), building a mini-shell, and I don't know how to solve the following problem:
My mini-shell has to accept two commands, for example ls | grep a. For that I create a pipe of size two and a child. The child closes all that it has to close and opens all that it has to open (standard/pipe's in & out). It then executes "ls," using execvp. I am sure this works well. After that, the parent shuts and opens inputs and outputs (I am sure I do it well), and then executes grep a.
Now, the problem is that the process grep a never finishes. Same for tail -1, e.g.. Yet it does work for head -1. I think that happens because grep and tail, which are executed by the parent, wait for more input, even though the child has finished its operation. ls | grep a produces the right output, displayed on the console (The pipe's output is set as default output), but, as I've said, grep a does not finish.
So, my question is: how can I inform the parent that the pipe has finished writing, so it can finish the execution of grep a for example?
Thank you.
Here's the code:
[fd is the pipe, it is initialized previously in the code. If you can see any incongruous thing, please let me know; I've cleaned the code a bit, and this is only the problematic part, as you can see.]
int fd[2];
pipe(fd);
if ((pid = fork()) != -1){
if(pid == 0){ /*Child executing */
close(fd[0]);
close(1);
dup(fd[1]);
close(fd[1]);
execvp(argvv[0][0], argvv[0]); /* Here's stored the first instruction */
} else{ /* Parent executing */
wait(&status);
close(fd[1]);
close(0);
dup(fd[0]);
close(fd[0]);
execvp(argvv[1][0], argvv[1]); /* Here's stored the second instruction */
}
}
If the grep continues to run after the ls has exited, that indicates that you have not closed all the pipes that you need to close.
In particular, the write end of the pipe whose read end is attached to the grep process is still open in another process. You will need to show your code to know more.
The code you have pasted works correctly (when expanded to a full program, as per the below). Both subprocesses exit just fine.
This means that you've eliminated the code that has the problem when you created your cut-down version here - perhaps you have another fork() between the pipe() call and this fork()?
#include <unistd.h>
#include <sys/wait.h>
int main()
{
pid_t pid;
char *argvv[2][3] = { { "ls", 0, 0}, { "grep", "a", 0 } };
int status;
int fd[2];
pipe(fd);
if ((pid = fork()) != -1) {
if(pid == 0){ /*Child executing */
close(fd[0]);
close(1);
dup(fd[1]);
close(fd[1]);
execvp(argvv[0][0], argvv[0]); /* Here's stored the first instruction */
} else{ /* Parent executing */
wait(&status);
close(fd[1]);
close(0);
dup(fd[0]);
close(fd[0]);
execvp(argvv[1][0], argvv[1]); /* Here's stored the second instruction */
}
}
return 0;
}

Resources