Skip to content

Commit

Permalink
Allow invoking helper script as a replacement for udev rules
Browse files Browse the repository at this point in the history
  • Loading branch information
Ella-0 committed Jul 13, 2024
1 parent bbeb7ad commit 18af5d2
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 12 deletions.
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@

PREFIX = /usr/local
LIBDIR = ${PREFIX}/lib
LIBEXECDIR = ${PREFIX}/libexec
INCLUDEDIR = ${PREFIX}/include
PKGCONFIGDIR = ${LIBDIR}/pkgconfig
RULES_HELPER_PATH=${LIBEXECDIR}/libudev-zero-rules-helper
XCFLAGS = ${CPPFLAGS} ${CFLAGS} -std=c99 -fPIC -D_XOPEN_SOURCE=700 \
-Wall -Wextra -Wpedantic -Wmissing-prototypes -Wstrict-prototypes \
-Wno-unused-parameter
-Wno-unused-parameter \
-DRULES_HELPER_PATH=\"${RULES_HELPER_PATH}\"
XLDFLAGS = ${LDFLAGS} -shared -Wl,-soname,libudev.so.1
XARFLAGS = -rc
AR = ar
Expand Down
124 changes: 113 additions & 11 deletions udev_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,16 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include <assert.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <spawn.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <linux/input.h>

#include "udev.h"
Expand Down Expand Up @@ -52,6 +56,18 @@
#define INPUT_PROP_CNT 0x20
#endif

#ifndef RULES_HELPER_PATH
#error "RULES_HELPER_PATH not specified"
#endif

#ifndef UEVENT_NUM_ENVP
#define UEVENT_NUM_ENVP 64
#endif

#ifndef UEVENT_BUFFER_SIZE
#define UEVENT_BUFFER_SIZE 2048
#endif

struct udev_device {
struct udev_list_entry properties;
struct udev_list_entry sysattrs;
Expand Down Expand Up @@ -349,19 +365,10 @@ static char *read_symlink(const char *syspath, const char *name)
return strdup(strrchr(link, '/') + 1);
}

static int set_properties_from_uevent(struct udev_device *udev_device, const char *syspath)
static void set_properties_from_file(struct udev_device *udev_device, FILE *file)
{
char line[LINE_MAX], path[PATH_MAX + sizeof("/uevent")], devnode[PATH_MAX];
FILE *file;
char line[LINE_MAX], devnode[PATH_MAX];
char *pos;

snprintf(path, sizeof(path), "%s/uevent", syspath);
file = fopen(path, "r");

if (!file) {
return -1;
}

while (fgets(line, sizeof(line), file)) {
line[strlen(line) - 1] = '\0';

Expand All @@ -374,7 +381,21 @@ static int set_properties_from_uevent(struct udev_device *udev_device, const cha
udev_list_entry_add(&udev_device->properties, line, pos + 1, 0);
}
}
}

static int set_properties_from_uevent(struct udev_device *udev_device, const char *syspath)
{
char path[PATH_MAX + sizeof("/uevent")];
FILE *file;

snprintf(path, sizeof(path), "%s/uevent", syspath);
file = fopen(path, "r");

if (!file) {
return -1;
}

set_properties_from_file(udev_device, file);
fclose(file);
return 0;
}
Expand Down Expand Up @@ -540,6 +561,85 @@ static void set_properties_from_props(struct udev_device *udev_device)
udev_list_entry_add(&udev_device->properties, "ID_PATH", id, 0);
}

static int set_properties_from_helper(struct udev_device *udev_device)
{
char *envp[UEVENT_NUM_ENVP];
char env[UEVENT_BUFFER_SIZE];

size_t env_offset = 0;
size_t env_idx = 0;
struct udev_list_entry *entry;

for (entry = udev_device_get_properties_list_entry(udev_device);
entry;
entry = udev_list_entry_get_next(entry)) {
const char *name = entry->name;
const char *value = entry->value ? entry->value : "";

// '{name}={value}\0'
size_t max_size = strlen(name) + 1 + strlen(value) + 1;

assert(env_offset + max_size < UEVENT_BUFFER_SIZE);
snprintf(&env[env_offset], max_size, "%s=%s", name, value);

assert(env_idx < UEVENT_NUM_ENVP);
envp[env_idx] = &env[env_offset];

env_offset += max_size;
env_idx++;
}

assert(env_idx < UEVENT_NUM_ENVP);
envp[env_idx] = NULL;

int out_pipe[2];

if (pipe2(out_pipe, O_CLOEXEC)) {
return -1;
}

int null_fd = open("/dev/null", O_CLOEXEC | O_RDWR);

if (null_fd < 0) {
return -1;
}

posix_spawn_file_actions_t actions;

posix_spawn_file_actions_init(&actions);
posix_spawn_file_actions_addclose(&actions, out_pipe[0]);
posix_spawn_file_actions_adddup2(&actions, null_fd, 0);
posix_spawn_file_actions_adddup2(&actions, out_pipe[1], 1);
posix_spawn_file_actions_adddup2(&actions, null_fd, 2);
posix_spawn_file_actions_addclose(&actions, out_pipe[1]);

pid_t pid;

char argv0[] = RULES_HELPER_PATH;
char *argv[] = { argv0, NULL };

if (posix_spawn(&pid, argv0, &actions, NULL, argv, envp)) {
return -1;
}

posix_spawn_file_actions_destroy(&actions);
close(out_pipe[1]);
close(null_fd);

FILE *file = fdopen(out_pipe[0], "r");

if (!file) {
return -1;
}

set_properties_from_file(udev_device, file);

int status;
waitpid(pid, &status, 0);
fclose(file);
return 0;
}

struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath)
{
char *subsystem, *driver, *sysname;
Expand Down Expand Up @@ -593,6 +693,7 @@ struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *

set_properties_from_evdev(udev_device);
set_properties_from_props(udev_device);
set_properties_from_helper(udev_device);

free(driver);
free(subsystem);
Expand Down Expand Up @@ -712,6 +813,7 @@ struct udev_device *udev_device_new_from_uevent(struct udev *udev, char *buf, si

set_properties_from_props(udev_device);
set_properties_from_evdev(udev_device);
set_properties_from_helper(udev_device);
return udev_device;
}

Expand Down

0 comments on commit 18af5d2

Please sign in to comment.