I am creating an application in C which I have to execute the firefox with the command execlp but every time I execute it I "lost" my current terminal, but after the execlp i still need to use the terminal which I was before, so my question is: Is there a way where I can be in one terminal call execlp and it executes in another one without block the one I am on?
here is a snippet of my code:
pid_t child = fork();
if (child == -1) {
perror("fork error");
} else if (child == 0) {
exec_pid = getpid();
execlp("firefox", "firefox", URL, NULL);
perror("exec error");
}
// keep with program logic
If I'm understanding you correctly, you're saying that your program launches Firefox and then keeps control of your shell until Firefox terminates. If this is the case, there are a couple of ways around this.
The easiest solution is to run your program in the background. Execute it like ./my_program & and it be launched in a separate process and control of your terminal will be returned to you immediately.
If you want to solve this from your C code, the first step would be to print out the process ID of the child process after the fork. In a separate shell, use ps to monitor both your program and the forked PID. Ensure that your program is actually terminating and that it's not just stuck waiting on something.
Related
Considering the following code, when the parent is terminated, the stdin control is taken back by the shell and there is no way to see that the child process is running except through the "ps -e" command.
Is there is any way to give the stdin control to the child process before the parent dies?
I read some similar topics here, but non of them gives a solution to this issue. One has suggested to use "#cat | ./a.out" as a work around but I want a code level solution if there is any.
pid = fork();
if( pid == 0)
{
while(1);
}
else
{
//wait(&childstatus);
printf("Hello From Parent\n");
}
Yes, this is the way shell works. If you don't want the shell take active process group, keep the parent alive.
First I have used mpg123 remotely using FIFOs to implement Pause functionality, but now I want to close the mpg123 player when file is played through automatically.
The code for playing current is
pid p = fork();
if (p<0)
return;
else if (p==0)
execlp("mpg123", "mpg123", "-R", "--fifo", "aFifo", NULL);
else
system("load test.mp3 > aFifo");
Currently if the file is played through then also child process else if (p==0) will stay there and mpg123 player process will continue to exist
You have no ? in your question, but any way
your code looks wrong, because system uses fork and exec
under the hood. So instead of one fork and one exec
you use fork three times and uses execv twice.
Read how to run process here: how to correctly use fork, exec, wait
after you run process in proper way, you have real pid of mpg123,
and so you can kill it if you want, or pause or what else you want.
I am trying to implement a shell in C language on Linux.This project that I am working on, asks to create a shell in C, starting from creating a very basic one (myShell), which goes deeper step by step.First I had to create a shell with simple commands like
ls,pwd,echo,date,time
(shell1).
After that, my Shell had to be improved so it could sort things from files (txt's for example) (shell2) and as it goes on, I had to do more by developing it, and make it execute commands like
sort -r,sort -u.(shell3).
Until the 3rd shell, I was working with redirections and everything was going well.
Now for the 4th shell, I am supposed to make it run commands with pipes, e.g. ls -l /home/ | sort > out.txt. I have managed to make the command work, the out.txt file gets created succesfully and is sorted accordingly. There is a while() on my code, so that after every command that I give to the shell it asks for the next one etc. etc.. But when the above example command is given and the pipes are used, the program stops. The terminal doesn't show "myShell4>" but Desktop$ and it basically exits the shell. Giving it simple commands like "ls -l" ,that don't use the pipes, works perfectly, so from that I realise that the problem is in the pipes and that they stop my program from looping.
The part where this happens in my code:
//CHILD
dup2(pipefd[1],1);
close(pipefd[0]);
execute(cmd,path,argm);
//PARENT
dup2(pipefd[0],0);
close(pipefd[1]);
execlp(cmd2,cmd2,NULL);
Any thoughts? Thanks in advance!
The parent is the shell, right? Don't exec there; create children for both ends of the pipe and wait for them in the parent. If you do, the shell will be replaced and no longer run after the command ends.
Below is some pseudo-code for a pipe between two commands:
int pipefd[2];
pipe (pipefd);
// child for first command
if (fork () == 0) {
// setup in redirection if any
...
// setup out redirection
close (pipefd[0]);
dup2 (pipefd[1], STDOUT_FILENO);
...
exec (cmd1, ...);
exit (1);
}
// child for second command
if (fork () == 0) {
// setup in redirection
close (pipefd[1]);
dup2 (pipefd[0], STDIN_FILENO);
// setup out redirection if any
dup2 (output_file_fd, STDOUT_FILENO);
exec (cmd2, ...);
exit (1);
}
close (pipefd[0]);
close (pipefd[1]);
// parent waits and then restarts the loop
wait (NULL);
wait (NULL);
Things get more complicated for a list of more than two commands connected by pipes.
Right now I'm writing a C program that must execute a child process. I'm not doing multiple child processes simultaneously or anything, so this is fairly straightforward. I am definitely executing the built-in shell programs (i.e. things like cat and echo) successfully, but I also need to be able to tell when one of these programs fails to execute successfully. I'm trying this with the following simplified code:
int returnStatus; // The return status of the child process.
pid_t pid = fork();
if (pid == -1) // error with forking.
{
// Not really important for this question.
}
else if (pid == 0) // We're in the child process.
{
execvp(programName, programNameAndCommandsArray); // vars declared above fork().
// If this code executes the execution has failed.
exit(127); // This exit code was taken from a exec tutorial -- why 127?
}
else // We're in the parent process.
{
wait(&returnStatus); // Wait for the child process to exit.
if (returnStatus == -1) // The child process execution failed.
{
// Log an error of execution.
}
}
So for example, if I try to execute rm fileThatDoesntExist.txt, I would like to consider that a failure since the file didn't exist. How can I accomplish this? Also, while that execvp() call successfully executes built-in shell programs, it doesn't execute programs in the current directory of the executable (i.e. the program that this code is running inside of); Is there something else that I have to do in order to get it to run programs in the current directory?
Thanks!
This is a classic problem with a very elegant solution. Before forking, create a pipe in the parent. After fork, the parent should close the writing end of the pipe, and block attempting to read from the reading end. The child should close the reading end and set the close-on-exec flag, using fcntl, for the writing end.
Now, if the child calls execvp successfully, the writing end of the pipe will be closed with no data, and read in the parent will return 0. If execvp fails in the child, write the error code to the pipe, and read in the parent will return nonzero, having read the error code for the parent to handle.
wait(2) gives you more than just the exit status of the child process. In order to get the real exit status, you need to use the WIFEXITED() macro to test if the child exited normally (as opposed to abnormally via a signal etc.), and then use the WEXITSTATUS() macro to get the real exit status:
wait(&status);
if(WIFEXITED(status))
{
if(WEXITSTATUS(status) == 0)
{
// Program succeeded
}
else
{
// Program failed but exited normally
}
}
else
{
// Program exited abnormally
}
In order for execvp(3) to run a program in the current directory, you either need to add the current directory to your $PATH environment (generally not a good idea), or pass it the full path, e.g. use ./myprogram instead of just myprogram.
In terms of failure detection, if an exec() function replaces the current process with a new one, then the current process is gone; it doesn't matter if the executed program decides that what it has been asked to do is a success or failure. However, the parent process from before the fork can discover the child's exit code which would likely have the command success/failure information.
In terms of finding executables, execvp() duplicates the action of the shell, searching the current path. If it is not finding executables in the working directory, it is likely that directory is not in the search path (or the files are not actually executable). You can try specifying them by a full path name.
If you simply want to run a command and wait for the result, you might want to use the system() function which handles this for you, instead of building it yourself with fork/exec.
I want to launch a process from within my c program, but I don't want to wait for that program to finish. I can launch that process OK using system() but that always waits. Does anyone know of a 'non-blocking' version that will return as soon as the process has been started?
[Edit - Additional Requirement] When the original process has finished executing, the child process needs to keep on running.
One option is in your system call, do this:
system("ls -l &");
the & at the end of the command line arguments forks the task you've launched.
Why not use fork() and exec(), and simply don't call waitpid()?
For example, you could do the following:
// ... your app code goes here ...
pid = fork();
if( pid < 0 )
// error out here!
if( !pid && execvp( /* process name, args, etc. */ )
// error in the child proc here!
// ...parent execution continues here...
The normal way to do it, and in fact you shouldn't really use system() anymore is popen.
This also allows you to read or write from the spawned process's stdin/out
edit: See popen2() if you need to read and write - thansk quinmars
You could use posix_spawnp() function. It's much similar to system() than the fork and exec* combination, but non-blocking.
In the end, this code appears to work. Bit of a mis-mash of the above answers:
pid = fork();
if (!pid)
{
system("command here &");
}
exit(0);
Not quite sure why it works, but it does what I'm after, thanks to everyone for your help
How about using "timeout" command if you are looking for your command to exit after a specific time:
Ex: system("timeout 5 your command here"); // Kills the command in 5 seconds if process is not completed