summaryrefslogtreecommitdiff
path: root/rcm-server-keymap.c
diff options
context:
space:
mode:
Diffstat (limited to 'rcm-server-keymap.c')
-rw-r--r--rcm-server-keymap.c88
1 files changed, 88 insertions, 0 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)
{