LINUX.ORG.RU

Отслеживание подключения флешки

 ,


1

3

Нужно отследить момент подключения флешки. Предполагаю, что это делается через 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)

Я когдато решал такую задачу при помощи glib

cvv ★★★★★
()
Ответ на: комментарий от anonymous

Немного не то. Монтирование надо перехватить и если что дать пользователю по рукам. А в inotify_add_watch похоже уже приходит нотификация по свершившемуся факту.

bugs-bunny
() автор топика

Зачем столько всего, когда можно просто читать текст из

socket(AF_NETLINK,SOCK_DGRAM,NETLINK_KOBJECT_UEVENT);
anonymous
()
Ответ на: комментарий от anonymous

Через d-bus UDisks2 интерфейс можно зачитать так же и серийник, модель устройства. А дальше резать пользователю права в соответствии с политикой.

bugs-bunny
() автор топика
Ответ на: комментарий от anonymous

Не везде есть dbus

А поподробнее пожалуйста. Казалось DE к нему гвоздями прибиты, и в Linux вроде на этом IPC остановились.

bugs-bunny
() автор топика
Ответ на: комментарий от bugs-bunny

Он наверное про bsd(?) с вендой.

anonymous
()

Через dbus и udisks и на чистом Си я это делал когда-то. Но уже не помню ничего. Начитался, кстати, тогда кучи мата в исходниках от разработчиков enlightenment про всякие glib и прочие libdbus. В итоге у меня получилось вот это: https://sourceforge.net/projects/xmsvm/

zloy_starper ★★★
()
Ответ на: комментарий от zloy_starper

Спасибо. Кажется то что надо. Только

xmsvm.c:14:19: fatal error: Xm/Xm.h: No such file or directory
. Какой-то -dev пакет наверное пропущен. Но configure отработал и ничего не сообщил.

bugs-bunny
() автор топика
Ответ на: комментарий от bugs-bunny

Какой-то -dev пакет наверное пропущен.

Не какой-то, а libmotif-dev. Но зачем тебе Motif? Задача была отреагировать на подключение, а вывод можно просто в консоль, без каких то там «окошек».

anonymous
()
Ответ на: комментарий от anonymous

Хотелось бы глянуть как эта софтина работает. Сейчас пока несколько сот unresolved-ов. Все на printf менять? Ну не собрется или не запустится, тогда просто в исходники буду подглядывать.

libmotif-dev, libxpm-dev. И до кучи поправить Makefile https://stackoverflow.com/questions/33617367/undefined-reference-to-xtinitialize . С таким недавно сталкивался, что либу нужно линкеру подсовывать до объектников, иначе куча undefined reference.

bugs-bunny
() автор топика
Ответ на: комментарий от bugs-bunny

GUI там относительно легко можно выкинуть. Разумеется для этого надо править исходники и правила сборки. Взаимодействие с dbus, udisks там крутится в отдельном потоке. Всего лишь нужно заменить гуевый модуль на собственный, какой там нужно. Для этого, конечно, нужно потратить какое-то время. Но в свое время я вообще ничего не нашел подобного без всяких богомерзких glib/gtk. Ковырял библиотеку для enlightenment. Может её стоит посмотреть. Но там уже тогда было всего до хрена на всякие случаи жизни. А сейчас, я думаю, там все настолько обросло собственными API, что теперь вряд ли проще, чем тот же glib ковырять.

zloy_starper ★★★
()

Нужно отследить момент подключения флешки

лови через udev вместо всего вот этого вот

ananas ★★★★★
()
Ответ на: комментарий от zloy_starper

Спасибо.

Всего лишь нужно заменить гуевый модуль на собственный, какой там нужно.

Сейчас пробую...

bugs-bunny
() автор топика
Ответ на: комментарий от ananas

лови через udev вместо всего вот этого вот

Ну если только подключения, т.е. момент возникновения флэшки как устройства в системе, то почему бы нет. А вот монтирование им же не поймаешь. Да и по большому счету работа, что с udev, что с dbus/udisks на Си в общем то геморрой приблизительно одной степени тяжести. Может udev малость попроще.

zloy_starper ★★★
()
Ответ на: комментарий от zloy_starper

для ловли монтирования есть inotify. и с udev работа на порядки проще - простое правило, которое на нужном событии дернет отдельный бинарь с сишным кодом, содержащим только логику, без всякой дополнительной шелухи

ananas ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.