--- rxvt-unicode/src/rxvtd.C 2009/05/08 23:52:55 1.48 +++ rxvt-unicode/src/rxvtd.C 2021/07/23 19:18:52 1.67 @@ -3,11 +3,11 @@ *----------------------------------------------------------------------* * * All portions of code are copyright by their respective author/s. - * Copyright (c) 2003-2007 Marc Lehmann + * Copyright (c) 2003-2007 Marc Lehmann * * 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, @@ -21,10 +21,10 @@ *----------------------------------------------------------------------*/ #include "../config.h" -#include -#include -#include -#include +#include +#include +#include +#include #include #include @@ -41,13 +41,15 @@ # include #endif -#include +#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,19 +100,17 @@ 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); - unlink (rxvt_connection::unix_sockname ()); + unlink (sockname); mode_t omask = umask (0077); @@ -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) @@ -188,8 +196,6 @@ return err ("protocol error: unexpected NEW token.\n"); } - envv->push_back (0); - { rxvt_term *term = new rxvt_term; @@ -202,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; } @@ -217,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); } @@ -224,15 +233,68 @@ return err (); } -int opt_fork, opt_opendisplay, opt_quiet; -#if ENABLE_MLOCK -int opt_lock; +#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, const char *const *argv) +main (int argc, char *argv[]) { - rxvt_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 + static char *opt_eval; +#endif +#if ENABLE_MLOCK + static char opt_lock; +#endif for (int i = 1; i < argc; i++) { @@ -246,6 +308,10 @@ else if (!strcmp (argv [i], "-m") || !strcmp (argv [i], "--mlock")) opt_lock = 1; #endif +#if ENABLE_PERL + else if (!strcmp (argv [i], "-e") || !strcmp (argv [i], "--eval")) + opt_eval = argv [++i]; +#endif else { rxvt_log ("%s: unknown option '%s', aborting.\n", argv [0], argv [i]); @@ -253,23 +319,54 @@ } } + rxvt_init (); + +#if ENABLE_PERL + if (opt_eval) + { + rxvt_perl.init (); + rxvt_perl.eval (opt_eval); + } +#endif + // optionally open display and never release it. if (opt_opendisplay) 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) { - printf ("rxvt-unicode daemon listening on %s.\n", sockname); - fflush (stdout); + fputs ("received multiple file descriptors, aborting.\n", stderr); + exit (EXIT_FAILURE); } + else if (n == 1) + { + 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); + } + + unix_listener l (fd); - free (sockname); + chdir ("/"); pid_t pid = 0; if (opt_fork) @@ -294,10 +391,10 @@ else if (pid > 0) _exit (EXIT_SUCCESS); - ev_default_fork (); + ev_loop_fork (EV_DEFAULT_UC); } - ev_loop (0); + ev_run (); return EXIT_SUCCESS; }