Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 17 additions & 50 deletions hotplug-dispatch.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
#include <errno.h>
#include <fcntl.h>
#include <glob.h>
#include <limits.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
Expand All @@ -39,11 +38,8 @@
#define HOTPLUG_BASEDIR "/etc/hotplug.d"
#define HOTPLUG_OBJECT_PREFIX "hotplug."

#define INOTIFY_SZ (sizeof(struct inotify_event) + PATH_MAX + 1)

struct ubus_context *ctx;
static char *inotify_buffer;
static struct uloop_fd fd_inotify_read;
static struct inotify_watch basedir_watch;

static AVL_TREE(subsystems, avl_strcmp, false, NULL);

Expand Down Expand Up @@ -423,41 +419,24 @@ static int init_subsystems(void)
return 0;
}

static void inotify_read_handler(struct uloop_fd *u, unsigned int events)
static void basedir_event(struct inotify_watch *w, struct inotify_event *in)
{
int rc;
char *p;
struct inotify_event *in;

/* read inotify events */
while ((rc = read(u->fd, inotify_buffer, INOTIFY_SZ)) == -1 && errno == EINTR);

if (rc <= 0)
/* skip everything but directories */
if (!(in->mask & IN_ISDIR))
return;

/* process events from buffer */
for (p = inotify_buffer;
rc - (p - inotify_buffer) >= (int)sizeof(struct inotify_event);
p += sizeof(struct inotify_event) + in->len) {
in = (struct inotify_event*)p;

/* skip everything but directories */
if (!(in->mask & IN_ISDIR))
continue;

if (in->len < 1)
continue;
if (in->len < 1)
return;

/* skip hidden files */
if (in->name[0] == '.')
continue;
/* skip hidden files */
if (in->name[0] == '.')
return;

/* add/remove subsystem objects */
if (in->mask & (IN_CREATE | IN_MOVED_TO))
add_subsystem(in->name);
else if (in->mask & (IN_DELETE | IN_MOVED_FROM))
remove_subsystem(in->name);
}
/* add/remove subsystem objects */
if (in->mask & (IN_CREATE | IN_MOVED_TO))
add_subsystem(in->name);
else if (in->mask & (IN_DELETE | IN_MOVED_FROM))
remove_subsystem(in->name);
}

void hotplug_ubus_event(struct blob_attr *data)
Expand Down Expand Up @@ -488,20 +467,8 @@ void ubus_init_hotplug(struct ubus_context *newctx)
printf("failed to initialize hotplug subsystems from %s\n", HOTPLUG_BASEDIR);
return;
}
fd_inotify_read.fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
fd_inotify_read.cb = inotify_read_handler;
if (fd_inotify_read.fd == -1) {
if (inotify_watch_add(&basedir_watch, HOTPLUG_BASEDIR,
IN_CREATE | IN_MOVED_TO | IN_DELETE |
IN_MOVED_FROM | IN_ONLYDIR, basedir_event))
printf("failed to initialize inotify handler for %s\n", HOTPLUG_BASEDIR);
return;
}

inotify_buffer = calloc(1, INOTIFY_SZ);
if (!inotify_buffer)
return;

if (inotify_add_watch(fd_inotify_read.fd, HOTPLUG_BASEDIR,
IN_CREATE | IN_MOVED_TO | IN_DELETE | IN_MOVED_FROM | IN_ONLYDIR) == -1)
return;

uloop_fd_add(&fd_inotify_read, ULOOP_READ);
}
113 changes: 110 additions & 3 deletions plug/hotplug.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
* GNU General Public License for more details.
*/

#include <sys/inotify.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/types.h>
Expand All @@ -28,17 +29,23 @@

#include <errno.h>
#include <fcntl.h>
#include <glob.h>
#include <unistd.h>
#include <stdlib.h>
#include <libgen.h>
#include <grp.h>

#include "../procd.h"
#include "../utils/utils.h"

#include "hotplug.h"

#define HOTPLUG_WAIT 500

#define HOTPLUG_RULES_EVENTS (IN_CREATE | IN_CLOSE_WRITE | IN_MOVED_TO | \
IN_DELETE | IN_MOVED_FROM | IN_DELETE_SELF | \
IN_MOVE_SELF)

struct cmd_handler;
struct cmd_queue {
struct list_head list;
Expand Down Expand Up @@ -492,18 +499,50 @@ static const char* rule_handle_var(struct json_script_ctx *ctx, const char *name
}

static struct json_script_file *
rule_handle_file(struct json_script_ctx *ctx, const char *name)
rule_load_file(const char *path, const char *key)
{
json_object *obj;

obj = json_object_from_file((char*)name);
obj = json_object_from_file(path);
if (!obj)
return NULL;

blob_buf_init(&script, 0);
blobmsg_add_json_element(&script, "", obj);
json_object_put(obj);

return json_script_file_from_blobmsg(key, blob_data(script.head), blob_len(script.head));
}

static struct json_script_file *
rule_handle_file(struct json_script_ctx *ctx, const char *name)
{
struct json_script_file *head = NULL, *f, **tail;
const char *key = name;
glob_t gl;
size_t i;

if (!strpbrk(name, "*?["))
return rule_load_file(name, name);

if (glob(name, 0, NULL, &gl)) {
globfree(&gl);
return NULL;
}

return json_script_file_from_blobmsg(name, blob_data(script.head), blob_len(script.head));
tail = &head;
for (i = 0; i < gl.gl_pathc; i++) {
f = rule_load_file(gl.gl_pathv[i], key);
if (!f)
continue;

key = NULL;
*tail = f;
tail = &f->next;
}
globfree(&gl);

return head;
}

static void rule_handle_command(struct json_script_ctx *ctx, const char *name,
Expand Down Expand Up @@ -552,6 +591,73 @@ static struct json_script_ctx jctx = {
.handle_file = rule_handle_file,
};

static struct inotify_watch rules_watch;

static void hotplug_rules_flush(void)
{
json_script_free(&jctx);
json_script_init(&jctx);
}

static int hotplug_rules_reload(struct ubus_context *ctx,
struct ubus_object *obj,
struct ubus_request_data *req,
const char *method, struct blob_attr *msg)
{
hotplug_rules_flush();

return UBUS_STATUS_OK;
}

static const struct ubus_method hotplug_rules_methods[] = {
UBUS_METHOD_NOARG("reload", hotplug_rules_reload),
};

static struct ubus_object_type hotplug_rules_object_type =
UBUS_OBJECT_TYPE("hotplug", hotplug_rules_methods);

static struct ubus_object hotplug_rules_object = {
.name = "hotplug",
.type = &hotplug_rules_object_type,
.methods = hotplug_rules_methods,
.n_methods = ARRAY_SIZE(hotplug_rules_methods),
};

void ubus_init_hotplug_rules(struct ubus_context *ctx)
{
int ret;

if (!rule_file)
return;

ret = ubus_add_object(ctx, &hotplug_rules_object);
if (ret)
ERROR("Failed to add object: %s\n", ubus_strerror(ret));
}

static void hotplug_rules_changed(struct inotify_watch *w,
struct inotify_event *ev)
{
hotplug_rules_flush();
}

static void hotplug_rules_watch(const char *rules)
{
char *dir;

dir = malloc(strlen(rules) + sizeof(".d"));
if (!dir)
return;

sprintf(dir, "%s.d", rules);

if (inotify_watch_add(&rules_watch, dir, HOTPLUG_RULES_EVENTS,
hotplug_rules_changed))
ERROR("Failed to watch %s: %m\n", dir);

free(dir);
}

static void hotplug_handler_debug(struct blob_attr *data)
{
char *str;
Expand Down Expand Up @@ -626,6 +732,7 @@ void hotplug(char *rules)
ERROR("Failed to resize receive buffer: %m\n");

json_script_init(&jctx);
hotplug_rules_watch(rules);
queue_proc.cb = queue_proc_cb;
uloop_fd_add(&hotplug_fd, ULOOP_READ);
}
Expand Down
5 changes: 5 additions & 0 deletions procd.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,15 @@ void ubus_init_service(struct ubus_context *ctx);
void ubus_init_system(struct ubus_context *ctx);
#ifndef DISABLE_INIT
void hotplug_ubus_event(struct blob_attr *data);
void ubus_init_hotplug_rules(struct ubus_context *ctx);
#else
static inline void hotplug_ubus_event(struct blob_attr *data)
{
}

static inline void ubus_init_hotplug_rules(struct ubus_context *ctx)
{
}
#endif

void procd_state_next(void);
Expand Down
1 change: 1 addition & 0 deletions ubus.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ ubus_connect_cb(struct uloop_timeout *timeout)
udebug_ubus_init(&udebug, ctx, "procd", procd_udebug_cb);
ctx->connection_lost = ubus_disconnect_cb;
ubus_init_hotplug(ctx);
ubus_init_hotplug_rules(ctx);
ubus_init_service(ctx);
ubus_init_system(ctx);
watch_ubus(ctx);
Expand Down
53 changes: 53 additions & 0 deletions utils/utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

Expand All @@ -30,6 +32,10 @@
#define O_PATH 010000000
#endif

#define INOTIFY_SZ (sizeof(struct inotify_event) + PATH_MAX + 1)

static char *inotify_buffer;

void
__blobmsg_list_init(struct blobmsg_list *list, int offset, int len, blobmsg_list_cmp cmp)
{
Expand Down Expand Up @@ -250,3 +256,50 @@ int patch_stdio(const char *device)

return rv;
}

static void inotify_watch_handler(struct uloop_fd *ufd, unsigned int events)
{
struct inotify_watch *w = container_of(ufd, struct inotify_watch, ufd);
struct inotify_event *in;
char *p;
int rc;

while ((rc = read(ufd->fd, inotify_buffer, INOTIFY_SZ)) == -1 &&
errno == EINTR);

if (rc <= 0)
return;

for (p = inotify_buffer;
rc - (p - inotify_buffer) >= (int)sizeof(struct inotify_event);
p += sizeof(struct inotify_event) + in->len) {
in = (struct inotify_event *)p;
w->cb(w, in);
}
}

int inotify_watch_add(struct inotify_watch *w, const char *path,
uint32_t mask, inotify_watch_cb cb)
{
if (!inotify_buffer) {
inotify_buffer = calloc(1, INOTIFY_SZ);
if (!inotify_buffer)
return -1;
}

w->ufd.fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
if (w->ufd.fd == -1)
return -1;

w->ufd.cb = inotify_watch_handler;
w->cb = cb;

if (inotify_add_watch(w->ufd.fd, path, mask) == -1 ||
uloop_fd_add(&w->ufd, ULOOP_READ)) {
close(w->ufd.fd);
w->ufd.fd = -1;
return -1;
}

return 0;
}
16 changes: 16 additions & 0 deletions utils/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@
#ifndef __PROCD_UTILS_H
#define __PROCD_UTILS_H

#include <sys/inotify.h>

#include <libubox/avl.h>
#include <libubox/blob.h>
#include <libubox/blobmsg.h>
#include <libubox/uloop.h>

#define CMDLINE_SIZE 2048

Expand Down Expand Up @@ -60,4 +63,17 @@ char *get_active_console(char *out, int len);
int patch_fd(const char *device, int fd, int flags);
int patch_stdio(const char *device);

struct inotify_watch;

typedef void (*inotify_watch_cb)(struct inotify_watch *w,
struct inotify_event *ev);

struct inotify_watch {
struct uloop_fd ufd;
inotify_watch_cb cb;
};

int inotify_watch_add(struct inotify_watch *w, const char *path,
uint32_t mask, inotify_watch_cb cb);

#endif
Loading