diff options
author | Paul Eggert <eggert@cs.ucla.edu> | 2018-12-01 23:06:06 -0800 |
---|---|---|
committer | Paul Eggert <eggert@cs.ucla.edu> | 2018-12-01 23:08:48 -0800 |
commit | 92282cb50248117185774cf8076d1ff83d501be7 (patch) | |
tree | 0e03dbd31e82b3f962b54c88ce0be1290b23d7ff /lib-src/emacsclient.c | |
parent | 070ef95c1007cb3d54e04bc337d9fb5463912cc1 (diff) | |
download | emacs-92282cb50248117185774cf8076d1ff83d501be7.tar.gz emacs-92282cb50248117185774cf8076d1ff83d501be7.tar.bz2 emacs-92282cb50248117185774cf8076d1ff83d501be7.zip |
emacsclient: prefer XDG_RUNTIME_DIR (Bug#33367)
* lib-src/emacsclient.c: Disable -Wformat-truncation=2,
to avoid false alarms about the new snprintf calls.
(local_sockname): New function.
(set_local_socket): Use it. Prefer XDG_RUNTIME_DIR (if set)
for location of socket directory. Avoid unnecessary memory
allocation by using snprintf to destination.
* lisp/server.el (server-socket-dir): Prefer XDG_RUNTIME_DIR if set.
Diffstat (limited to 'lib-src/emacsclient.c')
-rw-r--r-- | lib-src/emacsclient.c | 130 |
1 files changed, 77 insertions, 53 deletions
diff --git a/lib-src/emacsclient.c b/lib-src/emacsclient.c index c67d34f77ff..ba72651343f 100644 --- a/lib-src/emacsclient.c +++ b/lib-src/emacsclient.c @@ -87,6 +87,11 @@ char *w32_getenv (const char *); #define VERSION "unspecified" #endif +/* Work around GCC bug 88251. */ +#if GNUC_PREREQ (7, 0, 0) +# pragma GCC diagnostic ignored "-Wformat-truncation=2" +#endif + /* Name used to invoke this program. */ static char const *progname; @@ -1271,10 +1276,41 @@ act_on_signals (HSOCKET emacs_socket) } } -/* Create a local socket and connect it to Emacs. */ +/* Create in SOCKNAME (of size SOCKNAMESIZE) a name for a local socket. + The first TMPDIRLEN bytes of SOCKNAME are already initialized to be + the name of a temporary directory. Use UID and SERVER_NAME to + concoct the name. Return the total length of the name if successful, + -1 if it does not fit (and store a truncated name in that case). + Fail if TMPDIRLEN is out of range. */ + +static int +local_sockname (char *sockname, int socknamesize, int tmpdirlen, + uintmax_t uid, char const *server_name) +{ + /* If ! (0 <= TMPDIRLEN && TMPDIRLEN < SOCKNAMESIZE) the truncated + temporary directory name is already in SOCKNAME, so nothing more + need be stored. */ + if (0 <= tmpdirlen) + { + int remaining = socknamesize - tmpdirlen; + if (0 < remaining) + { + int suffixlen = snprintf (&sockname[tmpdirlen], remaining, + "/emacs%"PRIuMAX"/%s", uid, server_name); + if (0 <= suffixlen && suffixlen < remaining) + return tmpdirlen + suffixlen; + } + } + return -1; +} + +/* Create a local socket for SERVER_NAME and connect it to Emacs. If + SERVER_NAME is a file name component, the local socket name + relative to a well-known location in a temporary directory. + Otherwise, the local socket name is SERVER_NAME. */ static HSOCKET -set_local_socket (const char *local_socket_name) +set_local_socket (char const *server_name) { union { struct sockaddr_un un; @@ -1288,55 +1324,54 @@ set_local_socket (const char *local_socket_name) return INVALID_SOCKET; } - char const *server_name = local_socket_name; - char const *tmpdir = NULL; - char *tmpdir_storage = NULL; - char *socket_name_storage = NULL; - static char const subdir_format[] = "/emacs%"PRIuMAX"/"; - int subdir_size_bound = (sizeof subdir_format - sizeof "%"PRIuMAX - + INT_STRLEN_BOUND (uid_t) + 1); + char *sockname = server.un.sun_path; + enum { socknamesize = sizeof server.un.sun_path }; + int tmpdirlen = -1; + int socknamelen = -1; - if (! (strchr (local_socket_name, '/') - || (ISSLASH ('\\') && strchr (local_socket_name, '\\')))) + if (strchr (server_name, '/') + || (ISSLASH ('\\') && strchr (server_name, '\\'))) + socknamelen = snprintf (sockname, socknamesize, "%s", server_name); + else { /* socket_name is a file name component. */ - uintmax_t uid = geteuid (); - tmpdir = egetenv ("TMPDIR"); - if (!tmpdir) + char const *xdg_runtime_dir = egetenv ("XDG_RUNTIME_DIR"); + if (xdg_runtime_dir) + socknamelen = snprintf (sockname, socknamesize, "%s/emacs/%s", + xdg_runtime_dir, server_name); + else { + char const *tmpdir = egetenv ("TMPDIR"); + if (tmpdir) + tmpdirlen = snprintf (sockname, socknamesize, "%s", tmpdir); + else + { # ifdef DARWIN_OS # ifndef _CS_DARWIN_USER_TEMP_DIR # define _CS_DARWIN_USER_TEMP_DIR 65537 # endif - size_t n = confstr (_CS_DARWIN_USER_TEMP_DIR, NULL, 0); - if (n > 0) - { - tmpdir = tmpdir_storage = xmalloc (n); - confstr (_CS_DARWIN_USER_TEMP_DIR, tmpdir_storage, n); - } - else + size_t n = confstr (_CS_DARWIN_USER_TEMP_DIR, + sockname, socknamesize); + if (0 < n && n < (size_t) -1) + tmpdirlen = min (n - 1, socknamesize); # endif - tmpdir = "/tmp"; + if (tmpdirlen < 0) + tmpdirlen = snprintf (sockname, socknamesize, "/tmp"); + } + socknamelen = local_sockname (sockname, socknamesize, tmpdirlen, + geteuid (), server_name); } - socket_name_storage = - xmalloc (strlen (tmpdir) + strlen (server_name) + subdir_size_bound); - char *z = stpcpy (socket_name_storage, tmpdir); - strcpy (z + sprintf (z, subdir_format, uid), server_name); - local_socket_name = socket_name_storage; } - if (strlen (local_socket_name) < sizeof server.un.sun_path) - strcpy (server.un.sun_path, local_socket_name); - else + if (! (0 <= socknamelen && socknamelen < socknamesize)) { - message (true, "%s: socket-name %s too long\n", - progname, local_socket_name); + message (true, "%s: socket-name %s... too long\n", progname, sockname); fail (); } /* See if the socket exists, and if it's owned by us. */ - int sock_status = socket_status (server.un.sun_path); - if (sock_status && tmpdir) + int sock_status = socket_status (sockname); + if (sock_status) { /* Failing that, see if LOGNAME or USER exist and differ from our euid. If so, look for a socket based on the UID @@ -1355,31 +1390,20 @@ set_local_socket (const char *local_socket_name) if (pw && (pw->pw_uid != geteuid ())) { /* We're running under su, apparently. */ - uintmax_t uid = pw->pw_uid; - char *user_socket_name - = xmalloc (strlen (tmpdir) + strlen (server_name) - + subdir_size_bound); - char *z = stpcpy (user_socket_name, tmpdir); - strcpy (z + sprintf (z, subdir_format, uid), server_name); - - if (strlen (user_socket_name) < sizeof server.un.sun_path) - strcpy (server.un.sun_path, user_socket_name); - else + socknamelen = local_sockname (sockname, socknamesize, tmpdirlen, + pw->pw_uid, server_name); + if (socknamelen < 0) { - message (true, "%s: socket-name %s too long\n", - progname, user_socket_name); + message (true, "%s: socket-name %s... too long\n", + progname, sockname); exit (EXIT_FAILURE); } - free (user_socket_name); - sock_status = socket_status (server.un.sun_path); + sock_status = socket_status (sockname); } } } - free (socket_name_storage); - free (tmpdir_storage); - switch (sock_status) { case -1: @@ -1403,7 +1427,7 @@ set_local_socket (const char *local_socket_name) progname, progname); else message (true, "%s: can't stat %s: %s\n", - progname, server.un.sun_path, strerror (sock_status)); + progname, sockname, strerror (sock_status)); break; } @@ -1421,12 +1445,12 @@ set_socket (bool no_exit_if_error) INITIALIZE (); #ifdef SOCKETS_IN_FILE_SYSTEM - /* Explicit --socket-name argument. */ if (!socket_name) socket_name = egetenv ("EMACS_SOCKET_NAME"); if (socket_name) { + /* Explicit --socket-name argument, or environment variable. */ s = set_local_socket (socket_name); if (s != INVALID_SOCKET || no_exit_if_error) return s; |