From d4755d94b0d6c77e2a95a4fd01c544acb4213e2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 4 Feb 2020 18:28:09 +0100 Subject: [PATCH] main: add -p,--print-pid=FILE|FD When specified, print our PID to the file, or FD, after everything has started up. --- completions/zsh/_yambar | 3 ++- doc/yambar.1.scd | 13 ++++++--- main.c | 59 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 69 insertions(+), 6 deletions(-) diff --git a/completions/zsh/_yambar b/completions/zsh/_yambar index 1991d7a..85790b9 100644 --- a/completions/zsh/_yambar +++ b/completions/zsh/_yambar @@ -6,4 +6,5 @@ _arguments \ '(-h --help)'{-h,--help}'[show help message and quit]' \ '(-b --backend)'{-b,--backend}'[backend to use (default: auto)]:backend:(xcb wayland auto)' \ '(-c --config)'{-c,--config}'[alternative configuration file]:filename:_files' \ - '(-C --validate)'{-C,--validate}'[verify configuration then quit]' + '(-C --validate)'{-C,--validate}'[verify configuration then quit]' \ + '(-p --print-pid)'{-p,--print-pid}'[print PID to this file or FD when up and running]:pidfile:_files' diff --git a/doc/yambar.1.scd b/doc/yambar.1.scd index f5ca81e..a4cc095 100644 --- a/doc/yambar.1.scd +++ b/doc/yambar.1.scd @@ -8,21 +8,26 @@ yambar - modular status panel for X11 and Wayland # OPTIONS -*-b, --backend={xcb,wayland,auto}* +*-b*,*--backend*={*xcb*,*wayland*,*auto*} Backend to use. The default is *auto*. In this mode, yambar will look for the environment variable _WAYLAND\_DISPLAY_, and if available, use the *Wayland* backend. If not, the *XCB* backend is used. -*-c, --config=FILE* +*-c*,*--config*=_FILE_ Use an alternative configuration file instead of the default one. -*-C, --validate* +*-C*,*--validate* Verify the configuration and then quit. If no errors are detected, nothing is printed and the exit code is 0. If there are errors, these are printed on stdout and the exit code is non-zero. -*-v, --version* +*-p*,*--print-pid*=_FILE_|_FD_ + Print PID to this file, or FD, when successfully started. The file + (or FD) is closed immediately after writing the PID. When a _FILE_ + as been specified, the file is unlinked when yambar exits. + +*-v*,*--version* Show the version number and quit # DESCRIPTION diff --git a/main.c b/main.c index a8d6ab9..1db575a 100644 --- a/main.c +++ b/main.c @@ -10,10 +10,12 @@ #include #include #include +#include #include #include #include +#include #include #include "bar/bar.h" @@ -128,9 +130,47 @@ print_usage(const char *prog_name) printf(" -b,--backend={xcb,wayland,auto} backend to use (default: auto)\n" " -c,--config=FILE alternative configuration file\n" " -C,--validate verify configuration then quit\n" + " -p,--print-pid=FILE|FD print PID to file or FD\n" " -v,--version print f00sel version and quit\n"); } +static bool +print_pid(const char *pid_file, bool *unlink_at_exit) +{ + LOG_DBG("printing PID to %s", pid_file); + + errno = 0; + char *end; + int pid_fd = strtoul(pid_file, &end, 10); + + if (errno != 0 || *end != '\0') { + if ((pid_fd = open(pid_file, + O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) < 0) { + LOG_ERRNO("%s: failed to open", pid_file); + return false; + } else + *unlink_at_exit = true; + } + + if (pid_fd >= 0) { + char pid[32]; + snprintf(pid, sizeof(pid), "%u\n", getpid()); + + ssize_t bytes __attribute((unused)) = write(pid_fd, pid, strlen(pid)); + close(pid_fd); + + if (bytes < 0) { + LOG_ERRNO("failed to write PID to FD=%u", pid_fd); + return false; + } + + LOG_DBG("wrote %zd bytes to FD=%d", bytes, pid_fd); + return true; + } else + return false; +} + int main(int argc, char *const *argv) { @@ -140,17 +180,21 @@ main(int argc, char *const *argv) {"backend", required_argument, 0, 'b'}, {"config", required_argument, 0, 'c'}, {"validate", no_argument, 0, 'C'}, + {"print-pid", required_argument, 0, 'p'}, {"version", no_argument, 0, 'v'}, {"help", no_argument, 0, 'h'}, {NULL, no_argument, 0, 0}, }; + bool unlink_pid_file = false; + const char *pid_file = NULL; + bool verify_config = false; char *config_path = NULL; enum bar_backend backend = BAR_BACKEND_AUTO; while (true) { - int c = getopt_long(argc, argv, ":b:c:Cvh", longopts, NULL); + int c = getopt_long(argc, argv, ":b:c:Cp:vh", longopts, NULL); if (c == -1) break; @@ -185,6 +229,10 @@ main(int argc, char *const *argv) verify_config = true; break; + case 'p': + pid_file = optarg; + break; + case 'v': printf("yambar version %s\n", YAMBAR_VERSION); return EXIT_SUCCESS; @@ -251,6 +299,11 @@ main(int argc, char *const *argv) /* Now unblock. We should be only thread receiving SIGINT */ pthread_sigmask(SIG_UNBLOCK, &signal_mask, NULL); + if (pid_file != NULL) { + if (!print_pid(pid_file, &unlink_pid_file)) + goto done; + } + while (!aborted) { struct pollfd fds[] = {{.fd = abort_fd, .events = POLLIN}}; int r __attribute__((unused)) = poll(fds, 1, -1); @@ -267,6 +320,7 @@ main(int argc, char *const *argv) if (aborted) LOG_INFO("aborted: %s (%d)", strsignal(aborted), aborted); +done: /* Signal abort to other threads */ if (write(abort_fd, &(uint64_t){1}, sizeof(uint64_t)) != sizeof(uint64_t)) LOG_ERRNO("failed to signal abort to threads"); @@ -278,5 +332,8 @@ main(int argc, char *const *argv) bar->destroy(bar); close(abort_fd); + + if (unlink_pid_file) + unlink(pid_file); return res; }