udev: watch for both ACL changes and processes closing devices

This commit is contained in:
Lennart Poettering 2009-08-21 22:49:23 +02:00
parent 4ec701aa21
commit 2d0120485c

View file

@ -45,7 +45,8 @@ PA_MODULE_USAGE(
struct device { struct device {
char *path; char *path;
pa_bool_t accessible; pa_bool_t accessible:1;
pa_bool_t need_verify:1;
char *card_name; char *card_name;
char *args; char *args;
uint32_t module; uint32_t module;
@ -277,6 +278,34 @@ fail:
u->udev_io = NULL; u->udev_io = NULL;
} }
static pa_bool_t pcm_node_belongs_to_device(
struct device *d,
const char *node) {
char *cd;
pa_bool_t b;
cd = pa_sprintf_malloc("pcmC%sD", path_get_card_id(d->path));
b = pa_startswith(node, cd);
pa_xfree(cd);
return b;
}
static pa_bool_t control_node_belongs_to_device(
struct device *d,
const char *node) {
char *cd;
pa_bool_t b;
cd = pa_sprintf_malloc("controlC%s", path_get_card_id(d->path));
b = pa_streq(node, cd);
pa_xfree(cd);
return b;
}
static void inotify_cb( static void inotify_cb(
pa_mainloop_api*a, pa_mainloop_api*a,
pa_io_event* e, pa_io_event* e,
@ -290,7 +319,9 @@ static void inotify_cb(
} buf; } buf;
struct userdata *u = userdata; struct userdata *u = userdata;
static int type = 0; static int type = 0;
pa_bool_t verify = FALSE, deleted = FALSE; pa_bool_t deleted = FALSE;
struct device *d;
void *state;
for (;;) { for (;;) {
ssize_t r; ssize_t r;
@ -305,22 +336,30 @@ static void inotify_cb(
goto fail; goto fail;
} }
if ((buf.e.mask & IN_CLOSE_WRITE) && pa_startswith(buf.e.name, "pcmC")) /* From udev we get the guarantee that the control
verify = TRUE; * device's ACL is changes last. To avoid races when ACLs
* are changed we hence watch only the control device */
if (((buf.e.mask & IN_ATTRIB) && pa_startswith(buf.e.name, "controlC")))
PA_HASHMAP_FOREACH(d, u->devices, state)
if (control_node_belongs_to_device(d, buf.e.name))
d->need_verify = TRUE;
/* ALSA doesn't really give us any guarantee on the closing
* order, so let's simply hope */
if (((buf.e.mask & IN_CLOSE_WRITE) && pa_startswith(buf.e.name, "pcmC")))
PA_HASHMAP_FOREACH(d, u->devices, state)
if (pcm_node_belongs_to_device(d, buf.e.name))
d->need_verify = TRUE;
if ((buf.e.mask & (IN_DELETE_SELF|IN_MOVE_SELF))) if ((buf.e.mask & (IN_DELETE_SELF|IN_MOVE_SELF)))
deleted = TRUE; deleted = TRUE;
} }
if (verify) { PA_HASHMAP_FOREACH(d, u->devices, state)
struct device *d; if (d->need_verify) {
void *state; d->need_verify = FALSE;
pa_log_debug("Verifying access.");
PA_HASHMAP_FOREACH(d, u->devices, state)
verify_access(u, d); verify_access(u, d);
} }
if (!deleted) if (!deleted)
return; return;