commit 7a09bb0557566f4ea2cc994d746483f08b5ce32c Author: illiliti Date: Sat Jul 4 09:25:16 2020 +0300 init diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..bf87ea9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,15 @@ +ISC License + +Copyright (c) 2020 illiliti + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..78877cd --- /dev/null +++ b/Makefile @@ -0,0 +1,49 @@ +# .POSIX ?? + +PREFIX = /usr/local +XCFLAGS = ${CFLAGS} -pedantic -fPIC -fvisibility=hidden \ + -D_POSIX_VERSION=200809L -D_XOPEN_SOURCE=700 -std=c99 \ + -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \ + -Wno-return-type -Wno-unused-parameter +XLDFLAGS = ${LDFLAGS} -shared -Wl,-soname,libudev.so.1 +XARFLAGS = -rc + +OBJ = \ + udev.o \ + udev_list.o \ + udev_util.o \ + udev_device.o \ + udev_monitor.o \ + udev_enumerate.o + +all: libudev.so libudev.a + +.c.o: + ${CC} ${XCFLAGS} -c -o $@ $< + +libudev.a: ${OBJ} + ${AR} ${XARFLAGS} $@ ${OBJ} + +libudev.so: ${OBJ} + ${CC} ${XCFLAGS} -o $@ ${OBJ} ${XLDFLAGS} + +install: libudev.so libudev.a + mkdir -p ${DESTDIR}${INCLUDEDIR} ${DESTDIR}${LIBDIR} + cp -f udev.h ${DESTDIR}${INCLUDEDIR}/libudev.h + chmod 0644 ${DESTDIR}${INCLUDEDIR}/libudev.h + cp -f libudev.a ${DESTDIR}${LIBDIR}/libudev.a + chmod 0644 ${DESTDIR}${LIBDIR}/libudev.a + cp -f libudev.so ${DESTDIR}${LIBDIR}/libudev.so + chmod 0755 ${DESTDIR}${LIBDIR}/libudev.so + ln -s libudev.so ${DESTDIR}${LIBDIR}/libudev.so.1 + +uninstall: + rm -f ${DESTDIR}${LIBDIR}/libudev.a \ + ${DESTDIR}${LIBDIR}/libudev.so \ + ${DESTDIR}${LIBDIR}/libudev.so.1 \ + ${DESTDIR}${INCLUDEDIR}/libudev.h + +clean: + rm -f libudev.so libudev.a ${OBJ} + +.PHONY: all clean install uninstall diff --git a/README.md b/README.md new file mode 100644 index 0000000..f77e34d --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +Nothing works here(yet), move along diff --git a/udev.c b/udev.c new file mode 100644 index 0000000..cc6a147 --- /dev/null +++ b/udev.c @@ -0,0 +1,40 @@ +#include + +#include "udev.h" + +struct udev +{ + int refcount; +}; + +UDEV_EXPORT struct udev *udev_new(void) +{ + struct udev *udev; + + udev = calloc(1, sizeof(struct udev)); + return udev; +} + +UDEV_EXPORT struct udev *udev_ref(struct udev *udev) +{ + if (!udev) { + return NULL; + } + + udev->refcount++; + return udev; +} + +UDEV_EXPORT struct udev *udev_unref(struct udev *udev) +{ + if (!udev) { + return NULL; + } + + if (--udev->refcount > 0) { + return udev; + } + + free(udev); + return NULL; +} diff --git a/udev.h b/udev.h new file mode 100644 index 0000000..83a3a9e --- /dev/null +++ b/udev.h @@ -0,0 +1,98 @@ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define UDEV_EXPORT __attribute__ ((visibility("default"))) + +#define udev_list_entry_foreach(list_entry, first_entry) \ + for (list_entry = first_entry; \ + list_entry != NULL; \ + list_entry = udev_list_entry_get_next(list_entry)) + +struct udev; +struct udev_device; +struct udev_monitor; +struct udev_enumerate; +struct udev_list_entry; + +struct udev *udev_new(void); +struct udev *udev_ref(struct udev *udev); +struct udev *udev_unref(struct udev *udev); + +const char *udev_device_get_syspath(struct udev_device *udev_device); +const char *udev_device_get_sysname(struct udev_device *udev_device); +const char *udev_device_get_sysnum(struct udev_device *udev_device); +const char *udev_device_get_devpath(struct udev_device *udev_device); +const char *udev_device_get_devnode(struct udev_device *udev_device); +dev_t udev_device_get_devnum(struct udev_device *udev_device); +const char *udev_device_get_devtype(struct udev_device *udev_device); +const char *udev_device_get_subsystem(struct udev_device *udev_device); +const char *udev_device_get_driver(struct udev_device *udev_device); +struct udev *udev_device_get_udev(struct udev_device *udev_device); +struct udev_device *udev_device_get_parent(struct udev_device *udev_device); +struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct udev_device *udev_device, const char *subsystem, const char *devtype); +int udev_device_get_is_initialized(struct udev_device *udev_device); +const char *udev_device_get_action(struct udev_device *udev_device); + +int udev_device_has_tag(struct udev_device *udev_device, const char *tag); +struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *udev_device); +struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device *udev_device); +struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_device *udev_device); +struct udev_list_entry *udev_device_get_sysattr_list_entry(struct udev_device *udev_device); +const char *udev_device_get_property_value(struct udev_device *udev_device, const char *key); +const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr); +int udev_device_set_sysattr_value(struct udev_device *udev_device, const char *sysattr, const char *value); + +struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath); +struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, dev_t devnum); +struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname); +struct udev_device *udev_device_new_from_device_id(struct udev *udev, const char *id); +struct udev_device *udev_device_new_from_environment(struct udev *udev); +struct udev_device *udev_device_ref(struct udev_device *udev_device); +struct udev_device *udev_device_unref(struct udev_device *udev_device); + +int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem); +int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem); +int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value); +int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value); +int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value); +int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname); +int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const char *tag); +int udev_enumerate_add_match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *parent); +int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev_enumerate); + +int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate); +int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate); +struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate); +int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath); +struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate); + +struct udev_enumerate *udev_enumerate_new(struct udev *udev); +struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate); +struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate *udev_enumerate); + +struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry); +struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_entry *list_entry, const char *name); +const char *udev_list_entry_get_name(struct udev_list_entry *list_entry); +const char *udev_list_entry_get_value(struct udev_list_entry *list_entry); + +struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor); +int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor); +int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int size); +int udev_monitor_get_fd(struct udev_monitor *udev_monitor); +struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor); + +int udev_monitor_filter_update(struct udev_monitor *udev_monitor); +int udev_monitor_filter_remove(struct udev_monitor *udev_monitor); +int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, const char *subsystem, const char *devtype); +int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag); + +struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name); +struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor); +struct udev_monitor *udev_monitor_unref(struct udev_monitor *udev_monitor); + +#ifdef __cplusplus +} +#endif diff --git a/udev_device.c b/udev_device.c new file mode 100644 index 0000000..42f9b5d --- /dev/null +++ b/udev_device.c @@ -0,0 +1,643 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "udev.h" +#include "udev_list.h" +#include "udev_util.h" +#include "udev_device.h" + +struct udev_device +{ + struct udev_list_entry properties; + struct udev_list_entry sysattrs; + struct udev_device *parent; + struct udev *udev; + char *subsystem; + char *syspath; + char *sysname; + char *devpath; + char *devnode; + char *devtype; + char *driver; + char *sysnum; + dev_t devnum; + int refcount; +}; + +UDEV_EXPORT const char *udev_device_get_syspath(struct udev_device *udev_device) +{ + if (!udev_device) { + return NULL; + } + + return udev_device->syspath; +} + +UDEV_EXPORT const char *udev_device_get_sysname(struct udev_device *udev_device) +{ + if (!udev_device) { + return NULL; + } + + return udev_device->sysname; +} + +UDEV_EXPORT const char *udev_device_get_sysnum(struct udev_device *udev_device) +{ + if (!udev_device) { + return NULL; + } + + return udev_device->sysnum; +} + +UDEV_EXPORT const char *udev_device_get_devpath(struct udev_device *udev_device) +{ + if (!udev_device) { + return NULL; + } + + return udev_device->devpath; +} + +UDEV_EXPORT const char *udev_device_get_devnode(struct udev_device *udev_device) +{ + if (!udev_device) { + return NULL; + } + + return udev_device->devnode; +} + +UDEV_EXPORT dev_t udev_device_get_devnum(struct udev_device *udev_device) +{ + if (!udev_device) { + return makedev(0, 0); + } + + return udev_device->devnum; +} + +UDEV_EXPORT const char *udev_device_get_devtype(struct udev_device *udev_device) +{ + if (!udev_device) { + return NULL; + } + + return udev_device->devtype; +} + +UDEV_EXPORT const char *udev_device_get_subsystem(struct udev_device *udev_device) +{ + if (!udev_device) { + return NULL; + } + + return udev_device->subsystem; +} + +UDEV_EXPORT const char *udev_device_get_driver(struct udev_device *udev_device) +{ + if (!udev_device) { + return NULL; + } + + return udev_device->driver; +} + +UDEV_EXPORT struct udev *udev_device_get_udev(struct udev_device *udev_device) +{ + if (!udev_device) { + return NULL; + } + + return udev_device->udev; +} + +UDEV_EXPORT struct udev_device *udev_device_get_parent(struct udev_device *udev_device) +{ + char *path; + int slash; + + if (!udev_device) { + return NULL; + } + + path = strdup(udev_device->syspath); + + while (1) { + slash = strrchr(path, '/') - path; + + if (!slash) { + free(path); + return NULL; + } + + path[slash] = '\0'; + + udev_device->parent = udev_device_new_from_syspath(udev_device->udev, path); + + if (udev_device->parent) { + free(path); + return udev_device->parent; + } + } +} + +UDEV_EXPORT struct udev_device *udev_device_get_parent_with_subsystem_devtype(struct udev_device *udev_device, const char *subsystem, const char *devtype) +{ + const char *parent_subsystem, *parent_devtype; + struct udev_device *parent; + + if (!udev_device || !subsystem) { + return NULL; + } + + while ((parent = udev_device_get_parent(udev_device))) { + parent_subsystem = udev_device_get_subsystem(parent); + parent_devtype = udev_device_get_devtype(parent); + + if (parent_subsystem && strcmp(parent_subsystem, subsystem) == 0) { + if (!devtype) { + return parent; + } + + if (parent_devtype && strcmp(parent_devtype, devtype) == 0) { + return parent; + } + } + } + + return NULL; +} + +UDEV_EXPORT int udev_device_get_is_initialized(struct udev_device *udev_device) +{ + return 1; +} + +UDEV_EXPORT const char *udev_device_get_action(struct udev_device *udev_device) +{ + return NULL; +} + +UDEV_EXPORT int udev_device_has_tag(struct udev_device *udev_device, const char *tag) +{ + // XXX NOT IMPLEMENTED + return 0; +} + +UDEV_EXPORT struct udev_list_entry *udev_device_get_devlinks_list_entry(struct udev_device *udev_device) +{ + // XXX NOT IMPLEMENTED + return NULL; +} + +UDEV_EXPORT struct udev_list_entry *udev_device_get_properties_list_entry(struct udev_device *udev_device) +{ + if (!udev_device) { + return NULL; + } + + return &udev_device->properties; +} + +UDEV_EXPORT struct udev_list_entry *udev_device_get_tags_list_entry(struct udev_device *udev_device) +{ + // XXX NOT IMPLEMENTED + return NULL; +} + +UDEV_EXPORT struct udev_list_entry *udev_device_get_sysattr_list_entry(struct udev_device *udev_device) +{ + if (!udev_device) { + return NULL; + } + + return &udev_device->sysattrs; +} + +UDEV_EXPORT const char *udev_device_get_property_value(struct udev_device *udev_device, const char *key) +{ +} + +UDEV_EXPORT const char *udev_device_get_sysattr_value(struct udev_device *udev_device, const char *sysattr) +{ + struct udev_list_entry *list_entry; + char data[1024], *path = NULL; + struct stat st; + ssize_t len; + int fd; + + if (!udev_device || !sysattr) { + return NULL; + } + + list_entry = udev_list_entry_get_by_name(&udev_device->sysattrs, sysattr); + + if (list_entry) { + return udev_list_entry_get_value(list_entry); + } + + if (xasprintf(path, "%s/%s", udev_device->syspath, sysattr) == -1) { + return NULL; + } + + if (stat(path, &st) != 0 || S_ISDIR(st.st_mode)) { + free(path); + return NULL; + } + + fd = open(path, O_RDONLY); + + if (fd == -1) { + free(path); + return NULL; + } + + len = read(fd, data, sizeof(data)); + + if (len == -1) { + close(fd); + free(path); + return NULL; + } + + close(fd); + free(path); + data[len] = '\0'; + list_entry = udev_list_entry_add(&udev_device->sysattrs, sysattr, data); + return udev_list_entry_get_value(list_entry); +} + +UDEV_EXPORT int udev_device_set_sysattr_value(struct udev_device *udev_device, const char *sysattr, const char *value) +{ + size_t len = strlen(value); + char *path = NULL; + struct stat st; + int fd; + + if (!udev_device || !sysattr || !value) { + return -1; + } + + if (xasprintf(path, "%s/%s", udev_device->syspath, sysattr) == -1) { + return -1; + } + + if (stat(path, &st) != 0 || S_ISDIR(st.st_mode)) { + free(path); + return -1; + } + + fd = open(path, O_WRONLY | O_NOFOLLOW); + + if (fd == -1) { + free(path); + return -1; + } + + if (write(fd, value, len) == -1) { + close(fd); + free(path); + return -1; + } + + close(fd); + free(path); + udev_list_entry_add(&udev_device->sysattrs, sysattr, value); + return 0; +} + +char *udev_device_read_uevent(struct udev_device *udev_device, const char *name) +{ + char *line, *path = NULL, *data = NULL; + size_t nlen = strlen(name), glen = 0; + FILE *file; + + if (xasprintf(path, "%s/%s", udev_device->syspath, "uevent") == -1) { + return NULL; + } + + file = fopen(path, "r"); + + if (!file) { + free(path); + return NULL; + } + + while (getline(&line, &glen, file) != -1) { + if (strncmp(line, name, nlen) == 0) { + data = strdup(line + nlen); + break; + } + } + + fclose(file); + free(line); + free(path); + return data; +} + +char *udev_device_read_symlink(struct udev_device *udev_device, const char *name) +{ + char *link, *data, *path = NULL; + + if (xasprintf(path, "%s/%s", udev_device->syspath, name) == -1) { + return NULL; + } + + link = realpath(path, NULL); // XXX XSI + + if (!link) { + free(path); + return NULL; + } + + data = strdup(strrchr(link, '/') + 1); + free(path); + free(link); + return data; +} + +void udev_device_set_subsystem(struct udev_device *udev_device) +{ + char *subsystem; + + udev_device->subsystem = NULL; + + subsystem = udev_device_read_symlink(udev_device, "subsystem"); + + if (!subsystem) { + return; + } + + udev_device->subsystem = subsystem; +} + +void udev_device_set_sysname(struct udev_device *udev_device) +{ + char *devname, *sysname; + + udev_device->sysname = NULL; + + devname = udev_device_read_uevent(udev_device, "DEVNAME="); + + if (!devname) { + return; + } + + sysname = strrchr(devname, '/'); + + if (!sysname) { + sysname = devname; + } + else { + sysname++; + } + + udev_device->sysname = strdup(sysname); + free(devname); +} + +void udev_device_set_devnode(struct udev_device *udev_device) +{ + char *devname, *devnode = NULL; + + udev_device->devnode = NULL; + + devname = udev_device_read_uevent(udev_device, "DEVNAME="); + + if (!devname) { + return; + } + + if (xasprintf(devnode, "/dev/%s", devname) == -1) { + free(devname); + return; + } + + udev_device->devnode = devnode; + free(devname); +} + +void udev_device_set_devtype(struct udev_device *udev_device) +{ + char *devtype; + + udev_device->devtype = NULL; + + devtype = udev_device_read_uevent(udev_device, "DEVTYPE="); + + if (!devtype) { + return; + } + + udev_device->devtype = devtype; +} + +void udev_device_set_driver(struct udev_device *udev_device) +{ + char *driver; + + udev_device->driver = NULL; + + driver = udev_device_read_symlink(udev_device, "driver"); + + if (!driver) { + return; + } + + udev_device->driver = driver; +} + +void udev_device_set_devnum(struct udev_device *udev_device) +{ + char *major, *minor; + + udev_device->devnum = makedev(0, 0); + + major = udev_device_read_uevent(udev_device, "MAJOR="); + minor = udev_device_read_uevent(udev_device, "MINOR="); + + if (!major && !minor) { + return; + } + + udev_device->devnum = makedev(atoi(major), atoi(minor)); + free(major); + free(minor); +} + +void udev_device_set_sysnum(struct udev_device *udev_device) +{ + int i; + + udev_device->sysnum = NULL; + + if (!udev_device->sysname) { + return; + } + + for (i = 0; udev_device->sysname[i] != '\0'; i++) { + if (udev_device->sysname[i] >= '0' && + udev_device->sysname[i] <= '9') { + udev_device->sysnum = strdup(udev_device->sysname + i); + return; + } + } +} + +void udev_device_set_properties(struct udev_device *udev_device) +{ +} + +UDEV_EXPORT struct udev_device *udev_device_new_from_syspath(struct udev *udev, const char *syspath) +{ + struct udev_device *udev_device; + char *path, *file = NULL; + struct stat st; + + if (!udev || !syspath) { + return NULL; + } + + path = realpath(syspath, NULL); // XXX XSI + + if (!path) { + return NULL; + } + + if (stat(path, &st) != 0 || S_ISDIR(st.st_mode) == 0) { + free(path); + return NULL; + } + + if (xasprintf(file, "%s/%s", path, "uevent") == -1) { + free(path); + return NULL; + } + + if (access(file, R_OK) == -1) { + free(file); + free(path); + return NULL; + } + + free(file); + + udev_device = calloc(1, sizeof(struct udev_device)); + + if (!udev_device) { + free(path); + return NULL; + } + + udev_device->udev = udev; + udev_device->refcount = 1; + udev_device->syspath = path; + udev_device->devpath = strdup(path + 4); + + udev_list_entry_init(&udev_device->properties); + udev_list_entry_init(&udev_device->sysattrs); + + udev_device_set_properties(udev_device); + udev_device_set_subsystem(udev_device); + udev_device_set_sysname(udev_device); + udev_device_set_devnode(udev_device); + udev_device_set_devtype(udev_device); + udev_device_set_driver(udev_device); + udev_device_set_sysnum(udev_device); + udev_device_set_devnum(udev_device); + + return udev_device; +} + +UDEV_EXPORT struct udev_device *udev_device_new_from_devnum(struct udev *udev, char type, dev_t devnum) +{ + struct udev_device *udev_device; + char *path = NULL; + + if (!udev || !type || !devnum) { + return NULL; + } + + switch (type) { + case 'c': + xasprintf(path, "/sys/dev/char/%d:%d", major(devnum), minor(devnum)); + break; + case 'b': + xasprintf(path, "/sys/dev/block/%d:%d", major(devnum), minor(devnum)); + break; + default: + return NULL; + } + + udev_device = udev_device_new_from_syspath(udev, path); + + free(path); + return udev_device; +} + +UDEV_EXPORT struct udev_device *udev_device_new_from_subsystem_sysname(struct udev *udev, const char *subsystem, const char *sysname) +{ + // XXX NOT IMPLEMENTED + return NULL; +} + +UDEV_EXPORT struct udev_device *udev_device_new_from_device_id(struct udev *udev, const char *id) +{ + // XXX NOT IMPLEMENTED + return NULL; +} + +UDEV_EXPORT struct udev_device *udev_device_new_from_environment(struct udev *udev) +{ + // XXX NOT IMPLEMENTED + return NULL; +} + +UDEV_EXPORT struct udev_device *udev_device_ref(struct udev_device *udev_device) +{ + if (!udev_device) { + return NULL; + } + + udev_device->refcount++; + return udev_device; +} + +UDEV_EXPORT struct udev_device *udev_device_unref(struct udev_device *udev_device) +{ + if (!udev_device) { + return NULL; + } + + if (--udev_device->refcount > 0) { + return NULL; + } + + if (udev_device->parent) { + udev_device_unref(udev_device->parent); + } + + udev_list_entry_free_all(&udev_device->properties); + udev_list_entry_free_all(&udev_device->sysattrs); + + free(udev_device->subsystem); + free(udev_device->syspath); + free(udev_device->devpath); + free(udev_device->sysname); + free(udev_device->devnode); + free(udev_device->devtype); + free(udev_device->driver); + free(udev_device->sysnum); + free(udev_device); + + return NULL; +} diff --git a/udev_device.h b/udev_device.h new file mode 100644 index 0000000..766cb80 --- /dev/null +++ b/udev_device.h @@ -0,0 +1,10 @@ +char *udev_device_read_uevent(struct udev_device *udev_device, const char *name); +char *udev_device_read_symlink(struct udev_device *udev_device, const char *name); +void udev_device_set_properties(struct udev_device *udev_device); +void udev_device_set_subsystem(struct udev_device *udev_device); +void udev_device_set_sysname(struct udev_device *udev_device); +void udev_device_set_devnode(struct udev_device *udev_device); +void udev_device_set_devtype(struct udev_device *udev_device); +void udev_device_set_driver(struct udev_device *udev_device); +void udev_device_set_sysnum(struct udev_device *udev_device); +void udev_device_set_devnum(struct udev_device *udev_device); diff --git a/udev_enumerate.c b/udev_enumerate.c new file mode 100644 index 0000000..9e8d57e --- /dev/null +++ b/udev_enumerate.c @@ -0,0 +1,162 @@ +#include + +#include "udev.h" +#include "udev_list.h" + +struct udev_enumerate +{ + struct udev_list_entry subsystem_nomatch; + struct udev_list_entry subsystem_match; + struct udev_list_entry sysattr_nomatch; + struct udev_list_entry property_match; + struct udev_list_entry sysattr_match; + struct udev_list_entry sysname_match; + struct udev_list_entry devices; + struct udev *udev; + int refcount; +}; + +UDEV_EXPORT int udev_enumerate_add_match_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) +{ + if (!udev_enumerate || !subsystem) { + return -1; + } + + return udev_list_entry_add(&udev_enumerate->subsystem_match, subsystem, NULL) ? 0 : -1; +} + +UDEV_EXPORT int udev_enumerate_add_nomatch_subsystem(struct udev_enumerate *udev_enumerate, const char *subsystem) +{ + if (!udev_enumerate || !subsystem) { + return -1; + } + + return udev_list_entry_add(&udev_enumerate->subsystem_nomatch, subsystem, NULL) ? 0 : -1; +} + +UDEV_EXPORT int udev_enumerate_add_match_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value) +{ + if (!udev_enumerate || !sysattr) { + return -1; + } + + return udev_list_entry_add(&udev_enumerate->sysattr_match, sysattr, value) ? 0 : -1; +} + +UDEV_EXPORT int udev_enumerate_add_nomatch_sysattr(struct udev_enumerate *udev_enumerate, const char *sysattr, const char *value) +{ + if (!udev_enumerate || !sysattr) { + return -1; + } + + return udev_list_entry_add(&udev_enumerate->sysattr_nomatch, sysattr, value) ? 0 : -1; +} + +UDEV_EXPORT int udev_enumerate_add_match_property(struct udev_enumerate *udev_enumerate, const char *property, const char *value) +{ + if (!udev_enumerate || !property) { + return -1; + } + + return udev_list_entry_add(&udev_enumerate->property_match, property, value) ? 0 : -1; +} + +UDEV_EXPORT int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumerate, const char *sysname) +{ + if (!udev_enumerate || !sysname) { + return -1; + } + + return udev_list_entry_add(&udev_enumerate->sysname_match, sysname, NULL) ? 0 : -1; +} + +UDEV_EXPORT int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate, const char *tag) +{ + // XXX NOT IMPLEMENTED + return 0; +} + +UDEV_EXPORT int udev_enumerate_add_match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *parent) +{ + // XXX NOT IMPLEMENTED + return 0; +} + +UDEV_EXPORT int udev_enumerate_add_match_is_initialized(struct udev_enumerate *udev_enumerate) +{ + return 0; +} + +UDEV_EXPORT int udev_enumerate_scan_devices(struct udev_enumerate *udev_enumerate) +{ +} + +UDEV_EXPORT int udev_enumerate_scan_subsystems(struct udev_enumerate *udev_enumerate) +{ +} + +UDEV_EXPORT struct udev_list_entry *udev_enumerate_get_list_entry(struct udev_enumerate *udev_enumerate) +{ + if (!udev_enumerate) { + return NULL; + } + + return &udev_enumerate->devices; +} + +UDEV_EXPORT int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath) +{ + // XXX NOT IMPLEMENTED + return 0; +} + +UDEV_EXPORT struct udev *udev_enumerate_get_udev(struct udev_enumerate *udev_enumerate) +{ + if (!udev_enumerate) { + return NULL; + } + + return udev_enumerate->udev; +} + +UDEV_EXPORT struct udev_enumerate *udev_enumerate_new(struct udev *udev) +{ + struct udev_enumerate *udev_enumerate; + + if (!udev) { + return NULL; + } + + udev_enumerate = calloc(1, sizeof(struct udev_enumerate)); + + if (!udev_enumerate) { + return NULL; + } + + udev_enumerate->refcount = 1; + udev_enumerate->udev = udev; + + udev_list_entry_init(&udev_enumerate->subsystem_nomatch); + udev_list_entry_init(&udev_enumerate->subsystem_match); + udev_list_entry_init(&udev_enumerate->sysattr_nomatch); + udev_list_entry_init(&udev_enumerate->property_match); + udev_list_entry_init(&udev_enumerate->sysattr_match); + udev_list_entry_init(&udev_enumerate->sysname_match); + udev_list_entry_init(&udev_enumerate->devices); + + return udev_enumerate; +} + +UDEV_EXPORT struct udev_enumerate *udev_enumerate_ref(struct udev_enumerate *udev_enumerate) +{ + if (!udev_enumerate) { + return NULL; + } + + udev_enumerate->refcount++; + return udev_enumerate; +} + +UDEV_EXPORT struct udev_enumerate *udev_enumerate_unref(struct udev_enumerate *udev_enumerate) +{ +} diff --git a/udev_list.c b/udev_list.c new file mode 100644 index 0000000..a3f2f7f --- /dev/null +++ b/udev_list.c @@ -0,0 +1,109 @@ +#include +#include + +#include "udev.h" +#include "udev_list.h" + +void udev_list_entry_init(struct udev_list_entry *list_entry) +{ + list_entry->value = NULL; + list_entry->name = NULL; + list_entry->next = NULL; +} + +void udev_list_entry_free(struct udev_list_entry *list_entry) +{ + free(list_entry->value); + free(list_entry->name); + free(list_entry); +} + +void udev_list_entry_free_all(struct udev_list_entry *list_entry) +{ + struct udev_list_entry *tmp, *tmp2; + + tmp = list_entry; + + while (tmp) { + tmp2 = tmp; + tmp = tmp->next; + udev_list_entry_free(tmp2); + } +} + +struct udev_list_entry *udev_list_entry_add(struct udev_list_entry *list_entry, const char *name, const char *value) +{ + struct udev_list_entry *new, *old; + + old = udev_list_entry_get_by_name(list_entry, name); + + if (old) { + free(old->value); + old->value = strdup(value); + return old; + } + + new = calloc(1, sizeof(struct udev_list_entry)); + + if (!new) { + return NULL; + } + + udev_list_entry_init(new); + + new->value = value ? strdup(value) : NULL; + new->name = strdup(name); + + new->next = list_entry->next; + list_entry->next = new; + + return new; +} + +UDEV_EXPORT struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry) +{ + if (!list_entry) { + return NULL; + } + + return list_entry->next; +} + +UDEV_EXPORT struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_entry *list_entry, const char *name) +{ + struct udev_list_entry *tmp; + + if (!list_entry || !name) { + return NULL; + } + + tmp = list_entry; + + while (tmp) { + if (strcmp(tmp->name, name) == 0) { + return tmp; + } + + tmp = tmp->next; + } + + return NULL; +} + +UDEV_EXPORT const char *udev_list_entry_get_name(struct udev_list_entry *list_entry) +{ + if (!list_entry) { + return NULL; + } + + return list_entry->name; +} + +UDEV_EXPORT const char *udev_list_entry_get_value(struct udev_list_entry *list_entry) +{ + if (!list_entry) { + return NULL; + } + + return list_entry->value; +} diff --git a/udev_list.h b/udev_list.h new file mode 100644 index 0000000..370f636 --- /dev/null +++ b/udev_list.h @@ -0,0 +1,11 @@ +struct udev_list_entry +{ + struct udev_list_entry *next; + char *value; + char *name; +}; + +void udev_list_entry_init(struct udev_list_entry *list_entry); +void udev_list_entry_free(struct udev_list_entry *list_entry); +void udev_list_entry_free_all(struct udev_list_entry *list_entry); +struct udev_list_entry *udev_list_entry_add(struct udev_list_entry *list_entry, const char *name, const char *value); diff --git a/udev_monitor.c b/udev_monitor.c new file mode 100644 index 0000000..bc2f375 --- /dev/null +++ b/udev_monitor.c @@ -0,0 +1,125 @@ +#include +#include +#include + +#include "udev.h" + +struct udev_monitor +{ + struct udev *udev; + int refcount; + int fd[2]; +}; + +UDEV_EXPORT struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor) +{ + return (void *)1; +} + +UDEV_EXPORT int udev_monitor_enable_receiving(struct udev_monitor *udev_monitor) +{ + return 0; +} + +UDEV_EXPORT int udev_monitor_set_receive_buffer_size(struct udev_monitor *udev_monitor, int size) +{ + return 0; +} + +UDEV_EXPORT int udev_monitor_get_fd(struct udev_monitor *udev_monitor) +{ + if (!udev_monitor) { + return -1; + } + + return udev_monitor->fd[0]; +} + +UDEV_EXPORT struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor) +{ + if (!udev_monitor) { + return NULL; + } + + return udev_monitor->udev; +} + +UDEV_EXPORT int udev_monitor_filter_update(struct udev_monitor *udev_monitor) +{ + return 0; +} + +UDEV_EXPORT int udev_monitor_filter_remove(struct udev_monitor *udev_monitor) +{ + return 0; +} + +UDEV_EXPORT int udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, const char *subsystem, const char *devtype) +{ + return 0; +} + +UDEV_EXPORT int udev_monitor_filter_add_match_tag(struct udev_monitor *udev_monitor, const char *tag) +{ + return 0; +} + +UDEV_EXPORT struct udev_monitor *udev_monitor_new_from_netlink(struct udev *udev, const char *name) +{ + struct udev_monitor *udev_monitor; + int i; + + if (!udev || !name) { + return NULL; + } + + udev_monitor = calloc(1, sizeof(struct udev_monitor)); + + if (!udev_monitor) { + return NULL; + } + + // TODO better no-op, HELP WANTED ! + if (pipe(udev_monitor->fd) == -1) { + free(udev_monitor); + return NULL; + } + + for (i = 0; i < 2; i++) { + fcntl(udev_monitor->fd[i], F_SETFD, FD_CLOEXEC | O_NONBLOCK); + } + + udev_monitor->refcount = 1; + udev_monitor->udev = udev; + return udev_monitor; +} + +UDEV_EXPORT struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor) +{ + if (!udev_monitor) { + return NULL; + } + + udev_monitor->refcount++; + return udev_monitor; +} + +UDEV_EXPORT struct udev_monitor *udev_monitor_unref(struct udev_monitor *udev_monitor) +{ + int i; + + if (!udev_monitor) { + return NULL; + } + + if (--udev_monitor->refcount > 0) { + return NULL; + } + + for (i = 0; i < 2; i++) { + close(udev_monitor->fd[i]); + } + + free(udev_monitor); + return NULL; +} diff --git a/udev_util.c b/udev_util.c new file mode 100644 index 0000000..28d07d9 --- /dev/null +++ b/udev_util.c @@ -0,0 +1,37 @@ +#include +#include +#include + +#include "udev_util.h" +#include "udev.h" + +int xasprintf(char *str, const char *fmt, ...) +{ + va_list list; + int len; + + va_start(list, fmt); + len = vsnprintf(NULL, 0, fmt, list); + va_end(list); + + if (len == -1) { + return -1; + } + + str = malloc(len + 1); + + if (!str) { + return -1; + } + + len = vsnprintf(str, len + 1, fmt, list); + + if (len == -1) { + free(str); + return -1; + } + + return len; +} + +// TODO readlink+malloc diff --git a/udev_util.h b/udev_util.h new file mode 100644 index 0000000..583a347 --- /dev/null +++ b/udev_util.h @@ -0,0 +1 @@ +int xasprintf(char *str, const char *fmt, ...);