如何在linux下进程结束时收到通知?

时间:2016-01-14 21:59:06

标签: c++ c linux process operating-system

如何监控多个进程,如果一个进程结束,我想运行一些代码。

我找到了几个使用轮询来实现这个目的的例子,但我正在寻找一种方法来在进程死亡时推送(可能是由操作系统)。这可能用C或C ++吗?它应该在任何现代Linux上运行。

如果有机会,我想在不需要root权限的情况下这样做。

编辑:

整个计划的工作是监控这些流程并将此信息发送到另一台服务器,并将其集成到网站中。

我还没有开始这些流程,但我可以确保它们是以同一个用户身份启动的。

我认为它应该是可能的,因为Linux下的top / ps命令还为您提供了有关尚未启动的进程的信息。

3 个答案:

答案 0 :(得分:4)

一般情况下,在Linux上,您无法通过waitpid(2)SIGCHLD - 请signal(7) - ...)通知非子进程或进程外的进程您的流程组或会话。

在某些Linux上,甚至可能不允许您(非根)进程查询其他进程是否存在。

当然,有/proc/(每个进程有一个数字命名的目录,例如/proc/1234/用于pid 1234的过程,请参阅proc(5))您可能会定期扫描(例如, readdir(3) ...)但是您无法收到有关更改的通知(请参阅inotify(7),其中无效对于/proc/这样的伪文件系统...)在里面。请注意/proc/是一个伪文件系统,访问它不涉及任何磁盘IO,所以非常快。

所以你可以做的是每隔几秒使用opendir(3)/proc/closedir(3)sleep(3)在循环中扫描readdir。顺便说一句,从理论上讲,它不是防故障的(原则上,在实践中,内核可能会在几秒钟内重复使用相同的pid),并且可能无法捕获所有短期生存进程(例如ls shell命令)。

/proc的这种定期扫描很可能是top(1)实用程序正在做的事情。您可以通过深入了解top的源代码或strace(1)来查看它。

如果您的C代码已经知道某个进程的pid并且只想检查该进程是否存在,那么它可以使用kill(2)和信号编号0。

另见systemd& credentials(7)

如果您可以更改受监控程序的代码或替换它们(例如,通过包装它们的小型C程序),情况就会大不相同;例如您可以将/usr/bin/foo替换为/usr/local/bin/foo-wrapper,并将foo-wrapper.c编码为fork - s& exec - 原始的/usr/bin/foo然后是waitpid(2),最后是send(2)write(2)某些socket(7)fifo(7)上的消息或pipe(7),并在显示器中使用基于poll(2)event loop。如果您可以通过监视器获取所有程序fork,那么事情也会有所不同(使用waitpid ...)。请参阅我的execicar.c计划获取灵感。

答案 1 :(得分:3)

您可以配置auditd守护程序以在进程结束时创建审核记录(日志行)。然后使用auditd监控inotify日志文件。

前提是您可以访问auditd配置及其日志文件。

答案 2 :(得分:-3)

请注意,/ proc /目录为每个正在运行的进程的PID保存一个目录 例如/ proc / 1是PID 1

在该目录下有cmdline文件,可用于确定PID的命令,即: cat / proc / 1 / cmdline / usr / lib中/ systemd / systemd

你可以遍历/ proc / [09] * irectories寻找与你正在寻找的匹配的cmdline,当你匹配该命令时,你可以简单地检查cmdline是否仍然匹配原始cmdline(同样的PID可以是用于另一个进程,如果它已终止

这是一段完成工作的简单代码: 我没有编写大部分错误纠正(如果找不到应用程序,程序崩溃,导致段错误的其他一些错误)     #包括     #包括     #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");
}