mirror of
https://github.com/systemd/systemd.git
synced 2024-10-28 03:25:31 +03:00
libudev: add udev event monitor API
This commit is contained in:
parent
530fc1f526
commit
ba6929f669
7
NEWS
7
NEWS
@ -2,6 +2,13 @@ udev 127
|
||||
========
|
||||
Bugfixes.
|
||||
|
||||
A shared library "libudev" will be installed now, to access udev
|
||||
device information. DeviceKit, the successor of HAL, will need this
|
||||
library to access the udev database and search sysfs for devices.
|
||||
The library is currently in an experimental state, also the API is
|
||||
expected to change, as long as the DeviceKit integration isn't
|
||||
finished.
|
||||
|
||||
udev 126
|
||||
========
|
||||
We use ./configure now. See INSTALL for details. Current
|
||||
|
@ -24,6 +24,7 @@ libudev_la_SOURCES =\
|
||||
libudev-utils.c \
|
||||
libudev-device.c \
|
||||
libudev-enumerate.c \
|
||||
libudev-monitor.c \
|
||||
../list.h \
|
||||
../udev.h \
|
||||
../udev_utils.c \
|
||||
|
@ -15,3 +15,9 @@ udev_device_get_subsystem
|
||||
udev_device_get_devlinks
|
||||
udev_device_get_properties
|
||||
udev_devices_enumerate
|
||||
udev_monitor_new_from_socket
|
||||
udev_monitor_ref
|
||||
udev_monitor_unref
|
||||
udev_monitor_get_udev
|
||||
udev_monitor_get_fd
|
||||
udev_monitor_get_device
|
||||
|
@ -32,16 +32,22 @@
|
||||
#include "libudev-private.h"
|
||||
#include "../udev.h"
|
||||
|
||||
static struct udev_device *device_init(struct udev *udev)
|
||||
struct udev_device *device_init(struct udev *udev)
|
||||
{
|
||||
struct udev_device *udev_device;
|
||||
|
||||
if (udev == NULL)
|
||||
return NULL;
|
||||
|
||||
udev_device = malloc(sizeof(struct udev_device));
|
||||
if (udev_device == NULL)
|
||||
return NULL;
|
||||
memset(udev_device, 0x00, sizeof(struct udev_device));
|
||||
udev_device->refcount = 1;
|
||||
udev_device->udev = udev;
|
||||
INIT_LIST_HEAD(&udev_device->link_list);
|
||||
INIT_LIST_HEAD(&udev_device->env_list);
|
||||
log_info(udev_device->udev, "udev_device: %p created\n", udev_device);
|
||||
return udev_device;
|
||||
}
|
||||
|
||||
@ -64,8 +70,15 @@ struct udev_device *udev_device_new_from_devpath(struct udev *udev, const char *
|
||||
char path[PATH_SIZE];
|
||||
struct stat statbuf;
|
||||
struct udev_device *udev_device;
|
||||
struct udevice *udevice;
|
||||
struct name_entry *name_loop;
|
||||
int err;
|
||||
|
||||
if (udev == NULL)
|
||||
return NULL;
|
||||
if (devpath == NULL)
|
||||
return NULL;
|
||||
|
||||
strlcpy(path, udev_get_sys_path(udev), sizeof(path));
|
||||
strlcat(path, devpath, sizeof(path));
|
||||
if (stat(path, &statbuf) != 0)
|
||||
@ -77,20 +90,38 @@ struct udev_device *udev_device_new_from_devpath(struct udev *udev, const char *
|
||||
if (udev_device == NULL)
|
||||
return NULL;
|
||||
|
||||
udev_device->udevice = udev_device_init(NULL);
|
||||
if (udev_device->udevice == NULL) {
|
||||
udevice = udev_device_init(NULL);
|
||||
if (udevice == NULL) {
|
||||
free(udev_device);
|
||||
return NULL;
|
||||
}
|
||||
log_info(udev, "device %p created\n", udev_device);
|
||||
|
||||
/* resolve possible symlink to real path */
|
||||
strlcpy(path, devpath, sizeof(path));
|
||||
sysfs_resolve_link(path, sizeof(path));
|
||||
udev_device->devpath = strdup(path);
|
||||
log_info(udev, "device %p has devpath '%s'\n", udev_device, udev_device_get_devpath(udev_device));
|
||||
|
||||
err = udev_db_get_device(udev_device->udevice, path);
|
||||
err = udev_db_get_device(udevice, path);
|
||||
if (err >= 0)
|
||||
log_info(udev, "device %p filled with udev database data\n", udev_device);
|
||||
log_info(udev, "device %p filled with %s data\n", udev_device, udev_device_get_devpath(udev_device));
|
||||
|
||||
if (udevice->name[0] != '\0')
|
||||
asprintf(&udev_device->devname, "%s/%s", udev_get_dev_path(udev), udevice->name);
|
||||
|
||||
list_for_each_entry(name_loop, &udevice->symlink_list, node) {
|
||||
char name[PATH_SIZE];
|
||||
|
||||
strlcpy(name, udev_get_dev_path(udev), sizeof(name));
|
||||
strlcat(name, "/", sizeof(name));
|
||||
strlcat(name, name_loop->name, sizeof(name));
|
||||
name_list_add(&udev_device->link_list, name, 0);
|
||||
}
|
||||
|
||||
list_for_each_entry(name_loop, &udevice->env_list, node)
|
||||
name_list_add(&udev_device->env_list, name_loop->name, 0);
|
||||
|
||||
udev_device_cleanup(udevice);
|
||||
return udev_device;
|
||||
}
|
||||
|
||||
@ -103,6 +134,8 @@ struct udev_device *udev_device_new_from_devpath(struct udev *udev, const char *
|
||||
**/
|
||||
struct udev *udev_device_get_udev(struct udev_device *udev_device)
|
||||
{
|
||||
if (udev_device == NULL)
|
||||
return NULL;
|
||||
return udev_device->udev;
|
||||
}
|
||||
|
||||
@ -116,6 +149,8 @@ struct udev *udev_device_get_udev(struct udev_device *udev_device)
|
||||
**/
|
||||
struct udev_device *udev_device_ref(struct udev_device *udev_device)
|
||||
{
|
||||
if (udev_device == NULL)
|
||||
return NULL;
|
||||
udev_device->refcount++;
|
||||
return udev_device;
|
||||
}
|
||||
@ -130,10 +165,17 @@ struct udev_device *udev_device_ref(struct udev_device *udev_device)
|
||||
**/
|
||||
void udev_device_unref(struct udev_device *udev_device)
|
||||
{
|
||||
if (udev_device == NULL)
|
||||
return;
|
||||
udev_device->refcount--;
|
||||
if (udev_device->refcount > 0)
|
||||
return;
|
||||
udev_device_cleanup(udev_device->udevice);
|
||||
free(udev_device->devpath);
|
||||
free(udev_device->devname);
|
||||
free(udev_device->subsystem);
|
||||
name_list_cleanup(&udev_device->link_list);
|
||||
name_list_cleanup(&udev_device->env_list);
|
||||
log_info(udev_device->udev, "udev_device: %p released\n", udev_device);
|
||||
free(udev_device);
|
||||
}
|
||||
|
||||
@ -148,7 +190,9 @@ void udev_device_unref(struct udev_device *udev_device)
|
||||
**/
|
||||
const char *udev_device_get_devpath(struct udev_device *udev_device)
|
||||
{
|
||||
return udev_device->udevice->dev->devpath;
|
||||
if (udev_device == NULL)
|
||||
return NULL;
|
||||
return udev_device->devpath;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -156,16 +200,15 @@ const char *udev_device_get_devpath(struct udev_device *udev_device)
|
||||
* @udev_device: udev device
|
||||
*
|
||||
* Retrieve the device node file name belonging to the udev device.
|
||||
* The path does not contain the device directory, and does not contain
|
||||
* a leading '/'.
|
||||
* The path is an absolute path, and starts with the device directory.
|
||||
*
|
||||
* Returns: the device node file name of the udev device, or #NULL if no device node exists
|
||||
**/
|
||||
const char *udev_device_get_devname(struct udev_device *udev_device)
|
||||
{
|
||||
if (udev_device->udevice->name[0] == '\0')
|
||||
if (udev_device == NULL)
|
||||
return NULL;
|
||||
return udev_device->udevice->name;
|
||||
return udev_device->devname;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -179,13 +222,16 @@ const char *udev_device_get_devname(struct udev_device *udev_device)
|
||||
**/
|
||||
const char *udev_device_get_subsystem(struct udev_device *udev_device)
|
||||
{
|
||||
struct sysfs_device *dev = udev_device->udevice->dev;
|
||||
if (dev->subsystem[0] != '\0')
|
||||
return dev->subsystem;
|
||||
if (util_get_sys_subsystem(udev_device->udev, dev->devpath,
|
||||
dev->subsystem, sizeof(dev->subsystem)) < 2)
|
||||
char subsystem[NAME_SIZE];
|
||||
|
||||
if (udev_device == NULL)
|
||||
return NULL;
|
||||
return dev->subsystem;
|
||||
if (udev_device->subsystem != NULL)
|
||||
return udev_device->subsystem;
|
||||
if (util_get_sys_subsystem(udev_device->udev, udev_device->devpath, subsystem, sizeof(subsystem)) < 2)
|
||||
return NULL;
|
||||
udev_device->subsystem = strdup(subsystem);
|
||||
return udev_device->subsystem;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -196,10 +242,9 @@ const char *udev_device_get_subsystem(struct udev_device *udev_device)
|
||||
*
|
||||
* Retrieve the device links pointing to the device file of the
|
||||
* udev device. For every device link, the passed function will be
|
||||
* called with the device link string. If the function returns 1,
|
||||
* remaning device links will be ignored. The device link path
|
||||
* does not contain the device directory, and does not contain
|
||||
* a leading '/'.
|
||||
* called with the device link string.
|
||||
* The path is an absolute path, and starts with the device directory.
|
||||
* If the function returns 1, remaning device links will be ignored.
|
||||
*
|
||||
* Returns: the number of device links passed to the caller, or a negative value on error
|
||||
**/
|
||||
@ -210,7 +255,9 @@ int udev_device_get_devlinks(struct udev_device *udev_device,
|
||||
struct name_entry *name_loop;
|
||||
int count = 0;
|
||||
|
||||
list_for_each_entry(name_loop, &udev_device->udevice->symlink_list, node) {
|
||||
if (udev_device == NULL)
|
||||
return -1;
|
||||
list_for_each_entry(name_loop, &udev_device->link_list, node) {
|
||||
count++;
|
||||
if (cb(udev_device, name_loop->name, data) != 0)
|
||||
break;
|
||||
@ -238,7 +285,9 @@ int udev_device_get_properties(struct udev_device *udev_device,
|
||||
struct name_entry *name_loop;
|
||||
int count = 0;
|
||||
|
||||
list_for_each_entry(name_loop, &udev_device->udevice->env_list, node) {
|
||||
if (udev_device == NULL)
|
||||
return -1;
|
||||
list_for_each_entry(name_loop, &udev_device->env_list, node) {
|
||||
char name[PATH_SIZE];
|
||||
char *val;
|
||||
|
||||
@ -249,6 +298,7 @@ int udev_device_get_properties(struct udev_device *udev_device,
|
||||
continue;
|
||||
val[0] = '\0';
|
||||
val = &val[1];
|
||||
count++;
|
||||
if (cb(udev_device, name, val, data) != 0)
|
||||
break;
|
||||
}
|
||||
|
216
udev/lib/libudev-monitor.c
Normal file
216
udev/lib/libudev-monitor.c
Normal file
@ -0,0 +1,216 @@
|
||||
/*
|
||||
* libudev - interface to udev device information
|
||||
*
|
||||
* Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
#include "libudev.h"
|
||||
#include "libudev-private.h"
|
||||
#include "../udev.h"
|
||||
|
||||
struct udev_monitor {
|
||||
struct udev *udev;
|
||||
int refcount;
|
||||
int socket;
|
||||
};
|
||||
|
||||
struct udev_monitor *udev_monitor_new_from_socket(struct udev *udev, const char *socket_path)
|
||||
{
|
||||
struct udev_monitor *udev_monitor;
|
||||
struct sockaddr_un saddr;
|
||||
socklen_t addrlen;
|
||||
const int on = 1;
|
||||
|
||||
if (udev == NULL)
|
||||
return NULL;
|
||||
if (socket_path == NULL)
|
||||
return NULL;
|
||||
udev_monitor = malloc(sizeof(struct udev_monitor));
|
||||
if (udev_monitor == NULL)
|
||||
return NULL;
|
||||
memset(udev_monitor, 0x00, sizeof(struct udev_monitor));
|
||||
udev_monitor->refcount = 1;
|
||||
udev_monitor->udev = udev;
|
||||
|
||||
memset(&saddr, 0x00, sizeof(saddr));
|
||||
saddr.sun_family = AF_LOCAL;
|
||||
strcpy(saddr.sun_path, socket_path);
|
||||
addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(saddr.sun_path);
|
||||
|
||||
/* translate leading '@' to abstract namespace */
|
||||
if (saddr.sun_path[0] == '@')
|
||||
saddr.sun_path[0] = '\0';
|
||||
|
||||
udev_monitor->socket = socket(AF_LOCAL, SOCK_DGRAM, 0);
|
||||
if (udev_monitor->socket == -1) {
|
||||
log_err(udev, "error getting socket: %s\n", strerror(errno));
|
||||
free(udev_monitor);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (bind(udev_monitor->socket, (struct sockaddr *) &saddr, addrlen) < 0) {
|
||||
log_err(udev, "bind failed: %s\n", strerror(errno));
|
||||
close(udev_monitor->socket);
|
||||
free(udev_monitor);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* enable receiving of the sender credentials */
|
||||
setsockopt(udev_monitor->socket, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
|
||||
log_info(udev_monitor->udev, "udev_monitor: %p created\n", udev_monitor);
|
||||
|
||||
return udev_monitor;
|
||||
}
|
||||
|
||||
struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor)
|
||||
{
|
||||
if (udev_monitor == NULL)
|
||||
return NULL;
|
||||
udev_monitor->refcount++;
|
||||
return udev_monitor;
|
||||
}
|
||||
|
||||
void udev_monitor_unref(struct udev_monitor *udev_monitor)
|
||||
{
|
||||
if (udev_monitor == NULL)
|
||||
return;
|
||||
udev_monitor->refcount--;
|
||||
if (udev_monitor->refcount > 0)
|
||||
return;
|
||||
close(udev_monitor->socket);
|
||||
log_info(udev_monitor->udev, "udev_monitor: %p released\n", udev_monitor);
|
||||
free(udev_monitor);
|
||||
}
|
||||
|
||||
struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor)
|
||||
{
|
||||
if (udev_monitor == NULL)
|
||||
return NULL;
|
||||
return udev_monitor->udev;
|
||||
}
|
||||
|
||||
int udev_monitor_get_fd(struct udev_monitor *udev_monitor)
|
||||
{
|
||||
if (udev_monitor == NULL)
|
||||
return -1;
|
||||
return udev_monitor->socket;
|
||||
}
|
||||
|
||||
struct udev_device *udev_monitor_get_device(struct udev_monitor *udev_monitor)
|
||||
{
|
||||
struct udev_device *udev_device;
|
||||
struct msghdr smsg;
|
||||
struct cmsghdr *cmsg;
|
||||
struct iovec iov;
|
||||
struct ucred *cred;
|
||||
char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
|
||||
char buf[4096];
|
||||
size_t bufpos;
|
||||
|
||||
if (udev_monitor == NULL)
|
||||
return NULL;
|
||||
memset(buf, 0x00, sizeof(buf));
|
||||
iov.iov_base = &buf;
|
||||
iov.iov_len = sizeof(buf);
|
||||
memset (&smsg, 0x00, sizeof(struct msghdr));
|
||||
smsg.msg_iov = &iov;
|
||||
smsg.msg_iovlen = 1;
|
||||
smsg.msg_control = cred_msg;
|
||||
smsg.msg_controllen = sizeof(cred_msg);
|
||||
|
||||
if (recvmsg(udev_monitor->socket, &smsg, 0) < 0) {
|
||||
if (errno != EINTR)
|
||||
log_info(udev_monitor->udev, "unable to receive message");
|
||||
return NULL;
|
||||
}
|
||||
cmsg = CMSG_FIRSTHDR(&smsg);
|
||||
cred = (struct ucred *)CMSG_DATA (cmsg);
|
||||
|
||||
if (cmsg == NULL || cmsg->cmsg_type != SCM_CREDENTIALS) {
|
||||
log_info(udev_monitor->udev, "no sender credentials received, message ignored");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (cred->uid != 0) {
|
||||
log_info(udev_monitor->udev, "sender uid=%d, message ignored", cred->uid);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* skip header */
|
||||
bufpos = strlen(buf) + 1;
|
||||
if (bufpos < sizeof("a@/d") || bufpos >= sizeof(buf)) {
|
||||
log_info(udev_monitor->udev, "invalid message length");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* check message header */
|
||||
if (strstr(buf, "@/") == NULL) {
|
||||
log_info(udev_monitor->udev, "unrecognized message header");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
udev_device = device_init(udev_monitor->udev);
|
||||
if (udev_device == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (bufpos < sizeof(buf)) {
|
||||
char *key;
|
||||
size_t keylen;
|
||||
|
||||
key = &buf[bufpos];
|
||||
keylen = strlen(key);
|
||||
if (keylen == 0)
|
||||
break;
|
||||
bufpos += keylen + 1;
|
||||
|
||||
if (strncmp(key, "DEVPATH=", 8) == 0) {
|
||||
udev_device->devpath = strdup(&key[8]);
|
||||
} else if (strncmp(key, "SUBSYSTEM=", 10) == 0) {
|
||||
udev_device->subsystem = strdup(&key[10]);
|
||||
} else if (strncmp(key, "DEVNAME=", 8) == 0) {
|
||||
udev_device->devname = strdup(&key[8]);
|
||||
} else if (strncmp(key, "DEVLINKS=", 9) == 0) {
|
||||
char *slink = &key[9];
|
||||
char *next = strchr(slink, ' ');
|
||||
|
||||
while (next != NULL) {
|
||||
next[0] = '\0';
|
||||
name_list_add(&udev_device->link_list, slink, 0);
|
||||
slink = &next[1];
|
||||
next = strchr(slink, ' ');
|
||||
}
|
||||
if (slink[0] != '\0')
|
||||
name_list_add(&udev_device->link_list, slink, 0);
|
||||
}
|
||||
name_list_add(&udev_device->env_list, key, 0);
|
||||
}
|
||||
|
||||
return udev_device;
|
||||
}
|
@ -23,17 +23,14 @@
|
||||
#include "libudev.h"
|
||||
#include "../udev.h"
|
||||
|
||||
struct udev {
|
||||
int refcount;
|
||||
void (*log_fn)(struct udev *udev,
|
||||
int priority, const char *file, int line, const char *fn,
|
||||
const char *format, va_list args);
|
||||
};
|
||||
|
||||
struct udev_device {
|
||||
int refcount;
|
||||
struct udev *udev;
|
||||
struct udevice *udevice;
|
||||
char *devpath;
|
||||
char *devname;
|
||||
char *subsystem;
|
||||
struct list_head link_list;
|
||||
struct list_head env_list;
|
||||
};
|
||||
|
||||
#ifdef USE_LOG
|
||||
@ -57,6 +54,7 @@ static inline void udev_log(struct udev *udev,
|
||||
__attribute__ ((format(printf, 6, 7))) {}
|
||||
#endif
|
||||
|
||||
extern struct udev_device *device_init(struct udev *udev);
|
||||
extern ssize_t util_get_sys_subsystem(struct udev *udev, const char *devpath, char *subsystem, size_t size);
|
||||
|
||||
#endif
|
||||
|
@ -32,6 +32,13 @@
|
||||
#include "libudev-private.h"
|
||||
#include "../udev.h"
|
||||
|
||||
struct udev {
|
||||
int refcount;
|
||||
void (*log_fn)(struct udev *udev,
|
||||
int priority, const char *file, int line, const char *fn,
|
||||
const char *format, va_list args);
|
||||
};
|
||||
|
||||
void udev_log(struct udev *udev,
|
||||
int priority, const char *file, int line, const char *fn,
|
||||
const char *format, ...)
|
||||
@ -110,6 +117,8 @@ struct udev *udev_new(void)
|
||||
**/
|
||||
struct udev *udev_ref(struct udev *udev)
|
||||
{
|
||||
if (udev == NULL)
|
||||
return NULL;
|
||||
udev->refcount++;
|
||||
return udev;
|
||||
}
|
||||
@ -124,6 +133,8 @@ struct udev *udev_ref(struct udev *udev)
|
||||
**/
|
||||
void udev_unref(struct udev *udev)
|
||||
{
|
||||
if (udev == NULL)
|
||||
return;
|
||||
udev->refcount--;
|
||||
if (udev->refcount > 0)
|
||||
return;
|
||||
@ -164,6 +175,8 @@ void udev_set_log_fn(struct udev *udev,
|
||||
**/
|
||||
const char *udev_get_sys_path(struct udev *udev)
|
||||
{
|
||||
if (udev == NULL)
|
||||
return NULL;
|
||||
return sysfs_path;
|
||||
}
|
||||
|
||||
@ -179,5 +192,7 @@ const char *udev_get_sys_path(struct udev *udev)
|
||||
**/
|
||||
const char *udev_get_dev_path(struct udev *udev)
|
||||
{
|
||||
if (udev == NULL)
|
||||
return NULL;
|
||||
return udev_root;
|
||||
}
|
||||
|
@ -22,6 +22,7 @@
|
||||
|
||||
struct udev;
|
||||
struct udev_device;
|
||||
struct udev_monitor;
|
||||
|
||||
extern struct udev *udev_new(void);
|
||||
extern struct udev *udev_ref(struct udev *udev);
|
||||
@ -54,4 +55,11 @@ extern int udev_devices_enumerate(struct udev *udev, const char *subsystem,
|
||||
const char *devpath, const char *subsystem, const char *name, void *data),
|
||||
void *data);
|
||||
|
||||
extern struct udev_monitor *udev_monitor_new_from_socket(struct udev *udev, const char *socket_path);
|
||||
extern struct udev_monitor *udev_monitor_ref(struct udev_monitor *udev_monitor);
|
||||
extern void udev_monitor_unref(struct udev_monitor *udev_monitor);
|
||||
extern struct udev *udev_monitor_get_udev(struct udev_monitor *udev_monitor);
|
||||
extern int udev_monitor_get_fd(struct udev_monitor *udev_monitor);
|
||||
extern struct udev_device *udev_monitor_get_device(struct udev_monitor *udev_monitor);
|
||||
|
||||
#endif
|
||||
|
@ -21,6 +21,11 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/select.h>
|
||||
|
||||
#include "libudev.h"
|
||||
|
||||
static void log_fn(struct udev *udev,
|
||||
@ -31,9 +36,49 @@ static void log_fn(struct udev *udev,
|
||||
vprintf(format, args);
|
||||
}
|
||||
|
||||
static int devlinks_cb(struct udev_device *udev_device, const char *value, void *data)
|
||||
static int print_devlinks_cb(struct udev_device *udev_device, const char *value, void *data)
|
||||
{
|
||||
printf("link: %s\n", value);
|
||||
printf("link: '%s'\n", value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int print_properties_cb(struct udev_device *udev_device, const char *key, const char *value, void *data)
|
||||
{
|
||||
printf("property: '%s=%s'\n", key, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void print_device(struct udev_device *device)
|
||||
{
|
||||
const char *str;
|
||||
int count;
|
||||
|
||||
printf("*** device: %p ***\n", device);
|
||||
str = udev_device_get_devpath(device);
|
||||
printf("devpath: '%s'\n", str);
|
||||
str = udev_device_get_subsystem(device);
|
||||
printf("subsystem: '%s'\n", str);
|
||||
str = udev_device_get_devname(device);
|
||||
printf("devname: '%s'\n", str);
|
||||
count = udev_device_get_devlinks(device, print_devlinks_cb, NULL);
|
||||
printf("found %i links\n", count);
|
||||
count = udev_device_get_properties(device, print_properties_cb, NULL);
|
||||
printf("found %i properties\n", count);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static int test_device(struct udev *udev, const char *devpath)
|
||||
{
|
||||
struct udev_device *device;
|
||||
|
||||
printf("looking at device: %s\n", devpath);
|
||||
device = udev_device_new_from_devpath(udev, devpath);
|
||||
if (device == NULL) {
|
||||
printf("no device\n");
|
||||
return -1;
|
||||
}
|
||||
print_device(device);
|
||||
udev_device_unref(device);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -41,28 +86,79 @@ static int devices_enum_cb(struct udev *udev,
|
||||
const char *devpath, const char *subsystem, const char *name,
|
||||
void *data)
|
||||
{
|
||||
printf("device: %s (%s) %s\n", devpath, subsystem, name);
|
||||
printf("device: '%s' (%s) '%s'\n", devpath, subsystem, name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int properties_cb(struct udev_device *udev_device, const char *key, const char *value, void *data)
|
||||
static int test_enumerate(struct udev *udev, const char *subsystem)
|
||||
{
|
||||
printf("property: %s=%s\n", key, value);
|
||||
int count;
|
||||
|
||||
count = udev_devices_enumerate(udev, subsystem, devices_enum_cb, NULL);
|
||||
printf("found %i devices\n\n", count);
|
||||
return count;
|
||||
}
|
||||
|
||||
static int test_monitor(struct udev *udev, const char *socket_path)
|
||||
{
|
||||
struct udev_monitor *udev_monitor;
|
||||
fd_set readfds;
|
||||
int fd;
|
||||
|
||||
udev_monitor = udev_monitor_new_from_socket(udev, socket_path);
|
||||
if (udev_monitor == NULL) {
|
||||
printf("no socket\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
fd = udev_monitor_get_fd(udev_monitor);
|
||||
FD_ZERO(&readfds);
|
||||
|
||||
while (1) {
|
||||
struct udev_device *device;
|
||||
int fdcount;
|
||||
|
||||
FD_SET(STDIN_FILENO, &readfds);
|
||||
FD_SET(fd, &readfds);
|
||||
|
||||
printf("waiting for events on %s, press ENTER to exit\n", socket_path);
|
||||
fdcount = select(fd+1, &readfds, NULL, NULL, NULL);
|
||||
printf("select fd count: %i\n", fdcount);
|
||||
|
||||
if (FD_ISSET(fd, &readfds)) {
|
||||
device = udev_monitor_get_device(udev_monitor);
|
||||
if (device == NULL) {
|
||||
printf("no device from socket\n");
|
||||
continue;
|
||||
}
|
||||
print_device(device);
|
||||
udev_device_unref(device);
|
||||
}
|
||||
|
||||
if (FD_ISSET(STDIN_FILENO, &readfds)) {
|
||||
printf("exiting loop\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
udev_monitor_unref(udev_monitor);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[], char *envp[])
|
||||
{
|
||||
struct udev *udev;
|
||||
struct udev_device *device;
|
||||
const char *str;
|
||||
const char *devpath = "/devices/virtual/mem/null";
|
||||
const char *subsystem = NULL;
|
||||
const char *socket = "@/org/kernel/udev/monitor";
|
||||
const char *str;
|
||||
|
||||
if (argv[1] != NULL) {
|
||||
devpath = argv[1];
|
||||
if (argv[2] != NULL)
|
||||
subsystem = argv[2];
|
||||
if (argv[3] != NULL)
|
||||
socket = argv[3];
|
||||
}
|
||||
|
||||
udev = udev_new();
|
||||
@ -75,32 +171,13 @@ int main(int argc, char *argv[], char *envp[])
|
||||
printf("set log: %p\n", log_fn);
|
||||
|
||||
str = udev_get_sys_path(udev);
|
||||
printf("sys_path: %s\n", str);
|
||||
printf("sys_path: '%s'\n", str);
|
||||
str = udev_get_dev_path(udev);
|
||||
printf("dev_path: %s\n", str);
|
||||
printf("dev_path: '%s'\n", str);
|
||||
|
||||
printf("looking at device: %s\n", devpath);
|
||||
device = udev_device_new_from_devpath(udev, devpath);
|
||||
printf("device: %p\n", device);
|
||||
if (device == NULL) {
|
||||
printf("no device\n");
|
||||
return 1;
|
||||
}
|
||||
str = udev_device_get_devpath(device);
|
||||
printf("devpath: %s\n", str);
|
||||
str = udev_device_get_subsystem(device);
|
||||
printf("subsystem: %s\n", str);
|
||||
str = udev_device_get_devname(device);
|
||||
printf("devname: %s\n", str);
|
||||
udev_device_get_devlinks(device, devlinks_cb, NULL);
|
||||
udev_device_get_properties(device, properties_cb, NULL);
|
||||
udev_device_unref(device);
|
||||
|
||||
if (subsystem == NULL)
|
||||
printf("enumerating devices from all subsystems\n");
|
||||
else
|
||||
printf("enumerating devices from subsystem: %s\n", subsystem);
|
||||
udev_devices_enumerate(udev, subsystem, devices_enum_cb, NULL);
|
||||
test_device(udev, devpath);
|
||||
test_enumerate(udev, subsystem);
|
||||
test_monitor(udev, socket);
|
||||
|
||||
udev_unref(udev);
|
||||
return 0;
|
||||
|
Loading…
Reference in New Issue
Block a user