this is a simple example to use the tcsetpgrp function:
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
static void judge(void){
pid_t pid;
pid = tcgetpgrp(STDIN_FILENO);
if(pid == -1){
perror("tcgetpgrp");
return;
}else if(pid == getpgrp()){
printf("foreground\n");
}else{
printf("background\n");
}
}
int main(void){
signal(SIGTTOU,SIG_IGN);
judge();
int result;
result = tcsetpgrp(STDIN_FILENO,getpgrp());
if(result == -1){
perror("tcsetpgrp");
return -1;
}
judge();
return 0;
}
i will run it in the background,as my expection,the output like:
todd911#virtual-machine:./a.out &
[1] 15894
todd911#virtual-machine:~$ background
foreground
but in fact,it act like:
todd911#virtual-machine:./a.out &
[1] 15894
todd911#virtual-machine:~$ background
foreground
exit
at last,the terminal exit automatically,is anybody know the reason?
It is possible that if the process group that controls the terminal exits, then the shell or terminal will decide the session has ended and kill it off. I tried your program on gnome-terminal with ksh93 and bash and it did not exit.
Related
I was trying to build an interactive shell which runs within the ZSH shell. Any command would execute in it's own process group (thus I use tcsetpgrp call to make it the foreground process group, and once the command is executed the the interactive shell would become the foreground process group). However I observe that during the execution of my code I get a SIGTTOU signal, which to the best of my knowledge is delivered when a background process attempts to write to the terminal. With respect to the below example if someone could explain the reason for the aforementioned signal it would be really helpful.
Minimal reproducible example
#include <sys/types.h>
#include <termios.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
int main()
{
for(;;){
printf(">Network shell\n");
int par = getpid();
int child = fork();
if(child == 0){
int c2 = fork();
if(c2 == 0){
char * args[2];
args[0]="/bin/ls";
args[1] = NULL;
execv(args[0], args);
}
else{
wait(NULL);
tcsetpgrp(STDIN_FILENO, par); //done to bring previous process group back to foreground
tcsetpgrp(STDOUT_FILENO, par);
}
}
else{
setpgid(child, child);
tcsetpgrp(STDIN_FILENO, child);
tcsetpgrp(STDOUT_FILENO, child);
wait(NULL);
}
}
}
Here is the output I see on my terminal:
Your /bin/ls writes to stdout, and since its stdout is not redirected, it writes to the terminal.
Let's take this snippet as an example:
#include <signal.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
int main(int argc, char const *argv[]) {
int pid = fork();
if (pid == 0) { // Child
execlp(argv[1], argv[1], NULL);
} else if (pid > 0) { // Parent
int n = atoi(argv[2]);
sleep(n);
kill(pid, SIGKILL);
int status;
wait(&status);
...
exit(0);
}
return 0;
}
After being run with main [command] [seconds], the program should create a subprocess to execute the given command and terminate it after n seconds.
Problem is, if I call it with args top 3 it correctly starts top and terminates after 3 seconds, but i'm left with a working shell with invisible text: i can type and execute commands, but the typed text doesn't show on the screen until a reset is run.
Any insight on what's happening?
top sets the terminal to a mode where it doesn't echo input (see man noecho or man tcsetattr). If top exits cleanly, like when you press "q" interactively, it resets it to a normal mode. But your program kills it, so the terminal is left in no-echo mode.
I am forking a child process and execl a BinaryApp.exe in that child process. However, I want a separate terminal window for newly forked BinaryApp.exe and control transferred to that terminal window so that it can detect any key strokes. Also by separating terminal windows, I can show interprocess communication more straightforwardly as parent and child process will output in their respective terminal windows. I am using cygwinb20 on Windows.
I have written a code for forking BinaryApp.exe but it shows its output in the same window as its parent. Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
int main() {
pid_t Pid;
int ret;
printf("Main Program\n Initializing processe...\n");
Pid = fork();
if (Pid >= 0) /* fork succeeded */
{
if (Pid == 0) /* fork() returns 0 for the child process */
{
ret = execl("../BinaryApp.exe","BinaryApp.exe",(char*)NULL);
if(ret == -1) {
perror("execv - BinaryApp.exe");
}
}
}
else /* failure */
{
perror("fork - BinaryApp.exe");
exit(0);
}
// Doing other things
}
I'm trying to recode a shell and I would like to change the pgid of my programs launched with my shell !
I tried to do differents functions after my fork() :
setpgid(0, 0) that makes interactive programs like vim, emacs... to do an infinite loop
setsid() that doesn't deserve control to the terminal. It makes
programs like emacs failed with Could not open file: /dev/tty
tcsetpgrp(0, getpid()) that make my shell to go to background !
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
int pid;
if ((pid = fork()) == 0)
{
setpgid(0, 0);
execlp("/usr/bin/emacs", "", "-nw", "test_file", (char*)0);
}
if (pid < 0)
exit (1);
if (pid > 0)
{
printf("Program finished.\n");
waitpid(-1, 0, 0);
}
return (0);
}
Have you got a clue about how to solve that ?
So, I find the solution to make work emacs program like emacs, vim etc.. that needs to control the terminal !
I had to add control to the terminal into the parent, like that :
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
int pid;
if ((pid = fork()) == 0)
{
setpgid(0, 0);
execlp("/usr/bin/emacs", "", "-nw", "test_file", (char*)0);
}
if (pid < 0)
exit (1);
if (pid > 0)
{
tcsetpgrp(0, pid)
printf("Program finished.\n");
waitpid(-1, 0, 0);
}
return (0);
}
If you want more informations : Here is a good link http://www.gnu.org/software/libc/manual/html_node/Launching-Jobs.html
I'm trying to write my own C shell. I'm wondering how to make calling 'kill' in the command line work. For example,
shell> kill 2
shell: process 2 has been killed
Line 1 is user input 'kill 2'
Line 2 is program-printed message of what has been done.
I know I have to take the pid as the argument I believe and send the SIGKILL signal.
Using something like
kill(pid, SIGKILL);
How do I connect this kill function to respond when a user inputs 'kill 2' in a C implementation? I guess I'm having a hard time connecting it to the command line arguments for implementation. I might need strtok/atoi?
Thank you.
Better you go for "getopt" which might look as fallows,
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <signal.h>
int pid;
if((pid = getopt(argc, argv, "0123456789")) != -1)
if(isdigit(pid)){
if(kill(pid, SIGKILL) == -1){
perror("KILL:");
exit(0);
}
}else{
printf("Input format: kill <pid>");
}
#include<stdio.h>
#include<sys/types.h>
#include<signal.h>
int main(int argc, char **argv)
{
if (argc < 3)
{
printf("usage: ./kill OPERATION(kill/cont) PID\n");
return -1;
}
if(strcmp(argv[1],"kill") == 0 )
{
printf("Kill:\n");
kill(atoi(argv[2]), SIGKILL);
}
else if(strcmp(argv[1],"cont") == 0)
{
printf("cont:\n");
kill(atoi(argv[2]), SIGCONT);
}
else
{
printf("Kill default:\n");
kill(atoi(argv[2]), SIGKILL);
}
return 0;
}