>From 8debb5cd9ada5a8dc7d4a1e5300e7b913fe1e09b Mon Sep 17 00:00:00 2001 From: Matthew Leach Date: Sun, 7 Jan 2018 13:47:12 -0800 Subject: [PATCH 1/2] Fix `server-name' and `server-socket-dir' for Bug#24218 * lisp/server.el: (server-external-socket-initialised): New (server-name): Compute server name from `get-external-sockname'. (server-socket-dir): Compute socket dir from `get-external-sockname'. (server-start): Don't check for existing server when an uninitialised external socket has been passed to Emacs. * src/emacs.c: (main): Obtain socket name via getsockname and pass to `init_process_emacs'. * src/lisp.h: (init_process_emacs): Add second parameter. * src/process.c: (external_sock_name): New. (get-external-sockname): New. (init_process_emacs): Set `external_sock_name' to `sockname' parameter. --- lisp/server.el | 56 ++++++++++++++++++++++++++++++++++++-------------------- src/emacs.c | 16 +++++++++++++--- src/lisp.h | 2 +- src/process.c | 19 ++++++++++++++++++- 4 files changed, 68 insertions(+), 25 deletions(-) diff --git a/lisp/server.el b/lisp/server.el index ac0d701851..e8b53530c9 100644 --- a/lisp/server.el +++ b/lisp/server.el @@ -251,8 +251,16 @@ server-existing-buffer are done with it in the server.") (make-variable-buffer-local 'server-existing-buffer) -;;;###autoload -(defcustom server-name "server" +(defvar server-external-socket-initialised nil + "When an external socket is passed into Emacs, we need to call +`server-start' in order to initialise the connection. This flag +prevents multiple initialisations when an external socket has +been consumed.") + +(defcustom server-name + (if (get-external-sockname) + (file-name-nondirectory (get-external-sockname)) + "server") "The name of the Emacs server, if this Emacs process creates one. The command `server-start' makes use of this. It should not be changed while a server is running." @@ -263,8 +271,10 @@ server-name ;; We do not use `temporary-file-directory' here, because emacsclient ;; does not read the init file. (defvar server-socket-dir - (and (featurep 'make-network-process '(:family local)) - (format "%s/emacs%d" (or (getenv "TMPDIR") "/tmp") (user-uid))) + (if (get-external-sockname) + (file-name-directory (get-external-sockname)) + (and (featurep 'make-network-process '(:family local)) + (format "%s/emacs%d" (or (getenv "TMPDIR") "/tmp") (user-uid)))) "The directory in which to place the server socket. If local sockets are not supported, this is nil.") @@ -618,23 +628,29 @@ server-start (when server-process ;; kill it dead! (ignore-errors (delete-process server-process))) - ;; Delete the socket files made by previous server invocations. - (if (not (eq t (server-running-p server-name))) - ;; Remove any leftover socket or authentication file - (ignore-errors - (let (delete-by-moving-to-trash) - (delete-file server-file))) - (setq server-mode nil) ;; already set by the minor mode code - (display-warning - 'server - (concat "Unable to start the Emacs server.\n" - (format "There is an existing Emacs server, named %S.\n" - server-name) - (substitute-command-keys - "To start the server in this Emacs process, stop the existing + ;; Check to see if an uninitialised external socket has been + ;; passed in, if that is the case, skip checking + ;; `server-running-p' as this will return the wrong result. + (if (and (get-external-sockname) + (not server-external-socket-initialised)) + (setq server-external-socket-initialised t) + ;; Delete the socket files made by previous server invocations. + (if (not (eq t (server-running-p server-name))) + ;; Remove any leftover socket or authentication file + (ignore-errors + (let (delete-by-moving-to-trash) + (delete-file server-file))) + (setq server-mode nil) ;; already set by the minor mode code + (display-warning + 'server + (concat "Unable to start the Emacs server.\n" + (format "There is an existing Emacs server, named %S.\n" + server-name) + (substitute-command-keys + "To start the server in this Emacs process, stop the existing server or call `\\[server-force-delete]' to forcibly disconnect it.")) - :warning) - (setq leave-dead t)) + :warning) + (setq leave-dead t))) ;; If this Emacs already had a server, clear out associated status. (while server-clients (server-delete-client (car server-clients))) diff --git a/src/emacs.c b/src/emacs.c index 20ced26283..1af09166b6 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -60,6 +60,7 @@ along with GNU Emacs. If not, see . */ #ifdef HAVE_LIBSYSTEMD # include # include +# include #endif #ifdef HAVE_WINDOW_SYSTEM @@ -1002,6 +1003,7 @@ main (int argc, char **argv) int sockfd = -1; + char *sockname = NULL; if (argmatch (argv, argc, "-fg-daemon", "--fg-daemon", 10, NULL, &skip_args) || argmatch (argv, argc, "-fg-daemon", "--fg-daemon", 10, &dname_arg, &skip_args)) @@ -1061,8 +1063,16 @@ main (int argc, char **argv) "Try 'Accept=false' in the Emacs socket unit file.\n")); else if (systemd_socket == 1 && (0 < sd_is_socket (SD_LISTEN_FDS_START, - AF_UNSPEC, SOCK_STREAM, 1))) - sockfd = SD_LISTEN_FDS_START; + AF_UNIX, SOCK_STREAM, 1))) + { + struct sockaddr_un sockaddr; + socklen_t sockaddr_sz = sizeof(sockaddr); + + sockfd = SD_LISTEN_FDS_START; + + if (!getsockname(sockfd, &sockaddr, &sockaddr_sz)) + sockname = strdup(sockaddr.sun_path); + } #endif /* HAVE_LIBSYSTEMD */ #ifdef USE_GTK @@ -1656,7 +1666,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem /* This can create a thread that may call getenv, so it must follow all calls to putenv and setenv. Also, this sets up add_keyboard_wait_descriptor, which init_display uses. */ - init_process_emacs (sockfd); + init_process_emacs (sockfd, sockname); init_keyboard (); /* This too must precede init_sys_modes. */ if (!noninteractive) diff --git a/src/lisp.h b/src/lisp.h index 3eb6e0d3c1..2e9002a226 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -4313,7 +4313,7 @@ extern void delete_keyboard_wait_descriptor (int); extern void add_gpm_wait_descriptor (int); extern void delete_gpm_wait_descriptor (int); #endif -extern void init_process_emacs (int); +extern void init_process_emacs (int, char *); extern void syms_of_process (void); extern void setup_process_coding_systems (Lisp_Object); diff --git a/src/process.c b/src/process.c index d4440e472d..da8e5714b0 100644 --- a/src/process.c +++ b/src/process.c @@ -276,6 +276,10 @@ static int max_desc; the file descriptor of a socket that is already bound. */ static int external_sock_fd; +/* The name (path) of the socket that was passed to Emacs, when + `external_sock_fd' is not -1. */ +static const char *external_sock_name = NULL; + /* Indexed by descriptor, gives the process (if any) for that descriptor. */ static Lisp_Object chan_process[FD_SETSIZE]; static void wait_for_socket_fds (Lisp_Object, char const *); @@ -7974,10 +7978,21 @@ restore_nofile_limit (void) } +DEFUN ("get-external-sockname", Fget_external_sockname, Sget_external_sockname, 0, 0, 0, + doc: /* Return the path of an external socket passed to Emacs. +Otherwise return nil. */) + (void) +{ + if (external_sock_name) + return make_string(external_sock_name, strlen(external_sock_name)); + else + return Qnil; +} + /* This is not called "init_process" because that is the name of a Mach system call, so it would cause problems on Darwin systems. */ void -init_process_emacs (int sockfd) +init_process_emacs (int sockfd, char *sockname) { #ifdef subprocesses int i; @@ -8012,6 +8027,7 @@ init_process_emacs (int sockfd) #endif external_sock_fd = sockfd; + external_sock_name = sockname; max_desc = -1; memset (fd_callback_info, 0, sizeof (fd_callback_info)); @@ -8306,4 +8322,5 @@ returns non-`nil'. */); defsubr (&Sprocess_inherit_coding_system_flag); defsubr (&Slist_system_processes); defsubr (&Sprocess_attributes); + defsubr (&Sget_external_sockname); } -- 2.14.3