From 12ac8b17f0583d9f1e4bc8fdae69a40753d95193 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Thu, 21 Feb 2019 09:58:19 +1000 Subject: [PATCH] ratbagd: pick the ID from a list of preselected names We don't want anyone to rely on a specific content of the ID, e.g. by hardcoding hidraw/event node numbers. So let's make this an opaque list with no meaning other than "this is a rodent". This is solely for the benefit of ratbagctl which uses these IDs as access identifier. This doesn't affect ratbag-command which still uses device paths. It also does not affect the object path. And piper shows the device name anyway. Signed-off-by: Peter Hutterer --- ratbagd/ratbagd-device.c | 13 +++++++- ratbagd/ratbagd-test.c | 2 +- ratbagd/ratbagd.c | 67 +++++++++++++++++++++++++++++++++++++++- ratbagd/ratbagd.h | 2 ++ 4 files changed, 81 insertions(+), 3 deletions(-) diff --git a/ratbagd/ratbagd-device.c b/ratbagd/ratbagd-device.c index b854e79f..9c77335e 100644 --- a/ratbagd/ratbagd-device.c +++ b/ratbagd/ratbagd-device.c @@ -44,6 +44,7 @@ struct ratbagd_device { struct ratbagd *ctx; RBNode node; char *sysname; + char *id; char *path; struct ratbag_device *lib_device; @@ -274,7 +275,7 @@ ratbagd_device_get_capabilities(sd_bus *bus, const sd_bus_vtable ratbagd_device_vtable[] = { SD_BUS_VTABLE_START(0), - SD_BUS_PROPERTY("Id", "s", NULL, offsetof(struct ratbagd_device, sysname), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Id", "s", NULL, offsetof(struct ratbagd_device, id), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Capabilities", "au", ratbagd_device_get_capabilities, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Name", "s", ratbagd_device_get_device_name, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Profiles", "ao", ratbagd_device_get_profiles, 0, SD_BUS_VTABLE_PROPERTY_CONST), @@ -287,6 +288,7 @@ const sd_bus_vtable ratbagd_device_vtable[] = { int ratbagd_device_new(struct ratbagd_device **out, struct ratbagd *ctx, const char *sysname, + const char *id, struct ratbag_device *lib_device) { _cleanup_(ratbagd_device_freep) struct ratbagd_device *device = NULL; @@ -297,6 +299,7 @@ int ratbagd_device_new(struct ratbagd_device **out, assert(out); assert(ctx); assert(sysname); + assert(id); device = zalloc(sizeof(*device)); device->ctx = ctx; @@ -304,6 +307,7 @@ int ratbagd_device_new(struct ratbagd_device **out, device->lib_device = ratbag_device_ref(lib_device); device->sysname = strdup_safe(sysname); + device->id = strdup_safe(id); r = sd_bus_path_encode(RATBAGD_OBJ_ROOT "/device", device->sysname, @@ -357,12 +361,19 @@ struct ratbagd_device *ratbagd_device_free(struct ratbagd_device *device) device->lib_device = ratbag_device_unref(device->lib_device); device->path = mfree(device->path); device->sysname = mfree(device->sysname); + device->id = mfree(device->id); assert(!device->lib_device); /* ratbag yields !NULL if still pinned */ return mfree(device); } +const char *ratbagd_device_get_id(struct ratbagd_device *device) +{ + assert(device); + return device->sysname; +} + const char *ratbagd_device_get_sysname(struct ratbagd_device *device) { assert(device); diff --git a/ratbagd/ratbagd-test.c b/ratbagd/ratbagd-test.c index 514e4112..2e3aa3c1 100644 --- a/ratbagd/ratbagd-test.c +++ b/ratbagd/ratbagd-test.c @@ -190,7 +190,7 @@ int ratbagd_reset_test_device(sd_bus_message *m, device = ratbag_device_new_test_device(ctx->lib_ctx, &ratbagd_test_device_descr); - r = ratbagd_device_new(&ratbagd_test_device, ctx, "test_device", device); + r = ratbagd_device_new(&ratbagd_test_device, ctx, "test_device", "test_device", device); /* the ratbagd_device takes its own reference, drop ours */ ratbag_device_unref(device); diff --git a/ratbagd/ratbagd.c b/ratbagd/ratbagd.c index d7d51b90..29f62926 100644 --- a/ratbagd/ratbagd.c +++ b/ratbagd/ratbagd.c @@ -204,6 +204,67 @@ static const sd_bus_vtable ratbagd_vtable[] = { SD_BUS_VTABLE_END, }; +/* 32 pre-picked names. If you have more than 32 devices connected and need + * ratbag to control them all, congratulations, you are official a niche + * use-case. + */ +static const char *device_ids[] = { +"mara", "capybara", "porcupine", "paca", +"vole", "woodrat", "gerbil", "shrew", +"hare", "beaver", "gopher", "chinchilla", +"mouse", "rat", "rabbit", "guineapig", +"hutia", "degu", "gundi", "acouchy", +"nutria", "tuco-tuco", "paca", "hamster", +"zokor", "chipmunk", "squirrel", "marmot", +"groundhog", "suslik", "agouti", "blesmol", +}; + +/* bitmask telling us which ones of the above are free. */ +static uint32_t device_ids_free = (1UL << ARRAY_LENGTH(device_ids)) - 1; + +static inline const char * +pick_device_id(const char *sysname) +{ + int index; + + /* search for the first number in the sysname and where we find it, + * use that as lookup index. This way we get some sort of + * consistency, hidraw2 is always "rat", etc. + * Totally not necessary but we might as well have some fun here. + * Where this fails or picks an id already chosen, we fall back to + * "choose the first one free". + */ + if (sscanf(sysname, "%*[^0-9]%d", &index) == 1 && + index >= 0 && (unsigned)index < sizeof(device_ids_free) * 8 && + !!(device_ids_free & (1 << index))) + goto assign; + + index = ffs(device_ids_free); + + /* This can only happen if you have >32 devices, so let's not worry + * about this too much */ + if (index == 0) + return sysname; + + index -= 1; /* ffs is 1-based */ + +assign: + device_ids_free &= ~(1 << index); + + return device_ids[index]; +} + +static inline void +release_device_id(const char *id) +{ + for (size_t i = 0; i < ARRAY_LENGTH(device_ids); i++) { + if (streq(id, device_ids[i])) { + device_ids_free |= (1 << i); + break; + } + } +} + static void ratbagd_process_device(struct ratbagd *ctx, struct udev_device *udevice) { @@ -230,9 +291,11 @@ static void ratbagd_process_device(struct ratbagd *ctx, if (streq_ptr("remove", udev_device_get_action(udevice))) { /* device was removed, unlink it and destroy our context */ if (device) { + release_device_id(ratbagd_device_get_id(device)); ratbagd_device_unlink(device); ratbagd_device_free(device); + (void) sd_bus_emit_properties_changed(ctx->bus, RATBAGD_OBJ_ROOT, RATBAGD_NAME_ROOT ".Manager", @@ -242,6 +305,7 @@ static void ratbagd_process_device(struct ratbagd *ctx, } else if (device) { /* device already known, refresh our view of the device */ } else { + const char *id; enum ratbag_error_code error; /* device unknown, create new one and link it */ @@ -251,7 +315,8 @@ static void ratbagd_process_device(struct ratbagd *ctx, if (error != RATBAG_SUCCESS) return; /* unsupported device */ - r = ratbagd_device_new(&device, ctx, sysname, lib_device); + id = pick_device_id(sysname); + r = ratbagd_device_new(&device, ctx, sysname, id, lib_device); /* the ratbagd_device takes its own reference, drop ours */ ratbag_device_unref(lib_device); diff --git a/ratbagd/ratbagd.h b/ratbagd/ratbagd.h index a3a6b045..b9693c9d 100644 --- a/ratbagd/ratbagd.h +++ b/ratbagd/ratbagd.h @@ -169,8 +169,10 @@ extern const sd_bus_vtable ratbagd_device_vtable[]; int ratbagd_device_new(struct ratbagd_device **out, struct ratbagd *ctx, const char *sysname, + const char *id, struct ratbag_device *lib_device); struct ratbagd_device *ratbagd_device_free(struct ratbagd_device *device); +const char *ratbagd_device_get_id(struct ratbagd_device *device); const char *ratbagd_device_get_sysname(struct ratbagd_device *device); const char *ratbagd_device_get_path(struct ratbagd_device *device); unsigned int ratbagd_device_get_num_buttons(struct ratbagd_device *device);