summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Härdeman <david@hardeman.nu>2015-07-19 23:22:23 +0200
committerDavid Härdeman <david@hardeman.nu>2015-07-19 23:22:23 +0200
commitd13eb564b120be2d6694225aa408a39f860dbf45 (patch)
tree31cafac22b082e4cf2f349ea6f75f15133a7e5bb
parent69d14aaec02dd341d93b4c9b0ee07fef2f87ef6b (diff)
Implement keymap writing server-side
-rw-r--r--rcm-server-keymap.c88
-rw-r--r--rcm-server-keymap.h2
-rw-r--r--rcm-server-main.c11
3 files changed, 96 insertions, 5 deletions
diff --git a/rcm-server-keymap.c b/rcm-server-keymap.c
index 6e45570..04dd1a4 100644
--- a/rcm-server-keymap.c
+++ b/rcm-server-keymap.c
@@ -438,6 +438,94 @@ keymaps_load(struct device *device)
return 0;
}
+int
+keymap_write(struct keymap *keymap)
+{
+ _cleanup_close_ int dfd = -1;
+ _cleanup_close_ int fd = -1;
+ _cleanup_fclose_ FILE *file = NULL;
+ char *separator;
+ unsigned i;
+
+ separator = strrchr(keymap->id, '/');
+ if (!separator)
+ return -EINVAL;
+
+ /* FIXME: This is just a temporary location */
+ dfd = open("./keymaps", O_PATH | O_DIRECTORY);
+ if (dfd < 0)
+ return -errno;
+
+ *separator = '\0';
+ fd = openat(dfd, keymap->id, O_TMPFILE | O_WRONLY, 0644);
+ *separator = '/';
+ if (fd < 0)
+ return -errno;
+
+ /* https://sourceware.org/bugzilla/show_bug.cgi?id=17523 */
+ if (fchmod(fd, 0644) < 0)
+ return -errno;
+
+ int fdpath_len;
+ fdpath_len = snprintf(NULL, 0, "/proc/self/fd/%i", fd);
+ if (fdpath_len < 0)
+ return -errno;
+
+ char fdpath[fdpath_len + 1];
+ sprintf(fdpath, "/proc/self/fd/%d", fd);
+
+ file = fdopen(fd, "w");
+ if (!file)
+ return -errno;
+ else
+ fd = -1;
+
+ fprintf(file, "[Description]\n");
+ fprintf(file, "Name=%s\n", keymap->name);
+ fprintf(file, "Description=%s\n", keymap->description);
+ fprintf(file, "Rows=%u\n", keymap->rows);
+ fprintf(file, "Cols=%u\n", keymap->cols);
+ fprintf(file, "\n");
+
+ fprintf(file, "[Keymap]\n");
+ for (i = 0; i < keymap->keycode_count; i++) {
+ fprintf(file, "Map=%s:0x%08" PRIx64 ":%s\n",
+ keymap->keycodes[i].protocol,
+ keymap->keycodes[i].scancode,
+ keymap->keycodes[i].keycode);
+ }
+ fprintf(file, "\n");
+
+ fprintf(file, "[Layout]\n");
+ for (i = 0; i < (keymap->rows * keymap->cols); i++) {
+ if (keymap->layout[i])
+ fprintf(file, "Button=%s\n", keymap->layout[i]->keycode);
+ else
+ fprintf(file, "Button=Blank\n");
+ }
+
+ fflush(file);
+
+ if (ferror(file))
+ return errno ? -errno : -EIO;
+
+ char tmppath[strlen(keymap->id) + strlen(".tmp") + 1];
+ sprintf(tmppath, "%s.tmp", keymap->id);
+
+ if (linkat(AT_FDCWD, fdpath, dfd, tmppath, AT_SYMLINK_FOLLOW) < 0) {
+ printf("linkat failed: %i - %s\n", errno, strerror(errno));
+ return -errno;
+ }
+
+ if (renameat(dfd, tmppath, dfd, keymap->id) < 0) {
+ int r = -errno;
+ unlinkat(dfd, tmppath, 0);
+ return r;
+ }
+
+ return 0;
+}
+
void
keymap_free(struct keymap *keymap)
{
diff --git a/rcm-server-keymap.h b/rcm-server-keymap.h
index 03badb1..a68a1fd 100644
--- a/rcm-server-keymap.h
+++ b/rcm-server-keymap.h
@@ -23,6 +23,8 @@ struct keymap *find_keymap_by_id(struct device *dev, const char *id);
int keymaps_load(struct device *device);
+int keymap_write(struct keymap *keymap);
+
void keymap_free(struct keymap *keymap);
#endif
diff --git a/rcm-server-main.c b/rcm-server-main.c
index 0623a01..cde13a0 100644
--- a/rcm-server-main.c
+++ b/rcm-server-main.c
@@ -587,29 +587,30 @@ method_setkeymap(sd_bus_message *m, void *userdata, sd_bus_error *error)
new_keymap->layout = zmalloc(sizeof(struct keycode *) * cols * rows);
if (!new_keymap->layout) {
- keymap_free(new_keymap);
r = -ENOMEM;
goto out;
}
r = method_setkeymap_parse_dbus_msg(m, new_keymap, NULL, NULL, NULL, NULL);
- if (r < 0) {
- keymap_free(new_keymap);
+ if (r < 0)
goto out;
- }
printf("\tUpdated keymap: name (%s), desc (%s), keycodes(%u), rows(%u), cols(%u)\n",
new_keymap->name, new_keymap->description,
new_keymap->keycode_count,
new_keymap->rows, new_keymap->cols);
- /* FIXME: Write to disk */
+ r = keymap_write(new_keymap);
+ if (r < 0)
+ goto out;
+
list_replace(&old_keymap->list, &new_keymap->list);
keymap_free(old_keymap);
return sd_bus_reply_method_return(m, NULL);
out:
+ keymap_free(new_keymap);
return sd_bus_error_set_errno(error, r);
}