Sending signal to certain (grand-...)grandchildren - c

Is there a nice way to send a SIGUSR to a grandchild directly?
E.g. I have some process tree:
0
/ \
1 2
\
3
and need to send a signal from 0 to 3.
I know I could save child's pid after forking and the use it with kill() like
pid = fork();
if (pid == 0) {
pid = fork();
if (pid == 0) { /* grandchild */ }
savepid = pid;
}
...
kill(savepid,sig);
but then I'd have to use shared memory to make those variable globally visible, which is not allowed in my homework :)

There is no direct communication between parent and grandchildren. The usual approach here is having the grandchild to store its PID somewhere on the filesystem (say, in /var/lib/myapp/grandchild.pid) and reading it back in the parent.
You can also use process groups on Linux, but they offer a coarse-grained approach.

dunno if this works flawlessly, but the MAIN idea is here
int fd[2]; /*write(fd[1],buffer,strlen)
/ read(fd[0],buffer2,SIZE)*/
pid_t cpid,savepid;
if(pipe(fd)==-1){
perror("pipe");
exit(EXIT_FAILURE);
}
if((cpid=fork())<0){/* FORK INIT FOR CHILD */
printf("\n\tFORK ERROR\n");
exit(1);
}
if(cpid==0){ /*process CHILD*/
if((cpid=fork())<0){/* FORK INIT FOR GRANDCHILD */
printf("\n\tFORK ERROR\n");
exit(1);
}
if(cpid==0){ /*process GRANDCHILD*/
close(fd[0]);
if((write(fd[1],(char*)pid,strlen(final2)))<0){
perror("\n\tWRITE ERROR");
}
/********CODE******/
close(fd[1]);
}else{ /*process CHILD*/
/********CODE******/
}
}else{ /*process PARENT*/
close(fd[1]);
if((read(fd[0],(char*)savepid,NN))<0){
perror("\n\tREAD ERROR");
}
/********CODE******/
kill(savepid,SIGKILL);
/*code parent*/
wait(NULL);
close(fd[0]);
}

Related

Write Pid of a deamon in a file

This is my code and I'm trying to write a pid in a file, I'm using fprintf but it doesn't work
This is my code :
int write_pid_in_file(struct config *conf, pid_t pid)
{
//conf->global->pid_file = /tmp/HTTPd.pid
FILE *file_opened = fopen(conf->global->pid_file,"w+");
if (!file_opened)
return 2;
printf("%d\n",pid); //check if it's the good pid
fprintf(file_opened, "%d\n",pid);
fclose(file_opened);
return 0;
}
In this function I call the write function and I get the pid from the demone
int daemon_start(struct config *conf)
{
pid_t cpid;
cpid = fork();
if (cpid == -1)
{
perror("fork");
exit(0);
}
write_pid_in_file(conf,cpid);
if (cpid > 0)
{
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
exit(0);
}
serv(conf->vhosts); //infinite loop
return 0;
}
I'm doing this bc later I need to make a function who stop this deamon ^^
Given the code
int daemon_start(struct config *conf)
{
pid_t cpid;
cpid = fork();
if (cpid == -1)
{
perror("fork");
exit(0);
}
write_pid_in_file(conf,cpid); <-- both parent and child will call this
.
.
.
There will be two processes that call write_pid_in_file() - the parent process will write the pid of the child process, and the child process will write 0.

How do you read from pipe with both children in C?

int main()
{
int pipefd[2];
char buf;
int pid, pid1;
pid = fork();
if (pipe(pipefd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
if(pid == 0){ // CHILD 1
close(pipefd[1]);
while(read(pipefd[0],&buf,1) > 0){ // THIS DOESNT WORK
printf("FIRST CHILD WRITES: %s\n",&buf); // THIS DOESNT WORK
} // THIS DOESNT WORK
close(pipefd[0]);
_exit(EXIT_SUCCESS);
}else{
pid1 = fork();
if(pid1 == 0){ // CHILD 2
close(pipefd[1]);
// while(read(pipefd[0],&buf,1) > 0){ // ONLY THIS (WOULD) WORK
// printf("SECOND CHILD WRITES: %s\n",&buf); // ONLY THIS (WOULD) WORK
// } // ONLY THIS (WOULD) WORK
close(pipefd[0]);
_exit(EXIT_SUCCESS);
}else{ // PARENT
close(pipefd[0]);
char* s = "Write To Pipe";
write(pipefd[1],s,strlen(s));
close(pipefd[1]);
wait(NULL); // WAIT FOR CHILD TO TERMINATE
wait(NULL); // WAIT FOR CHILD TO TERMINATE
}
}
return 0;
}
Whenever I try to run the program only the 2ND CHILD can read from the pipe, the 1ST CHILD never. So I tried commenting the second child's pipe reading, however the first child still can't read from the pipe to which the parent wrote into.
Why can't the 1ST CHILD read from the pipe?
Thanks for the help!
The order is wrong. Your code is
pid = fork();
if (pipe(pipefd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
You need to create the pipe before you fork. You would probably catch this type of error if you check for errors on the close and/or the read.

Setting parent to child process group with setpgid fails

I'm trying to change the pgrp of the processes to that of the child's so i can setsid on the parent process. The only thing is I keep getting an EPERM error code. Both processes have the same session group, according to htop.
I'm basing this off of this blog post, so I can change which terminal output gets directed to.
void sig_exit(int signum)
{
_Exit(0);
}
pid_t change_process_group()
{
pid_t child_pid;
if ((child_pid = fork()) < 0)
{
perror("fork failed while attaching to term");
exit(1);
}
if (child_pid == 0)
{
pid_t parent = getppid();
setpgid(0, getpid());
signal(SIGUSR1, sig_exit); // wait till parent tells child to exit
//sleep(5);
//kill(parent, SIGUSR2);
pause();
printf("Shouldn't reach this\n");
}
//sleep(5);
//signal(SIGUSR2, sig_wait);
//pause();
int parent_pid = getpid();
int code = setpgid(parent_pid, child_pid); // need child process group
printf("%s\n", strerror(errno));
setsid();
return child_pid;
}
main()
{
pid_t child = change_process_group();
kill(child, SIGUSR1);
}
The commented out lines were from me thinking the processes might not be executing in the correct order, but those don't appear to fix the problem.
How may I correctly use setpgid to change the pgrp of the parent process to the child's?
This is a race condition and it works if you uncomment the sleep(5) line in the parent. When you call setpgid(parent_pid, child_pid), the child_pid process group must exist. It isn't enough that there exists a process with the PID child_pid: setpgid needs an existing process group unless the process is putting itself into its own group. If setpgid(parent_pid, child_pid) in the parent runs after setpgid(0, getpid()) in the child, it works.
Sleeping is both inefficient and fragile, so instead of that the parent should wait for a notification from the child. Signals are fragile because there aren't many different signals and they could come from anywhere. A good way to communicate between related processes is a pipe. Since all you need here is a one-time notification, you can set up a pipe and read from it in the parent (with the write end closed in the parent). The parent will wait until the child writes to the pipe or closes it. In the child, just close the write end of the pipe when you've finished the preparations. The parent's read call (or select if you need to do other things at the same time) will return.
Proof-of-concept code:
pid_t change_process_group()
{
pid_t child_pid;
int child_ready_pipe[2];
if (pipe(child_ready_pipe) < 0)
{
perror("pipe");
exit(1);
}
if ((child_pid = fork()) < 0)
{
perror("fork failed while attaching to term");
exit(1);
}
if (child_pid == 0)
{
close(child_ready_pipe[0]);
sleep(1); // mimic slow start of the child
if (setpgid(0, 0))
perror("child setpgid to create group");
close(child_ready_pipe[1]);
signal(SIGUSR1, sig_exit); // wait till parent tells child to exit
pause();
printf("Shouldn't reach this\n");
}
close(child_ready_pipe[1]);
int parent_pid = getpid();
char ignored;
read(child_ready_pipe[0], &ignored, 1);
close(child_ready_pipe[0]);
if (setpgid(parent_pid, child_pid) < 0) // need child process group
perror("parent setpgid");
if (setsid() < 0)
perror("parent setsid");
return child_pid;
}

Should I be terminating a forked child process with exit()?

I'm working on some stuff using fork() in C. This is my first contact with the concept of forking processes.
Basically, I have something like this:
int pid;
pid = fork();
if (pid < 0) {
fprintf(stderr, "Fork Failed");
exit(-1);
} else if (pid == 0) {
fprintf(stderr, "Inside child %d\n", getpid());
// do some other stuff
exit(0);
} else {
fprintf(stderr, "Inside parent %d\n", getpid());
}
Before, I hadn't put the exit(0) in the child process' code. I was getting seemingly tons of duplicate processes. I added the exit(0) and now I'm only spawning one child. However, I want to know if this is proper practise or just a bandaid. Is this the correct thing to do. How should a child "stop" when its done?
Usually the child either has it's own code with an exit or calls one of the exec functions to replace its process's image with another program. So the exit is okay. But the parent and child could execute at least some of the same code, something like this:
int pid = fork();
if (pid < 0) {
fprintf(stderr, "Fork Failed");
exit(-1);
} else if (pid == 0) {
// child code
} else {
// parent code
}
// shared code
Well if you want that parent process works only after child process finishes then you can use wait function.Here is the example:
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h> //fork() is defined in this header file
#include<sys/wait.h>//wait() is defined in this header file
int main()
{
int pid,a,b;
printf("\nPlease enter two numbers\n");
scanf("%d%d",&a,&b);
pid=fork();
if(pid<0)
{
printf("\nfork failed\n");
exit(1);
}
if(pid==0)
{
//you are in chiled process
//getting child process id
printf("\n[child %d]: sum of %d and %d is %d\n",getpid(),a,b,a+b);
}
else
{
//waiting for child process to finish
wait(NULL);
//getting parent id
printf("\n[parent %d]:difference of %d and %d is %d\n",pa_pid,a,b,a-b);
exit(0);
}
}

2 child process does not display a message

I am trying to learn programming on and I don’t understand why I can't get child 2 to print hello. I have also closed both read and write ends of the pipe for the parent because I don’t want the parent to communicate. Any help is much appreciated.
int main ()
{
int fd[2];
pid_t child_pid, child_pid1;
if (pipe(fd) < 0)
{
printf("Pipe error");
}
child_pid = fork (); // child 1
if (child_pid != 0)
{
printf("im child 1");
dup2 (fd[1], STDIN_FILENO);
printf("greetings");
child_pid1 = fork (); //child 2
if (child_pid1 != 0)
{
printf("im child 2");
dup2(fd[0], STDOUT_FILENO);
printf("hello");
}
else if (child_pid1 > 0) //Parent Code
{
close (fd[0]);
close (fd[1]);
}
}
return 0;
}
Your first if clause is wrong.
child_pid = fork (); // child 1
if (child_pid != 0)
{
printf("im child 1");
}
This is not the child but the parent. If it is the child, then pid will be 0, only on the parent you have child_pid != 0.
The same happens in the second if clause as well.
You should do if(child_pid == 0) in both cases, if you want that code to be executed in the child process.

Resources