Take in command line arguments like so "program /path_name -l" and create both a parent and child process. Fork needs to be used to create the child and the child should replace itself using one of the exec commands. The parent process needs to wait for the child to finish and receive the exit status, then use the exit status to determine if the program exited normally and if the process was killed by some signal. I'm having an issue where my program always gets an exit status of 1. I'm not sure I'm doing the whole command line thing correctly.
This is what I have so far:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char *argv[]){
pid_t pid = fork();
if (pid == -1){
perror("Fork Failure");
return EXIT_FAILURE;
}
else if ( pid == 0 ){
execvp(argv[1], &argv[1]);
return EXIT_FAILURE;
}
int status;
waitpid(pid, &status, 0);
if ( WIFEXITED(status) ){
int exit_status = WEXITSTATUS(status);
printf("Exit status is %d\n", exit_status);
}
return 0;
}
Related
I'm trying to better understand exec() - so I have the following script in testing.c
#include <stdio.h>
#include <sys/types.h>
#include <wait.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char ** argv)
{
if(argc < 2) {
fprintf(stderr,"Error:: Expecting an Argument!\n");
exit(-1);
}
pid_t pid;
pid = fork();
if (pid==0) {
execlp("./testing","testing",NULL);
fprintf(stderr, "I want to get to here...\n");
exit(-1);
}
wait(NULL);
printf("Parent and child done\n");
return 0;
}
The block below is the output after I execute with ./testing one:
Error:: Expecting an Argument!
Parent and child done
In reading how exec() works, I was expecting to be able to fprintf after my execlp call since it should be returning -1, I'm wondering if I need to be setting an errno or something or being more explicity about throwing something so that execlp recoginize the error?
If the execlp function successfully starts the given program, it does not return. The current program image gets replaced with the program image of the new program. So even if the new program exits with status -1, it still doesn't go back to the program that called execlp.
If you want to get the exit status of the child process, pass the address of an int to wait and read that:
int main(int argc, char ** argv)
{
if(argc < 2) {
fprintf(stderr,"Error:: Expecting an Argument!\n");
exit(-1);
}
pid_t pid;
pid = fork();
if (pid == -1 {
perror("fork failed");
exit(-1);
} else if (pid == 0) {
execlp("./testing","testing",NULL);
perror("execlp failed");
exit(-1);
}
int status;
wait(&status);
printf("child exit status: %d\n", WEXITSTATUS(status));
printf("Parent and child done\n");
return 0;
}
The output:
Error:: Expecting an Argument!
Parent and child done
is from
(first line) child process tries to run but no command line parameter.
(second line) parent process finishes
I made some weird experiment and created a program that forks itself and executes itself in the child process, which is forked again and executes itself again...and so on.
Only after exiting the ssh session I was connected to it stopped.
What are the possible ways to kill such program, which continuously changes it's own PID ?
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int spawn (char* program, char** arg_list)
{
pid_t child_pid;
child_pid = fork ();
if (child_pid != 0)
/* This is the parent process. */
return child_pid;
else {
printf("my pid is %d my ppid is %d\n", getpid(), getppid());
execvp (program, arg_list);
fprintf (stderr, "an error occurred in execvp\n");
abort ();
}
}
int main ()
{
char* arg_list[] = {
"./1", /* argv[0], the name of the program. */
NULL
};
spawn ("./1", arg_list);
return 0;
}
I run my C program on debian-linux ,the program is expected to output
$ ./kill_raise
Child(pid : 4877) is waiting for any signal
Parent kill 4877
but I just got
Parent kill 4877
the string in subprocess (Child(pid : %d) is waiting for any signal) is not print out,why?
and this is my program
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
pid_t pid;
int res;
pid = fork();
if (pid < 0)
{
perror ("Fork error\n");
exit(0);
}
if (pid == 0)
{
printf ("child(pid:%d) is waiting for signal\n", getpid());
raise(SIGSTOP);
exit(0);
}
else
{
if ((waitpid(pid, NULL, WNOHANG)) == 0)
{
if ((res = kill(pid, SIGKILL)) == 0)
{
printf ("parent kill %d\n", pid);
}
}
waitpid(pid, NULL, 0);
exit(0);
}
}
You're hitting a race condition. The parent is executing the kill before the child can execute its printf. Remove WNOHANG so the parent actually waits for the child to stop. Also, you need to add WUNTRACED so that waitpid reports the stop (by default, it will only report termination). Finally, you shouldn't be testing wait()'s return value against 0 in this case.
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
int main( ) {
pid_t pid;
int status = -1;
if ((pid = fork()) != 0) {
printf("Father process wait child PID=%d\n", pid);
wait(&status);
printf("Child finish with status: %d\n",WEXITSTATUS(status));
exit(0);
}
else {
printf("Child process running...\n");
execl("/bin/ls","ls", "-la", NULL);
printf("Child ending...\n");
}
}
When compiling this code the last line of the else doesn't print and I don't know why.
http://linux.die.net/man/3/execl
The exec() family of functions replaces the current process image with a new process image.
....
Return Value
The exec() functions only return if an error has occurred. The return
value is -1, and errno is set to indicate the error.
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <limits.h>
#include <unistd.h>
#include <stdlib.h>
#include <pwd.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
void sig_handler(int signal);
int pid, forkFlag = 0;
int main( int argc, char **argv, char **envp )
{
sigset(SIGINT, sig_handler); //handle ctrl + c
sigignore(SIGTSTP);
sigignore(SIGSTOP);
int ex, rv, status;
forkFlag = 1; //fork is being called
pid = fork();
if(pid == -1){
perror("fork");
exit(2);
}
else if (pid == 0){ //if child process
ex = access(argv[0], X_OK); //check if file is executable
if(ex){
perror("access");
exit(1);
}
else{
rv = execve(argv[0], argv, envp); //run program in child process
if(rv == -1){
perror("execve");
exit(1);
}
}
exit(0); //end child process
}
else{
rv = waitpid(pid, &status, 0); //wait for child
if(rv == -1){
perror("waitpid");
}
if(WEXITSTATUS(status)){ //check status of child if it did ot return 0
printf("The return status of the child was %d\n", WEXITSTATUS(status));
}
}
forkFlag=0;
}
void sig_handler(int signal)
{
if(signal == SIGINT && (pid && forkFlag)){
kill(pid,signal); //send kill to child
}
}
I'm trying to make my program ignore ctrl + C, except when there is a child process running, then it sends the the SIGINT to the child process. However, when I press ctrl + c when the child process is running, waitpid() returns -1 with the error "Interrupted System Call." This makes the child process stop running, but if I use ps, the child process is still there, but now labeled as defunct. I know from printf statements that kill is being calle din the function sig_handler, and that pid and forkFlag are their correct values. Is waitpid() making my program ignore the kill? How do I fix this? I know this code does next to nothing, but it's a small portion of my code (the only part involving fork)
Thanks for any help.
The problem is that the child processes get the same overridden handler for SIGINT. You probably want to reset the signal handler in the child process after the fork, or you might want to install the signal handler in the parent after you've already forked the child, so it doesn't inherit the overriden handler.