Stop mpg123 after playing the file completely in automatically - c

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.

Related

Execlp execute in another terminal

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.

stdin control is not given to the child after the parent death

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.

execvp/fork -- how to catch unsuccessful executions?

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.

capturing commandline output directly in a buffer

I want to execute a command using system() command or execl and want to capture the output directly in a buffer in C. Is ther any possibility to capture the output in a buffer using dup() system call or using pipe(). I dont want to use any file in between using mkstemp or any other temporary file. please help me in this.Thanks in advance.
I tried it with fork() creating two process and piping the output and it is working.However I dont want to use fork system call since i am going to run the module infinitely using seperate thread and it is invoking lot of fork() and system is running out of resources sometimes after.
To be clear about what i am doing is capturing an output of a shell script in a buffer processing the ouput and displaying it in a window which i have designed using ncurses.Thankyou.
Here is some code for capturing the output of program; it uses exec() instead of system(), but that is straightforward to accomodate by invoking the shell directly:
How can I implement 'tee' programmatically in C?
void tee(const char* fname) {
int pipe_fd[2];
check(pipe(pipe_fd));
const pid_t pid = fork();
check(pid);
if(!pid) { // our log child
close(pipe_fd[1]); // Close unused write end
FILE* logFile = fname? fopen(fname,"a"): NULL;
if(fname && !logFile)
fprintf(stderr,"cannot open log file \"%s\": %d (%s)\n",fname,errno,strerror(errno));
char ch;
while(read(pipe_fd[0],&ch,1) > 0) {
//### any timestamp logic or whatever here
putchar(ch);
if(logFile)
fputc(ch,logFile);
if('\n'==ch) {
fflush(stdout);
if(logFile)
fflush(logFile);
}
}
putchar('\n');
close(pipe_fd[0]);
if(logFile)
fclose(logFile);
exit(EXIT_SUCCESS);
} else {
close(pipe_fd[0]); // Close unused read end
// redirect stdout and stderr
dup2(pipe_fd[1],STDOUT_FILENO);
dup2(pipe_fd[1],STDERR_FILENO);
close(pipe_fd[1]);
}
}
A simple way is to use popen ( http://www.opengroup.org/onlinepubs/007908799/xsh/popen.html), which returns a FILE*.
You can try popen(), but your fundamental problem is running too many processes. You have to make sure your commands finish, otherwise you will end up with exactly the problems you're having. popen() internally calls fork() anyway (or the effect is as if it did).
So, in the end, you have to make sure that the program you want to run from your threads exits "soon enough".
You want to use a sequence like this:
Call pipe once per stream you want to create (eg. stdin, stdout, stderr)
Call fork
in the child
close the parent end of the handles
close any other handles you have open
set up stdin, stdout, stderr to be the appropriate child side of the pipe
exec your desired command
If that fails, die.
in the parent
close the child side of the handles
Read and write to the pipes as appropriate
When done, call waitpid() (or similar) to clean up the child process.
Beware of blocking and buffering. You don't want your parent process to block on a write while the child is blocked on a read; make sure you use non-blocking I/O or threads to deal with those issues.
If you are have implemented a C program and you want to execute a script, you want to use a fork(). Unless you are willing to consider embedding the script interpreter in your program, you have to use fork() (system() uses fork() internally).
If you are running out of resources, most likely, you are not reaping your children. Until the parent process get the exit code, the OS needs keeps the child around as a 'zombie' process. You need to issue a wait() call to get the OS to free up the final resources associated with the child.

Non-blocking version of system()

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

Resources