--- rxvt-unicode/src/rxvtd.C 2012/06/12 10:45:53 1.60 +++ rxvt-unicode/src/rxvtd.C 2021/07/23 19:18:52 1.67 @@ -7,7 +7,7 @@ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, @@ -43,11 +43,13 @@ #include +#include + #include "rxvt.h" #include "rxvtdaemon.h" -#include "libptytty.h" -struct server : rxvt_connection { +struct server : rxvt_connection +{ log_callback log_cb; getfd_callback getfd_cb; @@ -70,18 +72,26 @@ void err (const char *format = 0, ...); }; -struct unix_listener { +struct unix_listener +{ int fd; void accept_cb (ev::io &w, int revents); ev::io accept_ev; - unix_listener (const char *sockname); + unix_listener (int fd); + static int open (const char *sockname); }; -unix_listener::unix_listener (const char *sockname) +unix_listener::unix_listener (int fd) : fd (fd) { accept_ev.set (this); + fcntl (fd, F_SETFD, FD_CLOEXEC); + fcntl (fd, F_SETFL, O_NONBLOCK); + accept_ev.start (fd, ev::READ); +} +int unix_listener::open (const char *sockname) +{ sockaddr_un sa; if (strlen (sockname) >= sizeof(sa.sun_path)) @@ -90,15 +100,13 @@ exit (EXIT_FAILURE); } + int fd; if ((fd = socket (AF_UNIX, SOCK_STREAM, 0)) < 0) { perror ("unable to create listening socket"); exit (EXIT_FAILURE); } - fcntl (fd, F_SETFD, FD_CLOEXEC); - fcntl (fd, F_SETFL, O_NONBLOCK); - sa.sun_family = AF_UNIX; strcpy (sa.sun_path, sockname); @@ -120,7 +128,7 @@ exit (EXIT_FAILURE); } - accept_ev.start (fd, ev::READ); + return fd; } void unix_listener::accept_cb (ev::io &w, int revents) @@ -200,8 +208,9 @@ { term->init (argv, envv); } - catch (const class rxvt_failure_exception &e) + catch (const std::exception &e) { + log_msg (e.what()); success = false; } @@ -215,6 +224,8 @@ send ("END"); send (success ? 1 : 0); } } + else if (!strcmp (tok, "QUIT")) + _exit (0); else return err ("protocol error: request '%s' unsupported.\n", (char *)tok); } @@ -222,10 +233,60 @@ return err (); } +#ifdef ENABLE_FRILLS +enum { + SD_LISTEN_FDS_START = 3, +}; + +// https://www.freedesktop.org/software/systemd/man/sd_listen_fds.html +// https://github.com/systemd/systemd/blob/main/src/libsystemd/sd-daemon/sd-daemon.c +static int get_listen_fds () +{ + const char *listen_pid = getenv ("LISTEN_PID"); + if (!listen_pid) + return 0; + + char *end; + errno = 0; + long pid = strtol (listen_pid, &end, 10); + if (errno || end == listen_pid || *end) + return -1; + + if (getpid () != pid) + return 0; + + const char *listen_fds = getenv ("LISTEN_FDS"); + if (!listen_fds) + return 0; + + errno = 0; + long n = strtol (listen_fds, &end, 10); + if (errno || end == listen_fds || *end) + return -1; + + if (n <= 0 || n > INT_MAX - SD_LISTEN_FDS_START) + return -1; + + unsetenv ("LISTEN_PID"); + unsetenv ("LISTEN_FDS"); + unsetenv ("LISTEN_FDNAMES"); + + return n; +} +#endif + int main (int argc, char *argv[]) { - ptytty::init (); + try + { + ptytty::init (); + } + catch (const std::exception &e) + { + fputs (e.what (), stderr); + return EXIT_FAILURE; + } static char opt_fork, opt_opendisplay, opt_quiet; #if ENABLE_PERL @@ -273,18 +334,39 @@ if (const char *dpy = getenv ("DISPLAY")) displays.get (dpy ? dpy : ":0"); // move string logic into rxvt_display maybe? - char *sockname = rxvt_connection::unix_sockname (); - unix_listener l (sockname); - - chdir ("/"); - - if (!opt_quiet) + int fd; +#ifdef ENABLE_FRILLS + int n = get_listen_fds (); + if (n > 1) + { + fputs ("received multiple file descriptors, aborting.\n", stderr); + exit (EXIT_FAILURE); + } + else if (n == 1) { - printf ("rxvt-unicode daemon listening on %s.\n", sockname); - fflush (stdout); + fd = SD_LISTEN_FDS_START; + if (!opt_quiet) + { + printf ("rxvt-unicode daemon listening on fd.\n"); + fflush (stdout); + } + } + else +#endif + { + char *sockname = rxvt_connection::unix_sockname (); + fd = unix_listener::open (sockname); + if (!opt_quiet) + { + printf ("rxvt-unicode daemon listening on %s.\n", sockname); + fflush (stdout); + } + free (sockname); } - free (sockname); + unix_listener l (fd); + + chdir ("/"); pid_t pid = 0; if (opt_fork)