Home:ALL Converter>How can I catch SIGINT and have it only kill foreground processes in C?

How can I catch SIGINT and have it only kill foreground processes in C?

Ask Time:2019-12-21T16:03:23         Author:Alex

Json Formatter

I'm creating a shell program, and I want Ctrl+C to kill foreground processes but not background processes for example; &sleep 50 is a background process, and I want it to be so that if I were to use Ctrl+C it would kill any foreground processes, and leave the background unaffected. But for the life of me can't figure out what to do, any help is greatly appreciated :D

int main(void) {
  Command cmd;
  int n, forSignals;
  char **cmds;
  char **pipedCmds;
  signal(SIGINT, INThandler);
  while (!done) {
    char *line;
    line = readline("> ");
    if (!line) {
      done = 1;
    } else {
      stripwhite(line);
      if(*line) {
        add_history(line);
        n = parse(line, &cmd);
        PrintCommand(n, &cmd);
        cmds = getCmds(cmd.pgm);
        pipedCmds = getPipedCmds(cmd.pgm);
        executionDecider(line, cmds, pipedCmds, cmd);
      }
    }
    if(line) {
      free(line);
    }
  }
  return 0;
}

void  INThandler(int sig)
{
  signal(sig, SIG_IGN);
  kill(SIGINT, 0);
  printf("\n");
}

P.S. There is of course the rest of the code on actually executing programs, let me know if it's necessary to be shown, but I believe, this is a good minimally reproducible example.

EDIT: Quite important, don't know how I forgot :/ but I need it to not create a zombie process by doing this, it shouldn't leave ANY zombies behind.

EDIT: Please find linked a URL leading to a code dump of the full project. It may make more sense there: https://codedump.io/share/d8hrj40JdEqL/1/lshc---c-shell-program

Author:Alex,eproduced under the CC 4.0 BY-SA copyright license with a link to the original source and this disclaimer.
Link to original article:https://stackoverflow.com/questions/59434535/how-can-i-catch-sigint-and-have-it-only-kill-foreground-processes-in-c
mevets :

I think your core question is how to interpose on the standard signal semantics of a process group.\nBy default all the processes that you fork() remain within the process group you belong to. A system call, setpgid(), can create a new process group, divorcing group signal semantics for the new processes.\n\nCertain signals are delivered to process groups. Notifications from the tty driver are broadcast to the process group which the session leader of the tty currently belongs to. Simple, right :-?\n\nSo, what you want to do is use setpgid() in the child processes you start to create a new process group. Any processes they subsequently start will inherit their new process group; so they have no way back to the original, root, process group [ I think, the ground is uneven here ].\n\nI've written a sample program which creates a little set of processes which just hang around sleeping until they are sent a SIG_TERM signal. Each of these processes are placed in their own process group ( waste of resources, but much smaller code ). When you hit Control-C on this program running, it announces its SIG_INT, then delivers a SIG_TERM to all the processes it started. When you hit Control-D, the main process exits.\n\nYou can tell this program works if you input Control-C, Control-D, you should find with ps/pgrep that no residual children exist, and the output screen display the correctly configured (NPROC) number of processes receiving a SIG_TERM (15).\n\n#include <signal.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <unistd.h>\n\n#ifndef NPROC\n#define NPROC 7\n#endif\nstatic int children[NPROC];\nstatic int nproc;\n\nstatic void SigPrint(char *act, int signo) {\n char buf[100];\n int n;\n n = sprintf(buf, \"[%d]:(%d) -> %s\\n\", getpid(), signo, act);\n write(1, buf, n);\n}\n\nstatic void SigDie(int signo) {\n SigPrint(\"Die\", signo);\n _exit(1);\n}\n\nstatic void SigDisp(int signo) {\n SigPrint(\"Dispatch\", signo);\n int i;\n for (i = 0; i < nproc; i++) {\n if (kill(children[i], SIGTERM) < 0) {\n perror(\"kill\");\n }\n }\n}\n\nint main(void) {\n signal(SIGINT, SigDisp);\n signal(SIGTERM, SigDie);\n for (nproc = 0; nproc < NPROC; nproc++) {\n children[nproc] = fork();\n if (children[nproc] == 0) {\n signal(SIGINT, SIG_DFL);\n if (setpgid(0, 0) < 0) {\n perror(\"setpgid\");\n _exit(1);\n }\n while (sleep(5)) {\n }\n _exit(0);\n } else if (children[nproc] < 0) {\n perror(\"fork\");\n kill(getpid(), SIGINT);\n perror(\"kill\");\n _exit(1); /*Just in case... */\n }\n }\n int c;\n while ((c = getchar()) != EOF) {\n putchar(c);\n }\n return 0;\n}\n\n\nWhen you run this, you should get output something like:\n\n^C[15141]:(2) -> Dispatch\n[15142]:(15) -> Die\n[15143]:(15) -> Die\n[15146]:(15) -> Die\n[15144]:(15) -> Die\n[15145]:(15) -> Die\n[15147]:(15) -> Die\n[15148]:(15) -> Die\n\n\nwith different values for the [pid] field.\n\nThis program shows how to divorce child processes from the notifications of the parents. It could be much better, the model here is quite rich.",
2019-12-29T08:55:32
UpendraG :

By default STDIN of all background process is disabled.\nYou can check with sudo ls -al /proc/<"pid">/fd.\nIn that case any of the input can not be transferred from terminal to background process.\nSo even after ctrl+c it will not get terminated. And only the foreground process will get terminated.\n++\nAs per man page\nint kill(pid_t pid, int sig);\nHere you are doing kill(SIGINT,0);\nAs per your code, second argument 0 means Hangup signal (SIGHUP) which comes only when shell is get terminated. It terminates all process running in that shell.\nUpdate the kill function calling.\n++\nYou have mentioned "&sleep 50" this is not valid in linux.So which OS are you using.",
2019-12-21T12:23:00
yy