winpl

LD_PRELOAD-based X11 window manipulator
git clone https://git.sinitax.com/sinitax/winpl
Log | Files | Refs | LICENSE | sfeed.txt

commit c3b838c4f16762953b3bed16da031c88703fe2b1
parent 8958a15d5cace30f3bb2a49b5ff77b6cf9f0a9cc
Author: Louis Burda <quent.burda@gmail.com>
Date:   Tue, 14 Mar 2023 01:16:59 +0100

Improve commandline interface

Diffstat:
MMakefile | 2+-
Mloader.c | 173+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
2 files changed, 112 insertions(+), 63 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,7 +1,7 @@ PREFIX ?= /usr/local BINDIR ?= /bin -CFLAGS = --std=gnu99 -Wmissing-prototypes -Wunused-variable -g +CFLAGS = -Wunused-variable -Wunused-function -g LIB_FLAGS = $(CFLAGS) -nostartfiles -fPIC -shared -Wl,-soname,xwrap.so LOADER_FLAGS = $(CFLAGS) LDLIBS = -ldl -lX11 -lXinerama diff --git a/loader.c b/loader.c @@ -1,77 +1,96 @@ -#include <stdlib.h> -#include <stdbool.h> +#include <linux/limits.h> +#include <sys/stat.h> +#include <err.h> +#include <dirent.h> +#include <limits.h> +#include <unistd.h> #include <string.h> #include <stdio.h> -#include <unistd.h> -#include <sys/stat.h> +#include <stdbool.h> +#include <stdlib.h> #define ARRLEN(x) (sizeof(x) / sizeof((x)[0])) -#define ERROR(msg) { fprintf(stderr, "winpl: %s\n", msg); exit(1); } +static const char *libpath = "/tmp/winpl.so"; extern char _binary_winpl_so_start[]; extern char _binary_winpl_so_end[]; extern char **environ; -static void write_lib(const char *filename); -static bool parse_arg(const char *arg); - -static const char *conv[][2] = { - { "ax:", "WINPL_WX" }, - { "ay:", "WINPL_WY" }, - { "rx:", "WINPL_RWX" }, - { "ry:", "WINPL_RWY" }, - { "x:", "WINPL_MWX" }, - { "y:", "WINPL_MWY" }, - { "w:", "WINPL_WW" }, - { "h:", "WINPL_WH" }, - { "rw:", "WINPL_RWW" }, - { "rh:", "WINPL_RWH" }, - { "center", "WINPL_CENTER" }, - { "float", "WINPL_FLOAT" }, - { "screen:", "WINPL_SCREEN_NUM" }, - { "pointer", "WINPL_SCREEN_PTR" }, -}; +void +usage(int rc, bool full) +{ + fprintf(stderr, "Usage: winpl [OPT].. -- CMD [ARG]..\n"); + if (!full) exit(rc); + fprintf(stderr, "\n"); + fprintf(stderr, " [-ax|-ay] POS Absolute window position\n"); + fprintf(stderr, " [-mx|-my] POS Window position relative to monitor\n"); + fprintf(stderr, " [-rx|-ry] SCALE Window position relative to monitor\n" + " as a factor of monitor size\n"); + fprintf(stderr, " [-aw|-ah] SIZE Absolute window width/height\n"); + fprintf(stderr, " [-rw|-rh] SCALE Window size relative to monitor\n"); + fprintf(stderr, " -c Center window on monitor\n"); + fprintf(stderr, " -f Tag window as dialog (floating)\n"); + fprintf(stderr, " -sn SCREEN Select monitor based on number\n"); + fprintf(stderr, " -sp Select monitor based on cursor\n"); + fprintf(stderr, "\n"); + exit(rc); +} void write_lib(const char *filename) { FILE *file; + size_t size; void *data; - size_t expected, actual; - file = fopen(filename, "w+"); - if (!file) ERROR("Failed to create temp file"); + file = fopen(filename, "wb+"); + if (!file) err(1, "fopen %s", filename); data = (void*) _binary_winpl_so_start; - expected = (size_t) (_binary_winpl_so_end - _binary_winpl_so_start); + size = (size_t) (_binary_winpl_so_end - _binary_winpl_so_start); - actual = fwrite(data, 1, expected, file); - if (actual != expected) ERROR("Failed to write temp file"); + if (fwrite(data, size, 1, file) != 1) + errx(1, "failed to write winpl lib"); fclose(file); } bool -parse_arg(const char *arg) +find_bin(char *pathbuf, const char *bin) { - int i, len; - - for (i = 0; i < ARRLEN(conv); i++) { - len = strlen(conv[i][0]); - if (strncmp(arg, conv[i][0], len)) - continue; - - if (conv[i][0][len-1] == ':') { - setenv(conv[i][1], arg + len, true); - } else if (!arg[len]) { - setenv(conv[i][1], "1", true); - } else { - return false;; + char tmp[PATH_MAX]; + const char *env_path; + const char *tok, *start, *end; + struct dirent *ent; + DIR *dir; + + env_path = getenv("PATH"); + if (!env_path) return false; + + start = tok = env_path; + while (tok) { + tok = strchr(start, ':'); + if (!tok) end = start + strlen(start); + else end = tok; + + snprintf(tmp, PATH_MAX, "%.*s", (int) (end - start), start); + dir = opendir(tmp); + if (!dir) goto next; + + while ((ent = readdir(dir))) { + if (!strcmp(ent->d_name, bin)) { + snprintf(pathbuf, PATH_MAX, "%s/%s", + tmp, ent->d_name); + return true; + } } - return true; + closedir(dir); + +next: + start = tok + 1; } return false; @@ -80,33 +99,63 @@ parse_arg(const char *arg) int main(int argc, char *const *argv) { - char *tmpfile = "/tmp/winpl.so"; + char *const *arg, *const *cmd_argv; + char pathbuf[PATH_MAX]; struct stat st; - char *const *arg, *const *cmd; + int rc; if (argc < 1) return 0; - cmd = NULL; + cmd_argv = NULL; for (arg = argv + 1; *arg; arg++) { - if (!strcmp(*arg, "--") && *(arg+1)) { - cmd = arg + 1; + if (!strcmp(*arg, "-h")) { + usage(0, true); + } else if (!strcmp(*arg, "-ax")) { + setenv("WINPL_WX", *++arg, true); + } else if (!strcmp(*arg, "-ay")) { + setenv("WINPL_WY", *++arg, true); + } else if (!strcmp(*arg, "-mx")) { + setenv("WINPL_MWX", *++arg, true); + } else if (!strcmp(*arg, "-my")) { + setenv("WINPL_MWY", *++arg, true); + } else if (!strcmp(*arg, "-rx")) { + setenv("WINPL_RWX", *++arg, true); + } else if (!strcmp(*arg, "-ry")) { + setenv("WINPL_RWY", *++arg, true); + } else if (!strcmp(*arg, "-aw")) { + setenv("WINPL_WW", *++arg, true); + } else if (!strcmp(*arg, "-ah")) { + setenv("WINPL_WH", *++arg, true); + } else if (!strcmp(*arg, "-rw")) { + setenv("WINPL_RWW", *++arg, true); + } else if (!strcmp(*arg, "-rh")) { + setenv("WINPL_RWH", *++arg, true); + } else if (!strcmp(*arg, "-c")) { + setenv("WINPL_CENTER", "1", true); + } else if (!strcmp(*arg, "-f")) { + setenv("WINPL_FLOAT", "1", true); + } else if (!strcmp(*arg, "-sn")) { + setenv("WINPL_SCREEN_NUM", *++arg, true); + } else if (!strcmp(*arg, "-sp")) { + setenv("WINPL_SCREEN_PTR", "1", true); + } else if (!strcmp(*arg, "--") && *(arg+1)) { + cmd_argv = arg + 1; break; + } else { + usage(1, true); } - - if (!parse_arg(*arg)) - ERROR("Invalid argument"); } + if (cmd_argv == NULL) + usage(1, false); - if (cmd == NULL) - ERROR("Missing args separator"); - - if (stat(*cmd, &st)) - ERROR("Binary not full path"); + if (stat(libpath, &st)) + write_lib(libpath); - if (stat(tmpfile, &st)) - write_lib(tmpfile); + setenv("LD_PRELOAD", libpath, true); - setenv("LD_PRELOAD", tmpfile, true); + if (!find_bin(pathbuf, *cmd_argv)) + errx(1, "Binary not in PATH: %s", *cmd_argv); - execve(*cmd, cmd, environ); + rc = execve(pathbuf, cmd_argv, environ); + if (rc) err(1, "execve %s", pathbuf); }