summaryrefslogtreecommitdiff
path: root/tools/tools-common.c
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2020-07-08 12:51:54 +1000
committerRan Benita <ran@unusedvar.com>2020-07-25 11:05:14 +0300
commited57fb8b869ba1edd226b55953ace0719fe8e1c1 (patch)
tree00cf3c08e52080de2953db61ac999c5f46aa08da /tools/tools-common.c
parent1b796a7209b4962db69a9de2096464d117d9b0ef (diff)
downloadxorg-lib-libxkbcommon-ed57fb8b869ba1edd226b55953ace0719fe8e1c1.tar.gz
tools: add a xkbcli tool as entry point for the various tools we have
This is the base tool, no subtools are currently connected so you only get help and version for now. The goal here is to have a git-like infrastructure where /usr/bin/xkbcli is the main tool, anything else will hide in libexec. The infrastructure for this is copied from libinput. Tools themselves will will be installed in $prefix/libexec/xkbcommon and the xkbcli tool forks off whatever argv[1] is after modifying the PATH to include the libexec dir. libinput has additional code for checking whether we're running this from the builddir but it's a bit iffy and it's usefulness is limited - if you're in the builddir anyway you can just run ./builddir/xkbcli-<toolname> directly. So for this code here, running ./builddir/xkbcli <toolname> will execute the one in the prefix/libexecdir. Since we want that tool available everywhere even where some of the subtools aren't present, we need to ifdef the getopt handling. man page generation is handled via ronn which is a ruby program but allows markdown for the sources. It's hidden behind a meson option to disable where downloading ronn isn't an option. The setup is generic enough that we can add other man-pages by just appending to the array. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Diffstat (limited to 'tools/tools-common.c')
-rw-r--r--tools/tools-common.c61
1 files changed, 61 insertions, 0 deletions
diff --git a/tools/tools-common.c b/tools/tools-common.c
index 6e397c2..0b42892 100644
--- a/tools/tools-common.c
+++ b/tools/tools-common.c
@@ -34,16 +34,22 @@
#include <limits.h>
#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef _MSC_VER
#include <io.h>
#include <windows.h>
+#ifndef PATH_MAX
+#define PATH_MAX MAX_PATH
+#endif
#else
#include <unistd.h>
#include <termios.h>
#endif
+#include "utils.h"
#include "tools-common.h"
void
@@ -197,4 +203,59 @@ tools_enable_stdin_echo(void)
(void) tcsetattr(STDIN_FILENO, TCSADRAIN, &termios);
}
}
+
#endif
+
+static inline bool
+tools_setup_path(void)
+{
+ const char *path = getenv("PATH");
+ const char *extra_path = LIBXKBCOMMON_TOOL_PATH;
+ char new_path[PATH_MAX];
+
+ if (snprintf_safe(new_path, sizeof(new_path), "%s:%s",
+ extra_path, path ? path : "")) {
+ setenv("PATH", new_path, 1);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+int
+tools_exec_command(const char *prefix, int real_argc, char **real_argv)
+{
+ char *argv[64] = {NULL};
+ char executable[128];
+ const char *command;
+
+ assert((size_t)real_argc < ARRAY_SIZE(argv));
+
+ command = real_argv[0];
+
+ if (!snprintf_safe(executable, sizeof(executable),
+ "%s-%s", prefix, command)) {
+ fprintf(stderr, "Failed to assemble command\n");
+ return EXIT_FAILURE;
+ }
+
+ if (!tools_setup_path()) {
+ fprintf(stderr, "Failed to set PATH\n");
+ return EXIT_FAILURE;
+ }
+
+ argv[0] = executable;
+ for (int i = 1; i < real_argc; i++)
+ argv[i] = real_argv[i];
+
+ execvp(executable, argv);
+ if (errno == ENOENT) {
+ fprintf(stderr, "Command '%s' is not available\n", command);
+ return EXIT_INVALID_USAGE;
+ } else {
+ fprintf(stderr, "Failed to execute '%s' (%s)\n",
+ command, strerror(errno));
+ }
+
+ return EXIT_FAILURE;
+}