Why I don't call "read" after setting other group id? - c

In this program I change group id of child process.
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
int main(void) {
int status;
char b[4];
pid_t pid, ch_pid;
switch(pid=fork()) {
case -1:
perror("Fork failed");
exit(1);
case 0:
printf("\nCHILD: This is child process!\n");
printf("CHILD: My PID is-- %d\n", getpid());
printf("CHILD: My parent PID -- %d\n", getppid());
printf("CHILD: My GID is -- %d\n", getpgid(getpid()));
printf("CHILD: My SID is -- %d\n", getsid(getpid()));
int k = setpgid(getpid(),getpid()); /*Modifies group id. Therefore, when user press
Cn+C, ChPr can't die*/
printf("BEFORE SETPGRP CHILD: My GID is -- %d\n", getpgid(getpid()));
printf("BEFORE SETPGRP CHILD: My SID is -- %d\n", getsid(getpid()));
//read(0,b,4);
//printf("b: %s\n",b);
pause();
exit(0);
default:
printf("PARENT: This is parent process!\n");
printf("PARENT: My PID -- %d\n", getpid());
printf("PARENT: My child PID %d\n",pid);
printf("PARENT: My parent PID %d\n",getppid());
printf("PARENT: My GID %d\n",getpgid(getpid()));
printf("PARENT: My SID %d\n",getsid(getpid()));
pause();
exit(0);
}
return 0;
}
But when I attempt to call "read" (commented strings), bash terminal doesn't read and doesn't output. However, parent process are reading successful. Why? Parent and child process have similar session ID. It's mean that they are controlled from common tty. I noted, if I change GID for child process and press Cntrl+C, parent process interrupted only and child process becomes an orphan. So, if I uncomment "read" in my program and press Cntrl+C it kills both process . May be unsuccessful read-call sends some signal to bash? Thank you!

The terminal has a foreground process group setting. When the shell runs commands, it runs foreground jobs in the terminal's foreground process group, but background jobs are put in their own process group. Only the foreground process group is allowed to read from the terminal. If a background process tries to read, it's suspended; when the user moves it to the foreground, the terminal process group is changed to that group, the process is resumed, and then it will be able to read. There's a stty mode tostop that can be used to control whether a background process can write to the terminal, but there's no similar option for reading, it's always prohibited.
If you want the process to be able to read from the terminal after you change its process group, you need to change the terminal's foreground process group. This is done using the tcsetpgrp() function.
tcsetpgrp(0, getpgid(getpid()));

read(2) is only allowed to processes in terminal foreground process group
(this is the process group associated to the terminal in the terminal driver). Other processes get stopped, signal SIGSTOP is sent to them by the tty driver. Some control characters are directed to the terminal control process group also.
See termios(4) or tty(4) for a description on tty control.

Related

How do I kill a process from c with fork() process id?

I am building a feature, where I can open and close files in vi editor. I am using execlp() system call in C for opening a file in a new terminal window in a new child process. Here is how it looks:
void openFile (char *fileName) {
int pid=fork();
if (pid==0){
execlp("gnome-terminal", "gnome-terminal", "--", "vi", fileName, NULL) ;
}
insert(fileName, pid);
return;
}
So for closing the file, I have the child process Id.
void closeProcess (int pid){
printf("killing %d\n", pid);
kill(pid, SIGKILL);
return;
}
Now the challenge is this process id is not the same as the vi editor process id. Killing this process is not closing the vi editor.
Here are some example processes. The process id that I have in pid variable is 25803 but is now dead. To kill vi editor I need the process id 25815.
How killing vi process working.
Here is my current program output, which doesn't close vi editor for that file.
How can I kill the terminal window and vi?
Between the fork() and execlp() you will need to set up a process group id. Then when killing, use the group id.
int setpgid(0, 0);
When this is called in the child, the first 0 is shorthand for "me". The second 0 is shorthand for "use the pid". So this means "create a new process group and put me in that group."
When killing, use the PID you have been using. But it will also handle all children of the group.
How do you get the Process Group ID for a given process?
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main() {
int pid = 20989; // That PID has a PGID of 20988
int pgid = getpgid(pid);
printf("pgid = %d\n", pgid);
}
Alternatively you can use this ps command:
ps xao pid,ppid,pgid,sid,command
Why should I avoid using SIGKILL?
The KILL signal instructs Linux to end the job immediately. Any open files are closed in place. There is no clean up of user land state by the application.
Alternatively, sending SIGTERM instructs the application to end. Permitting the application to close all files, save their state, and prepare to end.

fork: child process doesn't stay in an infinite loop

#include <stdio.h>
#include <unistd.h>
int main()
{
pid_t pid;
pid = fork();
printf("pid : %d\n", getpid());
if( pid == 0)
{
printf("child: pid : %d \n", getpid());
while(1);
}
else
{
printf("parent: pid : %d \n", getpid());
//while(1);
}
}
In the above code snippet inside if statement if we put while(1), it doesn't remains blocked and when enter key is pressed program is exited, but in case of parent if we put while(1), parent remains blocked until we give ctrl+c. Please clarify this behaviour of child.
In the above code snippet inside if statement if we put while(1), it doesn't remains blocked
The child process doesn't exit actually; it just becomes an orphan process because its parent exits. The orphaned chuld process will be adopted by the init process of your system. You can see it via ps command.
But if you put the while(1); in the parent process it remains blocked.
Basically whichever process has while(1); infinite loop, it's still running. When parent exits you get the prompt back and the child becomes orphan. But the child process is still running.
In general, you need to wait(2) for the child process in the parent process to reap child processes.

Linux /proc/PID dir of child stays alive after parent kills child

It seems that if I create a process, fork it and send a SIGHUP from the parent to the child, the child dies but it's "/proc/PID" dir doesn't dissappear until the parent also dies.
(See code below).
What is the right way to let the parent check if the child is dead ?
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <errno.h>
#include <signal.h>
void testprocdir(pid_t pid) {
struct stat sb;
char path[1024];
sprintf(path,"/proc/%d",pid);
if(stat(path, &sb)==-1 && errno == ENOENT) {
printf("%s does not exist\n", path);
} else {
printf("%s exists\n", path);
}
}
int main(int argc,char **argv) {
pid_t parent,child;
parent=getpid();
printf("I am %d\n",parent);
child=fork();
switch(child) {
case -1:
printf("Forking failed\n");
return 2;
case 0:
parent=getppid();
child=getpid();
printf("I am the child (%d) and my parent is %d\n", child, parent);
while(1) { sleep(1); printf("I am the child and I have slept 1s\n");}
printf("This line should not be visible\n");
}
sleep(1); //make sure kid is in the while loop
printf("I am the parent (%d) and my kid is %d\n", parent, child);
kill(child,SIGHUP);
testprocdir(parent);
printf("Waiting 5s before testing if the procdir of the child (/proc/%d) is removed\n",child);
sleep(5);
testprocdir(child);
return 0;
}
You could use the wait family of system-calls.
fork returns the PID of the child process in the parent process, and 0 in the child process.
man waitpid should provide more than enough direction beyond that to call waitpid in the parent, allowing you to check that child process or all child processes ― including the ability to allow the parent to continue executing if the child is still alive or stop all execution in the parent until the child is dead.
I will start with some concepts:
The OS will keep a child process' entry in the process table (including exit status) around until the parent calls waitpid (or another wait-family function) or until the parent exits (at which point the status is collected by the init process). This is what a "zombie" process is: a process that has exited by is still resident in the process table for exactly this purpose. The process' entry in the table should go away after the first call to waitpid.
Also, from the man page :
A child that terminates, but has not been waited for becomes a "zombie". The kernel maintains a minimal set of information about the zombie process (PID, termination status, resource usage information) in order to allow the parent to later perform a wait to obtain information about the child.
So, by using the wait family of functions you can examine the status of child process.
There are some macros also that can be used with with wait family of functions to examine the status of child process like WEXITSTATUS, WIFSIGNALED, WIFEXITED etc .

After calling SIGTSTP on child, no response from parent [duplicate]

I'm coding a basic shell in C, and I'm working on suspending a child process right now.
I think my signal handler is correct, and my child process is suspending, but after that, the terminal should return to the parent process and that's not happening.
The child is suspended, but my shell isn't registering any input or output anymore. tcsetpgrp() doesn't seem to be helping.
Here's my signal handler in my shell code for SIGTSTP:
void suspend(int sig) {
pid_t pid;
sigset_t mask;
//mpid is the pgid of this shell.
tcsetpgrp(STDIN_FILENO, mpid);
tcsetpgrp(STDOUT_FILENO, mpid);
sigemptyset(&mask);
sigaddset(&mask, SIGTSTP);
sigprocmask(SIG_UNBLOCK, &mask, NULL);
signal(SIGTSTP, SIG_DFL);
//active.pid is the pid of the child currently in the fg.
if (active.pid != 0) {
kill(active.pid, SIGTSTP);
}
else{
//if this code is being run in the child, child calls SIGTSTP on itself.
pid = getpid();
if (pid != 0 && pid != mpid){
kill(pid, SIGTSTP);
}
}
signal(SIGTSTP, suspend);
}
Can anyone tell me what I'm doing wrong?
Am I suspending my shell along with the child, and do I need to return stdin and stdout to the shell somehow? How would I do this?
Thanks!
It's an old question but still I think I found an answer.
You didn't write your parent's code but I'm assuming its looks something like:
int main(){
pid_t pid = fork();
if(pid == 0) //child process
//call some program
else //parent process
wait(&status); //or waitpid(pid, &status, 0)
//continue with the program
}
the problem is with the wait() or waitpid(), it's look like if you run your program on OS like Ubuntu after using Ctrl+Z your child process is getting the SIGTSTP but the wait() function in the parent process is still waiting!
The right way of doing that is to replace the wait() in the parent with pause(), and make another handler that catch SIGCHLD. For example:
void sigHandler(int signum){
switch(signum){
case SIGCHLD:
// note that the last argument is important for the wait to work
waitpid(-1, &status, WNOHANG);
break;
}
}
In this case after the child process receive Ctrl+Z the parent process also receive SIGCHLD and the pause() return.
tcsetpgrp is to specify what is the foreground job. When your shell spawns a job in foreground (without &), it should create a new process group and make that the foreground job (of the controlling terminal, not whatever's on STDIN). Then, upon pressing CTRL-Z, that job will get the TSTP. It's the terminal that suspends the job, not your shell. Your shell shouldn't trap TSTP or send TSTP to anyone.
It should just wait() for the job it has spawned and detect when it has been stopped (and claim back the foreground group and mark the job as suspended internally). Your fg command would make the job's pgid the foreground process group again and send a SIGCONT to it and wait for it again, while bg would just send the SIGCONT
i used folk with signals for make process pause and resume with ctrl+c
video while is running : link
Code:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
void reverse_handler(int sig);
_Bool isPause=0;
_Bool isRunning=1;
int main()
{
int ppid;
int counter=0;
//make parent respond for ctrl+c (pause,resume).
signal(SIGINT,reverse_handler);
while(isRunning){
while(isPause==0)
{
/*code exec while process is resuming */
printf("\nc:%d",counter++);
fflush(stdout);
sleep(1);
}
//close parent after child is alive.
if((ppid=fork())==0){ exit(0); }
//make child respond for ctrl+c (pause,resume).
signal(SIGINT,reverse_handler);
//keep child alive and listening.
while(isPause==1){ /*code exec while process is pausing */ sleep(1); }
}
return 0;
}
//if process is pause made it resume and vice versa.
void reverse_handler(int sig){
if(isPause==0){
printf("\nPaused");
fflush(stdout);
isPause=1;
}
else if(isPause==1){
printf("\nresuming");
fflush(stdout);
isPause=0;
}
}
i hope that's be useful.
please comment me if there's any questions
I might be late to answer the question here but this is what worked when I was stuck with the same problem. According to the man pages for tcsetpgrp()
The function tcsetpgrp() makes the process group with process group ID
pgrp the foreground process group on the terminal associated to fd,
which must be the controlling terminal of the calling process, and
still be associated with its session. Moreover, pgrp must be a
(nonempty) process group belonging to the same session as the calling
process.
If tcsetpgrp() is called by a member of a background process group in
its session, and the calling process is not blocking or ignoring
SIGTTOU, a SIGTTOU signal is sent to all members of this background
process group.
So, what worked for me was ignoring the signal SIGTTOU in the shell program, before I created the processes that would come to the foreground. If I do not ignore this signal, then the kernel will send this signal to my shell program and suspend it.

semaphore equivalent for processes?

I have a parent process that forks two children. I need to force a certain order for when these child processes run.
For example, the parent process takes a "command" from a file, and depending on that command, the parent will either pass that command to child a or child b using unnamed pipes. I need stuff to happen in the children in the same order that the parent received the command from the file.
The way I was using semaphores did not work between processes. Any ideas?
Semaphores work just fine between processes. For example:
#include <stdio.h>
#include <semaphore.h>
#include <unistd.h>
int main(void)
{
// Error checking omitted for expository purposes
sem_t *sem = sem_open("test_semaphore", O_CREAT|O_EXCL, 0, 1);
sem_unlink("test_semaphore");
int child = fork();
printf("pid %d about to wait\n", getpid());
sem_wait(sem);
printf("pid %d done waiting\n", getpid());
sleep(1);
printf("pid %d done sleeping\n", getpid());
sem_post(sem);
if(child > 0)
{
int status;
printf("parent done, waiting for child\n");
wait(&status);
}
printf("pid %d exiting\n", getpid());
return 0;
}
Output:
$ time ./a.out
pid 61414 about to wait
pid 61414 done waiting
pid 61415 about to wait
pid 61414 done sleeping
parent done, waiting for child
pid 61415 done waiting
pid 61415 done sleeping
pid 61415 exiting
pid 61414 exiting
real 0m2.005s
user 0m0.001s
sys 0m0.003s
If you use IPC semaphores they also work for forks. Look here: http://www.advancedlinuxprogramming.com/alp-folder Chapter 5 will give you the informations you need.

Resources