【问题标题】:Monitoring mount point changes via /proc/mounts通过 /proc/mounts 监控挂载点的变化
【发布时间】:2011-07-01 13:04:53
【问题描述】:

根据proc手册,可以通过打开“/proc/mounts”,在select()调用中添加要读取fd_set的文件描述符来监控linux系统中挂载点的变化。

以下代码适用于 Ubuntu 9.04,而不适用于 Ubuntu 10.04(带有 2.6.32 linux 内核):

int mfd = open("/proc/mounts", O_RDONLY, 0);

fd_set rfds;
struct timeval tv;
int rv;

FD_ZERO(&rfds);
FD_SET(mfd, &rfds);
tv.tv_sec = 5;
tv.tv_usec = 0;

int changes = 0;
while ((rv = select(mfd+1, &rfds, NULL, NULL, &tv)) >= 0) {
    if (FD_ISSET(mfd, &rfds)) {
        fprintf(stdout, "Mount points changed. %d.\n", changes++);
    }

    FD_ZERO(&rfds);
    FD_SET(mfd, &rfds);
    tv.tv_sec = 5;
    tv.tv_usec = 0;

    if (changes > 10) {
        exit(EXIT_FAILURE);
    }
}

Compilable snippet.

文件描述符在一台机器上总是可读的,因此它会在 select 调用中不断弹出。即使坐骑没有变化。

我错过了什么吗?

提前感谢您的帮助!

man 5 proc:

/proc/[pid]/mounts(Linux 2.4.19 起)

这是当前挂载在进程挂载命名空间中的所有文件系统的列表。该文件的格式记录在 fstab(5) 中。从内核版本 2.6.15 开始,该文件是可轮询的:打开文件进行读取后,该文件的更改(即文件系统挂载或卸载)导致 select(2) 将文件描述符标记为可读,并且 poll( 2) 和 epoll_wait(2) 将文件标记为有错误条件。

【问题讨论】:

标签: c linux filesystems mount procfs


【解决方案1】:

在 linux 内核中有一个 bugfix 描述了这种行为:

SUSv3 说“常规文件应始终轮询 TRUE 以进行读取和 写作”。见 http://www.opengroup.org/onlinepubs/009695399/functions/poll.html

因此,您必须将 poll 与 POLLPRI | 一起使用。轮询标志。像这样的:

int mfd = open("/proc/mounts", O_RDONLY, 0); struct pollfd pfd; int rv; int changes = 0; pfd.fd = mfd; pfd.events = POLLERR | POLLPRI; pfd.revents = 0; while ((rv = poll(&pfd, 1, 5)) >= 0) { if (pfd.revents & POLLERR) { fprintf(stdout, "Mount points changed. %d.\n", changes++); } pfd.revents = 0; if (changes > 10) { exit(EXIT_FAILURE); } }

【讨论】:

  • 我还想为像我这样慢的人指出,您也可以在问题代码中使用 "select(mfd+1, NULL, NULL, &rfds, &tv)"它也会起作用。 (第三个参数用于“异常”条件)。我花了一段时间才意识到这一点:)
  • 这是一篇很老的帖子,现代 GNU/Linux 系统不需要 POLLPRI。
【解决方案2】:

您指向的文档不正确。要使用 select() 等待装载更改,/proc/mounts/proc/pid/mounts 文件描述符应设置在 exceptfds 中,而不是 readfds 中。只需交换程序中的第二个和第四个参数。 POSIX 要求与常规文件关联的文件描述符始终可读。

【讨论】:

  • 你是对的。 exceptfds 也可以。我引用的文档来自我正在运行的机器。我想必须更改 proc 手册。
【解决方案3】:

为了补充问题上发布的主要示例,这是另一个使用 GLibGIO 库的示例,通过监视 /proc/self/mountinfo 来监听挂载更改:

/* Compile with:
 * gcc -g -O0 `pkg-config --cflags --libs gio-2.0` -o test test.c
 */

#include <glib.h>
#include <gio/gio.h>

static gboolean
proc_mounts_changed (GIOChannel   *channel,
                     GIOCondition  cond,
                     gpointer      user_data)
{
  if (cond & G_IO_ERR)
    {
      g_message ("MOUNTS CHANGED!"); 
    }
  return TRUE;
}

int
main (int argc, char *argv[])
{
  GIOChannel *proc_mounts_channel;
  GSource *proc_mounts_watch_source;
  GError *error = NULL;
  GMainLoop *loop;

  proc_mounts_channel = g_io_channel_new_file ("/proc/self/mountinfo", "r", &error);
  if (proc_mounts_channel == NULL)
    {
      g_warning ("Error creating IO channel for %s: %s (%s, %d)", "/proc/self/mountinfo",
               error->message, g_quark_to_string (error->domain), error->code);
      g_error_free (error);
      return error->code;
    }

  proc_mounts_watch_source = g_io_create_watch (proc_mounts_channel, G_IO_ERR);
  g_source_set_callback (proc_mounts_watch_source,
                         (GSourceFunc) proc_mounts_changed,
                         NULL, NULL);
  g_source_attach (proc_mounts_watch_source,
                   g_main_context_get_thread_default ());
  g_source_unref (proc_mounts_watch_source);
  g_io_channel_unref (proc_mounts_channel);

  loop = g_main_loop_new (NULL, FALSE);

  /* Run the main loop, program can be ended with CTRL+C */
  g_main_loop_run (loop);
  g_main_loop_unref (loop);

  return 0;
}

【讨论】:

    【解决方案4】:

    如果你这样做

    ls -l /proc/mounts
    

    您会看到时间在不断变化,这意味着即使没有太大变化,装载数据也会不断更新。所以看起来当前监控安装的方法是行不通的。

    【讨论】:

      猜你喜欢
      • 2020-02-06
      • 2021-08-26
      • 2013-08-09
      • 2011-07-22
      • 1970-01-01
      • 2011-10-25
      • 1970-01-01
      • 1970-01-01
      • 2016-09-26
      相关资源
      最近更新 更多