diff options
| author | Paul Eggert | 2018-12-01 23:06:06 -0800 |
|---|---|---|
| committer | Paul Eggert | 2018-12-01 23:08:48 -0800 |
| commit | 92282cb50248117185774cf8076d1ff83d501be7 (patch) | |
| tree | 0e03dbd31e82b3f962b54c88ce0be1290b23d7ff /lib-src | |
| parent | 070ef95c1007cb3d54e04bc337d9fb5463912cc1 (diff) | |
| download | emacs-92282cb50248117185774cf8076d1ff83d501be7.tar.gz 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')
| -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 *); | |||
| 87 | #define VERSION "unspecified" | 87 | #define VERSION "unspecified" |
| 88 | #endif | 88 | #endif |
| 89 | 89 | ||
| 90 | /* Work around GCC bug 88251. */ | ||
| 91 | #if GNUC_PREREQ (7, 0, 0) | ||
| 92 | # pragma GCC diagnostic ignored "-Wformat-truncation=2" | ||
| 93 | #endif | ||
| 94 | |||
| 90 | 95 | ||
| 91 | /* Name used to invoke this program. */ | 96 | /* Name used to invoke this program. */ |
| 92 | static char const *progname; | 97 | static char const *progname; |
| @@ -1271,10 +1276,41 @@ act_on_signals (HSOCKET emacs_socket) | |||
| 1271 | } | 1276 | } |
| 1272 | } | 1277 | } |
| 1273 | 1278 | ||
| 1274 | /* Create a local socket and connect it to Emacs. */ | 1279 | /* Create in SOCKNAME (of size SOCKNAMESIZE) a name for a local socket. |
| 1280 | The first TMPDIRLEN bytes of SOCKNAME are already initialized to be | ||
| 1281 | the name of a temporary directory. Use UID and SERVER_NAME to | ||
| 1282 | concoct the name. Return the total length of the name if successful, | ||
| 1283 | -1 if it does not fit (and store a truncated name in that case). | ||
| 1284 | Fail if TMPDIRLEN is out of range. */ | ||
| 1285 | |||
| 1286 | static int | ||
| 1287 | local_sockname (char *sockname, int socknamesize, int tmpdirlen, | ||
| 1288 | uintmax_t uid, char const *server_name) | ||
| 1289 | { | ||
| 1290 | /* If ! (0 <= TMPDIRLEN && TMPDIRLEN < SOCKNAMESIZE) the truncated | ||
| 1291 | temporary directory name is already in SOCKNAME, so nothing more | ||
| 1292 | need be stored. */ | ||
| 1293 | if (0 <= tmpdirlen) | ||
| 1294 | { | ||
| 1295 | int remaining = socknamesize - tmpdirlen; | ||
| 1296 | if (0 < remaining) | ||
| 1297 | { | ||
| 1298 | int suffixlen = snprintf (&sockname[tmpdirlen], remaining, | ||
| 1299 | "/emacs%"PRIuMAX"/%s", uid, server_name); | ||
| 1300 | if (0 <= suffixlen && suffixlen < remaining) | ||
| 1301 | return tmpdirlen + suffixlen; | ||
| 1302 | } | ||
| 1303 | } | ||
| 1304 | return -1; | ||
| 1305 | } | ||
| 1306 | |||
| 1307 | /* Create a local socket for SERVER_NAME and connect it to Emacs. If | ||
| 1308 | SERVER_NAME is a file name component, the local socket name | ||
| 1309 | relative to a well-known location in a temporary directory. | ||
| 1310 | Otherwise, the local socket name is SERVER_NAME. */ | ||
| 1275 | 1311 | ||
| 1276 | static HSOCKET | 1312 | static HSOCKET |
| 1277 | set_local_socket (const char *local_socket_name) | 1313 | set_local_socket (char const *server_name) |
| 1278 | { | 1314 | { |
| 1279 | union { | 1315 | union { |
| 1280 | struct sockaddr_un un; | 1316 | struct sockaddr_un un; |
| @@ -1288,55 +1324,54 @@ set_local_socket (const char *local_socket_name) | |||
| 1288 | return INVALID_SOCKET; | 1324 | return INVALID_SOCKET; |
| 1289 | } | 1325 | } |
| 1290 | 1326 | ||
| 1291 | char const *server_name = local_socket_name; | 1327 | char *sockname = server.un.sun_path; |
| 1292 | char const *tmpdir = NULL; | 1328 | enum { socknamesize = sizeof server.un.sun_path }; |
| 1293 | char *tmpdir_storage = NULL; | 1329 | int tmpdirlen = -1; |
| 1294 | char *socket_name_storage = NULL; | 1330 | int socknamelen = -1; |
| 1295 | static char const subdir_format[] = "/emacs%"PRIuMAX"/"; | ||
| 1296 | int subdir_size_bound = (sizeof subdir_format - sizeof "%"PRIuMAX | ||
| 1297 | + INT_STRLEN_BOUND (uid_t) + 1); | ||
| 1298 | 1331 | ||
| 1299 | if (! (strchr (local_socket_name, '/') | 1332 | if (strchr (server_name, '/') |
| 1300 | || (ISSLASH ('\\') && strchr (local_socket_name, '\\')))) | 1333 | || (ISSLASH ('\\') && strchr (server_name, '\\'))) |
| 1334 | socknamelen = snprintf (sockname, socknamesize, "%s", server_name); | ||
| 1335 | else | ||
| 1301 | { | 1336 | { |
| 1302 | /* socket_name is a file name component. */ | 1337 | /* socket_name is a file name component. */ |
| 1303 | uintmax_t uid = geteuid (); | 1338 | char const *xdg_runtime_dir = egetenv ("XDG_RUNTIME_DIR"); |
| 1304 | tmpdir = egetenv ("TMPDIR"); | 1339 | if (xdg_runtime_dir) |
| 1305 | if (!tmpdir) | 1340 | socknamelen = snprintf (sockname, socknamesize, "%s/emacs/%s", |
| 1341 | xdg_runtime_dir, server_name); | ||
| 1342 | else | ||
| 1306 | { | 1343 | { |
| 1344 | char const *tmpdir = egetenv ("TMPDIR"); | ||
| 1345 | if (tmpdir) | ||
| 1346 | tmpdirlen = snprintf (sockname, socknamesize, "%s", tmpdir); | ||
| 1347 | else | ||
| 1348 | { | ||
| 1307 | # ifdef DARWIN_OS | 1349 | # ifdef DARWIN_OS |
| 1308 | # ifndef _CS_DARWIN_USER_TEMP_DIR | 1350 | # ifndef _CS_DARWIN_USER_TEMP_DIR |
| 1309 | # define _CS_DARWIN_USER_TEMP_DIR 65537 | 1351 | # define _CS_DARWIN_USER_TEMP_DIR 65537 |
| 1310 | # endif | 1352 | # endif |
| 1311 | size_t n = confstr (_CS_DARWIN_USER_TEMP_DIR, NULL, 0); | 1353 | size_t n = confstr (_CS_DARWIN_USER_TEMP_DIR, |
| 1312 | if (n > 0) | 1354 | sockname, socknamesize); |
| 1313 | { | 1355 | if (0 < n && n < (size_t) -1) |
| 1314 | tmpdir = tmpdir_storage = xmalloc (n); | 1356 | tmpdirlen = min (n - 1, socknamesize); |
| 1315 | confstr (_CS_DARWIN_USER_TEMP_DIR, tmpdir_storage, n); | ||
| 1316 | } | ||
| 1317 | else | ||
| 1318 | # endif | 1357 | # endif |
| 1319 | tmpdir = "/tmp"; | 1358 | if (tmpdirlen < 0) |
| 1359 | tmpdirlen = snprintf (sockname, socknamesize, "/tmp"); | ||
| 1360 | } | ||
| 1361 | socknamelen = local_sockname (sockname, socknamesize, tmpdirlen, | ||
| 1362 | geteuid (), server_name); | ||
| 1320 | } | 1363 | } |
| 1321 | socket_name_storage = | ||
| 1322 | xmalloc (strlen (tmpdir) + strlen (server_name) + subdir_size_bound); | ||
| 1323 | char *z = stpcpy (socket_name_storage, tmpdir); | ||
| 1324 | strcpy (z + sprintf (z, subdir_format, uid), server_name); | ||
| 1325 | local_socket_name = socket_name_storage; | ||
| 1326 | } | 1364 | } |
| 1327 | 1365 | ||
| 1328 | if (strlen (local_socket_name) < sizeof server.un.sun_path) | 1366 | if (! (0 <= socknamelen && socknamelen < socknamesize)) |
| 1329 | strcpy (server.un.sun_path, local_socket_name); | ||
| 1330 | else | ||
| 1331 | { | 1367 | { |
| 1332 | message (true, "%s: socket-name %s too long\n", | 1368 | message (true, "%s: socket-name %s... too long\n", progname, sockname); |
| 1333 | progname, local_socket_name); | ||
| 1334 | fail (); | 1369 | fail (); |
| 1335 | } | 1370 | } |
| 1336 | 1371 | ||
| 1337 | /* See if the socket exists, and if it's owned by us. */ | 1372 | /* See if the socket exists, and if it's owned by us. */ |
| 1338 | int sock_status = socket_status (server.un.sun_path); | 1373 | int sock_status = socket_status (sockname); |
| 1339 | if (sock_status && tmpdir) | 1374 | if (sock_status) |
| 1340 | { | 1375 | { |
| 1341 | /* Failing that, see if LOGNAME or USER exist and differ from | 1376 | /* Failing that, see if LOGNAME or USER exist and differ from |
| 1342 | our euid. If so, look for a socket based on the UID | 1377 | our euid. If so, look for a socket based on the UID |
| @@ -1355,31 +1390,20 @@ set_local_socket (const char *local_socket_name) | |||
| 1355 | if (pw && (pw->pw_uid != geteuid ())) | 1390 | if (pw && (pw->pw_uid != geteuid ())) |
| 1356 | { | 1391 | { |
| 1357 | /* We're running under su, apparently. */ | 1392 | /* We're running under su, apparently. */ |
| 1358 | uintmax_t uid = pw->pw_uid; | 1393 | socknamelen = local_sockname (sockname, socknamesize, tmpdirlen, |
| 1359 | char *user_socket_name | 1394 | pw->pw_uid, server_name); |
| 1360 | = xmalloc (strlen (tmpdir) + strlen (server_name) | 1395 | if (socknamelen < 0) |
| 1361 | + subdir_size_bound); | ||
| 1362 | char *z = stpcpy (user_socket_name, tmpdir); | ||
| 1363 | strcpy (z + sprintf (z, subdir_format, uid), server_name); | ||
| 1364 | |||
| 1365 | if (strlen (user_socket_name) < sizeof server.un.sun_path) | ||
| 1366 | strcpy (server.un.sun_path, user_socket_name); | ||
| 1367 | else | ||
| 1368 | { | 1396 | { |
| 1369 | message (true, "%s: socket-name %s too long\n", | 1397 | message (true, "%s: socket-name %s... too long\n", |
| 1370 | progname, user_socket_name); | 1398 | progname, sockname); |
| 1371 | exit (EXIT_FAILURE); | 1399 | exit (EXIT_FAILURE); |
| 1372 | } | 1400 | } |
| 1373 | free (user_socket_name); | ||
| 1374 | 1401 | ||
| 1375 | sock_status = socket_status (server.un.sun_path); | 1402 | sock_status = socket_status (sockname); |
| 1376 | } | 1403 | } |
| 1377 | } | 1404 | } |
| 1378 | } | 1405 | } |
| 1379 | 1406 | ||
| 1380 | free (socket_name_storage); | ||
| 1381 | free (tmpdir_storage); | ||
| 1382 | |||
| 1383 | switch (sock_status) | 1407 | switch (sock_status) |
| 1384 | { | 1408 | { |
| 1385 | case -1: | 1409 | case -1: |
| @@ -1403,7 +1427,7 @@ set_local_socket (const char *local_socket_name) | |||
| 1403 | progname, progname); | 1427 | progname, progname); |
| 1404 | else | 1428 | else |
| 1405 | message (true, "%s: can't stat %s: %s\n", | 1429 | message (true, "%s: can't stat %s: %s\n", |
| 1406 | progname, server.un.sun_path, strerror (sock_status)); | 1430 | progname, sockname, strerror (sock_status)); |
| 1407 | break; | 1431 | break; |
| 1408 | } | 1432 | } |
| 1409 | 1433 | ||
| @@ -1421,12 +1445,12 @@ set_socket (bool no_exit_if_error) | |||
| 1421 | INITIALIZE (); | 1445 | INITIALIZE (); |
| 1422 | 1446 | ||
| 1423 | #ifdef SOCKETS_IN_FILE_SYSTEM | 1447 | #ifdef SOCKETS_IN_FILE_SYSTEM |
| 1424 | /* Explicit --socket-name argument. */ | ||
| 1425 | if (!socket_name) | 1448 | if (!socket_name) |
| 1426 | socket_name = egetenv ("EMACS_SOCKET_NAME"); | 1449 | socket_name = egetenv ("EMACS_SOCKET_NAME"); |
| 1427 | 1450 | ||
| 1428 | if (socket_name) | 1451 | if (socket_name) |
| 1429 | { | 1452 | { |
| 1453 | /* Explicit --socket-name argument, or environment variable. */ | ||
| 1430 | s = set_local_socket (socket_name); | 1454 | s = set_local_socket (socket_name); |
| 1431 | if (s != INVALID_SOCKET || no_exit_if_error) | 1455 | if (s != INVALID_SOCKET || no_exit_if_error) |
| 1432 | return s; | 1456 | return s; |