Нужно отследить момент подключения флешки. Предполагаю, что это делается через D-Bus, и надо ловить сигнал на шине org.freedesktop.UDisks2 (dbus-monitor --system показывает сигналы на этой шине, d-feet-ом можно посмотреть структуру). Желательно на чистом C без крестов (да, читал на freedesktop.org, что это «pain»), без GTK, QT.
Есть утилита USBGuard, включена в Ubuntu, из исходников не собирается (в 2-х разных форумах пишут про эти грабли), писана на С++17 со всеми его прибабахами, про freedesktop.org там вообще не нашел в коде, но бинарный пакет ставил и он вообщем работает (автор проект забросил, в каждом дистре собирают его форки).
Тут примерно описано, что надо делать, но ссылка на пример сдохла http://wiki.linuxformat.ru/wiki/LXF99:D-Bus. Пример отсюда запускал, как-то работает, что-то гоняет https://stackoverflow.com/questions/9378593/dbuswatch-and-dbustimeout-examples . Прошу выдать волшебного пенделя. В какую сторону копать, что почитать? Ведь работают же например всякие нотификации в трее, может кто знает в каком пакете KDE/Gnome это находится.
Вот этот код ничего не ловит, кроме первого сообщения от org.freedesktop.DBus, NameAcquired.
/**
*/
#define _GNU_SOURCE /* for pipe2 in unistd.h */
#include "dbus/dbus.h"
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> /* for pipe2 */
#include <errno.h>
#include <fcntl.h> /* for O_NONBLOCK */
#include <sys/time.h> /* for gettimeofday */
#include <limits.h> /* for INT_MAX */
static DBusHandlerResult handle_messages(DBusConnection *connection, DBusMessage *message, void *user_data);
#if 0
#define INTERFACE "org.freedesktop.HAL"
#define OBJPATH "/org/freedesktop/HAL"
#endif
#if 1
#define INTERFACE "org.freedesktop.UDisks2"
#define OBJPATH "/org/freedesktop/UDisks2"
#endif
DBusObjectPathVTable vtable;
typedef struct _DBusContext
{
DBusConnection *conn;
}
DBusContext;
DBusContext ctx;
//---------------------------------------------------------------------------//
/**
* @brief flt_handle_messages
* @param connection
* @param message
* @param user_data
* @return
*/
static DBusHandlerResult flt_handle_messages(DBusConnection *connection, DBusMessage *message, void *user_data)
{
const char *interface_name = dbus_message_get_interface(message);
const char *member_name = dbus_message_get_member(message);
printf("##### Got Message \n%s\n%s\n", interface_name, member_name);
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
//---------------------------------------------------------------------------//
// watch
static DBusWatch * watched_watch = NULL;
static int watched_rd_fd = 0;
static int watched_wr_fd = 0;
static dbus_bool_t add_watch(DBusWatch *w, void *data)
{
if (!dbus_watch_get_enabled(w))
return TRUE;
int fd = dbus_watch_get_unix_fd(w);
unsigned int flags = dbus_watch_get_flags(w);
int old_rd_fd = watched_rd_fd;
int old_wr_fd = watched_wr_fd;
if (flags & DBUS_WATCH_READABLE)
watched_rd_fd = fd;
if (flags & DBUS_WATCH_WRITABLE)
watched_wr_fd = fd;
watched_watch = w;
printf(" WATCH: add dbus watch fd=%d watch=%p rd_fd=%d/%d wr_fd=%d/%d\n",
fd, w, watched_rd_fd, old_rd_fd, watched_wr_fd, old_wr_fd);
//watched_chgevt_send( CHGEVT_ADD_WATCH );
return TRUE;
}
static void remove_watch(DBusWatch *w, void *data)
{
watched_watch = NULL;
watched_rd_fd = 0;
watched_wr_fd = 0;
printf(" WATCH: remove dbus watch watch=%p\n", w);
}
static void toggle_watch(DBusWatch *w, void *data)
{
printf(" WATCH: toggle dbus watch watch=%p\n", w);
if (dbus_watch_get_enabled(w))
add_watch(w, data);
else
remove_watch(w, data);
}
//---------------------------------------------------------------------------//
/**
* @brief dbus_loop
* @return
*/
int flt_loop()
{
DBusError error;
DBusConnection *conn;
DBusMessage *msg;
DBusMessageIter iter;
dbus_bool_t res;
int ret = 1; // default fail
dbus_error_init (&error);
conn = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
if (!conn)
{
fprintf (stderr, "%s: %s\n", error.name, error.message);
return 1;
}
ctx.conn = conn;
dbus_connection_add_filter(conn, flt_handle_messages, NULL, NULL);
dbus_bus_add_match(conn, "type='signal',interface='"INTERFACE"'", NULL);
dbus_connection_flush(conn);
#if 0
DBusObjectPathVTable vtable;
vtable.message_function = handle_messages;
vtable.unregister_function = NULL;
res = dbus_connection_try_register_object_path(conn, OBJPATH,&vtable,NULL,&error);
#endif
#if 1
// setup watch and timeout
if (!dbus_connection_set_watch_functions(conn, add_watch, remove_watch,
toggle_watch, NULL, NULL)) {
printf(" ERROR dbus_connection_set_watch_functions() failed\n");
return ret; /* ret=1 fail */
}
/*if (!dbus_connection_set_timeout_functions(conn, add_timeout,
remove_timeout, toggle_timeout,
NULL, NULL)) {
printf(" ERROR dbus_connection_set_timeout_functions() failed\n");
return ret; // ret=1 fail
}*/
#endif
#if 1
while (1)
{
dbus_connection_read_write_dispatch(ctx.conn, 1000);
}
#endif
#if 0
// ToDo.
#endif
}
//---------------------------------------------------------------------------//
/**
* @brief main
* @param argc
* @param argv
* @return
*/
int main(int argc, char **argv)
{
// ToDo. Parse command line (e.g. start, stop commands)
flt_loop();
return 0;
}
Makefile
#PROJECT_ROOT = $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
#OBJS = portsflt.o
OBJS = test001.o
INC = -I/usr/include/dbus-1.0/ -I/usr/lib/x86_64-linux-gnu/dbus-1.0/include/
#INC = `pkg-config --cflags dbus-1`
LIBS = -L/usr/lib/x86_64-linux-gnu/ -ldbus-1
#LIBS = `pkg-config --cflags --libs dbus-1`
ifeq ($(BUILD_MODE),debug)
CXXFLAGS = $(CFLAGS) -O0 -g3 -Wall -fmessage-length=0
else ifeq ($(BUILD_MODE),run)
CXXFLAGS = $(CFLAGS) -O0 -g3 -Wall -fmessage-length=0
else
# $(error Build mode $(BUILD_MODE) not supported by this Makefile)
CXXFLAGS = $(CFLAGS) -O0 -g3 -Wall -fmessage-length=0
endif
.PHONY:all
all: portsflt
portsflt: $(OBJS)
$(CXX) -o $@ $^ $(LIBS)
.SUFFIXES: .c .cpp .o
%.o : %.cpp
$(CXX) -c $(CFLAGS) $(CXXFLAGS) $(CPPFLAGS) $(INC) -o $@ $<
%.o : %.c
$(CC) -c $(CFLAGS) $(CXXFLAGS) $(INC) -o $@ $<
clean:
rm -fr portsflt $(OBJS)
test:
echo $(LIBS)
echo $(BUILD_MODE)