#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/poll.h>
#include <sys/queue.h>
#include <sys/un.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <regex.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <libprop/proplib.h>
#include <sys/udev.h>
#define LIBDEVATTR_INTERNAL
#include "devattr.h"
struct udev {
int gp_fd;
int monitor_fd;
int refs;
void *userdata;
};
struct udev *
udev_ref(struct udev *udev_ctx)
{
atomic_add_int(&udev_ctx->refs, 1);
return udev_ctx;
}
void
udev_unref(struct udev *udev_ctx)
{
int refcount;
refcount = atomic_fetchadd_int(&udev_ctx->refs, -1);
if (refcount == 1) {
atomic_subtract_int(&udev_ctx->refs, 0x400);
if (udev_ctx->gp_fd != -1)
close (udev_ctx->gp_fd);
if (udev_ctx->monitor_fd != -1)
close (udev_ctx->monitor_fd);
free(udev_ctx);
}
}
struct udev *
udev_new(void)
{
struct udev *udev_ctx;
int ret, s;
ret = conn_local_server(LISTEN_SOCKET_FILE, SOCK_STREAM, 0, &s);
if (ret < 0)
return NULL;
udev_ctx = malloc(sizeof(struct udev));
udev_ctx->refs = 1;
udev_ctx->gp_fd = s;
udev_ctx->monitor_fd = -1;
udev_ctx->userdata = NULL;
return udev_ctx;
}
const char *udev_get_dev_path(struct udev *udev_ctx __unused)
{
return "/dev";
}
void *
udev_get_userdata(struct udev *udev_ctx)
{
return udev_ctx->userdata;
}
void
udev_set_userdata(struct udev *udev_ctx, void *userdata)
{
udev_ctx->userdata = userdata;
}
int
udev_get_fd(struct udev *udev_ctx)
{
return udev_ctx->gp_fd;
}
int
send_xml(int s, char *xml)
{
ssize_t r,n;
size_t sz;
sz = strlen(xml) + 1;
r = send(s, &sz, sizeof(sz), 0);
if (r <= 0)
return r;
r = 0;
while (r < (ssize_t)sz) {
n = send(s, xml+r, sz-r, 0);
if (n <= 0)
return n;
r += n;
}
return r;
}
int
read_xml(int s, char **buf)
{
char *xml;
size_t sz;
int n, r;
*buf = NULL;
n = recv(s, &sz, sizeof(sz), MSG_WAITALL);
if ((n <= 0) || (sz > 12*1024*1024))
return n;
xml = malloc(sz+2);
r = 0;
while (r < (ssize_t)sz) {
n = recv(s, xml+r, sz-r, MSG_WAITALL);
if (n <= 0) {
free(xml);
return n;
}
r += n;
}
*buf = xml;
return r;
}
int
_udev_dict_set_cstr(prop_dictionary_t dict, const char *key, char *str)
{
prop_string_t ps;
ps = prop_string_create_cstring(str);
if (ps == NULL)
return ENOMEM;
if (prop_dictionary_set(dict, key, ps) == false) {
prop_object_release(ps);
return ENOMEM;
}
prop_object_release(ps);
return 0;
}
int
_udev_dict_set_int(prop_dictionary_t dict, const char *key, int64_t val)
{
prop_number_t pn;
pn = prop_number_create_integer(val);
if (pn == NULL)
return ENOMEM;
if (prop_dictionary_set(dict, key, pn) == false) {
prop_object_release(pn);
return ENOMEM;
}
prop_object_release(pn);
return 0;
}
int
_udev_dict_set_uint(prop_dictionary_t dict, const char *key, uint64_t val)
{
prop_number_t pn;
pn = prop_number_create_unsigned_integer(val);
if (pn == NULL)
return ENOMEM;
if (prop_dictionary_set(dict, key, pn) == false) {
prop_object_release(pn);
return ENOMEM;
}
prop_object_release(pn);
return 0;
}
int
conn_local_server(const char *sockfile, int socktype, int nonblock __unused,
int *retsock)
{
int s;
struct sockaddr_un serv_addr;
*retsock = -1;
if ((s = socket(AF_UNIX, socktype, 0)) < 0)
return -1;
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sun_family = AF_UNIX;
strncpy(serv_addr.sun_path, sockfile, SOCKFILE_NAMELEN);
serv_addr.sun_path[SOCKFILE_NAMELEN - 1] = '\0';
*retsock = s;
return connect(s, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
}
prop_dictionary_t
udevd_get_command_dict(char *command)
{
prop_dictionary_t dict;
int error;
dict = prop_dictionary_create();
if (dict == NULL)
return NULL;
if ((error = _udev_dict_set_cstr(dict, "command", command)))
goto error_out;
return dict;
error_out:
prop_object_release(dict);
return NULL;
}
prop_array_t
udevd_request_devs(int s, prop_array_t filters)
{
prop_array_t pa;
prop_dictionary_t dict;
char *xml;
int n;
dict = udevd_get_command_dict(__DECONST(char *, "getdevs"));
if (dict == NULL)
return NULL;
if (filters != NULL) {
if (prop_dictionary_set(dict, "filters", filters) == false) {
prop_object_release(dict);
return NULL;
}
}
xml = prop_dictionary_externalize(dict);
prop_object_release(dict);
if (xml == NULL)
return NULL;
n = send_xml(s, xml);
free(xml);
if (n <= 0)
return NULL;
if ((n = read_xml(s, &xml)) <= 0)
return NULL;
xml[n+1] = '\0';
pa = prop_array_internalize(xml);
free(xml);
return (pa);
}