main: add -p,--print-pid=FILE|FD

When specified, print our PID to the file, or FD, after everything has
started up.
This commit is contained in:
Daniel Eklöf 2020-02-04 18:28:09 +01:00
parent ef98df1a95
commit d4755d94b0
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
3 changed files with 69 additions and 6 deletions

View file

@ -6,4 +6,5 @@ _arguments \
'(-h --help)'{-h,--help}'[show help message and quit]' \ '(-h --help)'{-h,--help}'[show help message and quit]' \
'(-b --backend)'{-b,--backend}'[backend to use (default: auto)]:backend:(xcb wayland auto)' \ '(-b --backend)'{-b,--backend}'[backend to use (default: auto)]:backend:(xcb wayland auto)' \
'(-c --config)'{-c,--config}'[alternative configuration file]:filename:_files' \ '(-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'

View file

@ -8,21 +8,26 @@ yambar - modular status panel for X11 and Wayland
# OPTIONS # OPTIONS
*-b, --backend={xcb,wayland,auto}* *-b*,*--backend*={*xcb*,*wayland*,*auto*}
Backend to use. The default is *auto*. In this mode, yambar will Backend to use. The default is *auto*. In this mode, yambar will
look for the environment variable _WAYLAND\_DISPLAY_, and if look for the environment variable _WAYLAND\_DISPLAY_, and if
available, use the *Wayland* backend. If not, the *XCB* backend is available, use the *Wayland* backend. If not, the *XCB* backend is
used. used.
*-c, --config=FILE* *-c*,*--config*=_FILE_
Use an alternative configuration file instead of the default one. 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, Verify the configuration and then quit. If no errors are detected,
nothing is printed and the exit code is 0. If there are errors, 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. 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 Show the version number and quit
# DESCRIPTION # DESCRIPTION

59
main.c
View file

@ -10,10 +10,12 @@
#include <threads.h> #include <threads.h>
#include <unistd.h> #include <unistd.h>
#include <getopt.h> #include <getopt.h>
#include <errno.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/eventfd.h> #include <sys/eventfd.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <fcntl.h>
#include <pwd.h> #include <pwd.h>
#include "bar/bar.h" #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" printf(" -b,--backend={xcb,wayland,auto} backend to use (default: auto)\n"
" -c,--config=FILE alternative configuration file\n" " -c,--config=FILE alternative configuration file\n"
" -C,--validate verify configuration then quit\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"); " -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 int
main(int argc, char *const *argv) main(int argc, char *const *argv)
{ {
@ -140,17 +180,21 @@ main(int argc, char *const *argv)
{"backend", required_argument, 0, 'b'}, {"backend", required_argument, 0, 'b'},
{"config", required_argument, 0, 'c'}, {"config", required_argument, 0, 'c'},
{"validate", no_argument, 0, 'C'}, {"validate", no_argument, 0, 'C'},
{"print-pid", required_argument, 0, 'p'},
{"version", no_argument, 0, 'v'}, {"version", no_argument, 0, 'v'},
{"help", no_argument, 0, 'h'}, {"help", no_argument, 0, 'h'},
{NULL, no_argument, 0, 0}, {NULL, no_argument, 0, 0},
}; };
bool unlink_pid_file = false;
const char *pid_file = NULL;
bool verify_config = false; bool verify_config = false;
char *config_path = NULL; char *config_path = NULL;
enum bar_backend backend = BAR_BACKEND_AUTO; enum bar_backend backend = BAR_BACKEND_AUTO;
while (true) { 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) if (c == -1)
break; break;
@ -185,6 +229,10 @@ main(int argc, char *const *argv)
verify_config = true; verify_config = true;
break; break;
case 'p':
pid_file = optarg;
break;
case 'v': case 'v':
printf("yambar version %s\n", YAMBAR_VERSION); printf("yambar version %s\n", YAMBAR_VERSION);
return EXIT_SUCCESS; return EXIT_SUCCESS;
@ -251,6 +299,11 @@ main(int argc, char *const *argv)
/* Now unblock. We should be only thread receiving SIGINT */ /* Now unblock. We should be only thread receiving SIGINT */
pthread_sigmask(SIG_UNBLOCK, &signal_mask, NULL); pthread_sigmask(SIG_UNBLOCK, &signal_mask, NULL);
if (pid_file != NULL) {
if (!print_pid(pid_file, &unlink_pid_file))
goto done;
}
while (!aborted) { while (!aborted) {
struct pollfd fds[] = {{.fd = abort_fd, .events = POLLIN}}; struct pollfd fds[] = {{.fd = abort_fd, .events = POLLIN}};
int r __attribute__((unused)) = poll(fds, 1, -1); int r __attribute__((unused)) = poll(fds, 1, -1);
@ -267,6 +320,7 @@ main(int argc, char *const *argv)
if (aborted) if (aborted)
LOG_INFO("aborted: %s (%d)", strsignal(aborted), aborted); LOG_INFO("aborted: %s (%d)", strsignal(aborted), aborted);
done:
/* Signal abort to other threads */ /* Signal abort to other threads */
if (write(abort_fd, &(uint64_t){1}, sizeof(uint64_t)) != sizeof(uint64_t)) if (write(abort_fd, &(uint64_t){1}, sizeof(uint64_t)) != sizeof(uint64_t))
LOG_ERRNO("failed to signal abort to threads"); LOG_ERRNO("failed to signal abort to threads");
@ -278,5 +332,8 @@ main(int argc, char *const *argv)
bar->destroy(bar); bar->destroy(bar);
close(abort_fd); close(abort_fd);
if (unlink_pid_file)
unlink(pid_file);
return res; return res;
} }