Мониторинг изменений точки монтирования через /proc / mounts
Согласно руководству proc, можно отслеживать изменения точки монтирования в системе linux, открыв "/proc / mounts " и добавив файловый дескриптор для чтения fd_set
в вызове select()
.
Следующий фрагмент кода работает на Ubuntu 9.04, а не в Ubuntu 10.04 (с ядром linux 2.6.32):
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);
}
}
Файловый дескриптор всегда читается на одной машине, и поэтому он постоянно появляется в вызове select. Даже в конях никаких изменений нет.
Am Я что-то упустил?
Заранее спасибо за любую помощь!
/ proc/[pid] / mounts (начиная с Linux 2.4.19)
Это список всех файловых систем, смонтированных в данный момент в пространстве имен монтирования процесса. Формат этого файла задокументирован в fstab (5). Начиная с версии ядра 2.6.15, этот файл можно опрашивать: после открытия файла для чтения, изменение в этом файле (т. е. монтирование или размонтирование файловой системы) вызывает select (2), чтобы отметить файл дескриптор считывается, а poll (2) и epoll_wait(2) помечают файл как имеющий условие ошибки.
4 ответа:
В ядре linux было исправление, описывающее это поведение:
SUSv3 говорит: "обычные файлы должны всегда опрашивать TRUE для чтения и письменный". видеть http://www.opengroup.org/onlinepubs/009695399/functions/poll.html
Итак, вы должны использовать poll с флагами POLLPRI | POLLERR. Что-то вроде этого:
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()
, файловый дескриптор/proc/mounts
или/proc/pid/mounts
должен быть установлен в exceptfds, а не readfds. Просто поменяйте местами 2-й и 4-й аргументы в вашей программе. Файловые дескрипторы, связанные с обычными файлами, должны быть всегда доступны для чтения в POSIX.
Чтобы дополнить основной пример, опубликованный на вопрос, вот еще один пример использования библиотек
GLib
иGIO
, чтобы слушать изменения монтирования путем мониторинга/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; }