简体   繁体   中英

How to get notified when a process ends under linux?

How do I monitor a number of processes and if one process ends, I would like to run some code.

I have found several examples which used polling to achieve this but I am looking for a method to get pushed (probably by the OS) when a process dies. Is this possible with C or C++? It should run on any modern Linux.

If there is any chance, I would like to do that without needing root privileges.

EDIT:

The job of this whole program is to monitor these processes and send this information to another server where it gets integrated into a website.

I have not started these processes but I could ensure that they are started as the same user.

I thought it should be possible because the top / ps command under Linux also gives you information about processes you haven't started.

In general on Linux you can't be notified (with waitpid(2) or SIGCHLD -see signal(7) - ...) about non-child processes, or processes outside of your process group or session.

And on some Linux your (non-root) process might not even be allowed to query the existence of other processes.

Of course, there is /proc/ (having one numerical-named directory per process, eg /proc/1234/ for process of pid 1234, see proc(5) ) that you might regularly scan (eg with readdir(3) ...) but you cannot be notified (see inotify(7) , which does not work for pseudo-file systems like /proc/ ...) about changes inside it. Notice that /proc/ is a pseudo file system, and accessing it does not involve any disk IO so is quite quick.

So what you could do is scan /proc/ every few seconds using opendir(3) , readdir , closedir(3) , sleep(3) in a loop. BTW, that in theory is not fail-proof (in principle, not in practice, the kernel might reuse the same pid within a few seconds), and probably won't catch all short-living processes (such as ls shell commands).

Such a periodic scan of /proc is very probably what the top(1) utility is doing. You could check that by diving into the source code of top or by strace(1) -ing it.

If your C code knows already the pid of some process and simply wants to check the existence of that process, it can use kill(2) with a signal number 0.

See also systemd & credentials(7) .

If you can change the code of the monitored programs or replace them (eg by your small C program wrapping them) things are very different; eg you could replace /usr/bin/foo with /usr/local/bin/foo-wrapper and code a foo-wrapper.c which fork -s & exec -s the original /usr/bin/foo then waitpid(2) on it and finally send(2) or write(2) some message on some socket(7) or fifo(7) or pipe(7) , and use a poll(2) based event loop in your monitor. If you can get all the programs fork -ed by your monitor things are also different (use waitpid ...). See my execicar.c program for inspiration.

You can configure auditd daemon to create audit records (log lines) when a process ends. And then monitor auditd log file with inotify .

Provided you have access to auditd configuration and its log file.

note that the /proc/ directory holds a directory for each running process' PID for example /proc/1 is PID 1

under that directory there's the cmdline file which can be used to determine the PID's command, ie: cat /proc/1/cmdline /usr/lib/systemd/systemd

you can traverse the /proc/[09]* irectories looking for a cmdline that matches what you are looking for, when you match that command you can simply check if the cmdline still matches the original one(the same PID can be used for another process if it had terminated

here's a simple piece of code that gets that job done: I haven't written most of the error correction(program crashes if the application isn't found, some other errors that cause segfault) #include #include #include

int main(int argc, char* argv[]) {
  if (argc != 2){
    printf("usage:\nproc <processname>\n");
    return 2;
  }
  char * processName = argv[1];
  int pid = 0;
  FILE *processFile;
  char *monitoredProcess;
  DIR *root;
  struct dirent *dir;
  root = opendir("/proc/");
if (root)
  {
    int reading = 0;
    while((dir=readdir(root))!=NULL && reading==0)
    {
     // printf("dir name:%i\n",dir->d_ino);
      if (dir->d_name[0] > 47 && dir->d_name[0] < 58) {
    char directory[128];
    strcpy(directory,"/proc/");
        strcat(directory,dir->d_name);
    strcat(directory,"/cmdline");
    processFile = fopen(directory,"r");
    if (processFile == NULL) {
      printf("Error");
      return 1;
    }
    char line[2048];
    while (fgets(line, sizeof line, processFile) != NULL) {
      if(strstr(line,processName)) {
        printf("%s\n",directory);
        monitoredProcess = directory;
        reading = 1;
      }
      //the pid has been determined at this point, now to monitor
    }
      }
    }
    //monitoring
    printf("monitoring %s\n",monitoredProcess);
    while(processFile=fopen(monitoredProcess,"r")) {
      char line[2048];
      while (fgets(line, sizeof line, processFile) != NULL) {
    if(strstr(line,processName) == NULL)
      printf("application terminated\n");
      }
      sleep(3);
      fclose(processFile);
    }
  } else
    printf("unable to open folder\n");
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM