summaryrefslogtreecommitdiff
path: root/lib-src
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2026-04-12 15:35:40 -0700
committerPaul Eggert <eggert@cs.ucla.edu>2026-04-12 23:21:02 -0700
commit180953c8f656edfc4333091d59d0d5cacbe277e9 (patch)
tree3f0d46ed061368c78b1afe877223c39ab1a8e15e /lib-src
parentca33663e5065fb9730924650ea9e86f486910fb3 (diff)
emacsclient config+sending long-line fixes
Do not mishandle long lines, or lines containing NUL, when getting configuration or sending data. * lib-src/emacsclient.c (send_to_emacs_len, quote_argument_len): New functions, generalizing the old send_to_emacs and quote_argument. Rewrite the old functions to use the new ones. (get_server_config): Do not mishandle long lines in the config file. (set_tcp_socket): No longer a need to null-terminate auth string. (main): Do not mishandle long lines from stdin, or lines with NUL.
Diffstat (limited to 'lib-src')
-rw-r--r--lib-src/emacsclient.c70
1 files changed, 44 insertions, 26 deletions
diff --git a/lib-src/emacsclient.c b/lib-src/emacsclient.c
index 4f3215ea6b1..fe5f405efb4 100644
--- a/lib-src/emacsclient.c
+++ b/lib-src/emacsclient.c
@@ -811,12 +811,12 @@ sock_err_message (const char *function_name)
}
-/* Send to S the data in *DATA when either
+/* Send to S the DATA, of size DLEN, when either
- the data's last byte is '\n', or
- - the buffer is full (but this shouldn't happen)
+ - the buffer is full.
Otherwise, just accumulate the data. */
static void
-send_to_emacs (HSOCKET s, const char *data)
+send_to_emacs_len (HSOCKET s, const char *data, ptrdiff_t dlen)
{
enum { SEND_BUFFER_SIZE = 4096 };
@@ -826,7 +826,7 @@ send_to_emacs (HSOCKET s, const char *data)
/* Fill pointer for the send buffer. */
static int sblen;
- for (ptrdiff_t dlen = strlen (data); dlen != 0; )
+ while (dlen != 0)
{
int part = min (dlen, SEND_BUFFER_SIZE - sblen);
memcpy (&send_buffer[sblen], data, part);
@@ -858,20 +858,27 @@ send_to_emacs (HSOCKET s, const char *data)
}
}
+/* Send to S the data in the string DATA. */
+static void
+send_to_emacs (HSOCKET s, const char *data)
+{
+ send_to_emacs_len (s, data, strlen (data));
+}
+
-/* In STR, insert a & before each &, each space, each newline, and
+/* Output to S a quoted copy of the array of bytes STR with length LEN.
+ Insert a & before each &, each space, each newline, and
any initial -. Change spaces to underscores, too, so that the
- return value never contains a space.
-
- Does not change the string. Outputs the result to S. */
+ output never contains a space. */
static void
-quote_argument (HSOCKET s, const char *str)
+quote_argument_len (HSOCKET s, const char *str, ptrdiff_t len)
{
- char *copy = xmalloc (strlen (str) * 2 + 1);
+ char const *lim = str + len;
+ char *copy = xmalloc (len * 2);
char *q = copy;
- if (*str == '-')
- *q++ = '&', *q++ = *str++;
- for (; *str; str++)
+ if (str < lim && *str == '-')
+ *q++ = '&';
+ for (; str < lim; str++)
{
char c = *str;
if (c == ' ')
@@ -882,13 +889,21 @@ quote_argument (HSOCKET s, const char *str)
*q++ = '&';
*q++ = c;
}
- *q = 0;
- send_to_emacs (s, copy);
+ send_to_emacs_len (s, copy, q - copy);
free (copy);
}
+/* Output to S a quoted copy of the string STR.
+ Insert a & before each &, each space, each newline, and
+ any initial -. Change spaces to underscores, too, so that the
+ output never contains a space. */
+static void
+quote_argument (HSOCKET s, const char *str)
+{
+ return quote_argument_len (s, str, strlen (str));
+}
/* The inverse of quote_argument. Remove quoting in string STR by
modifying the addressed string in place. Return STR. */
@@ -990,8 +1005,6 @@ static bool
get_server_config (const char *config_file, struct sockaddr_in *server,
char *authentication)
{
- char dotted[32];
- char *port;
FILE *config;
if (IS_ABSOLUTE_FILE_NAME (config_file))
@@ -1009,8 +1022,11 @@ get_server_config (const char *config_file, struct sockaddr_in *server,
if (! config)
return false;
- if (fgets (dotted, sizeof dotted, config)
- && (port = strchr (dotted, ':')))
+ char *dotted = NULL;
+ size_t dottedsize;
+ ssize_t dottedlen = getline (&dotted, &dottedsize, config);
+ char *port = dottedlen < 0 ? NULL : strchr (dotted, ':');
+ if (port)
*port++ = '\0';
else
{
@@ -1022,6 +1038,7 @@ get_server_config (const char *config_file, struct sockaddr_in *server,
server->sin_family = AF_INET;
server->sin_addr.s_addr = inet_addr (dotted);
server->sin_port = htons (atoi (port));
+ free (dotted);
if (! fread (authentication, AUTH_KEY_LENGTH, 1, config))
{
@@ -1060,9 +1077,9 @@ set_tcp_socket (const char *local_server_file)
struct sockaddr sa;
} server;
struct linger l_arg = { .l_onoff = 1, .l_linger = 1 };
- char auth_string[AUTH_KEY_LENGTH + 1];
+ char auth_buf[AUTH_KEY_LENGTH];
- if (! get_server_config (local_server_file, &server.in, auth_string))
+ if (! get_server_config (local_server_file, &server.in, auth_buf))
return INVALID_SOCKET;
if (server.in.sin_addr.s_addr != inet_addr ("127.0.0.1") && !quiet)
@@ -1096,10 +1113,8 @@ set_tcp_socket (const char *local_server_file)
sock_err_message ("setsockopt");
/* Send the authentication. */
- auth_string[AUTH_KEY_LENGTH] = '\0';
-
send_to_emacs (s, "-auth ");
- send_to_emacs (s, auth_string);
+ send_to_emacs_len (s, auth_buf, sizeof auth_buf);
send_to_emacs (s, " ");
return s;
@@ -2170,11 +2185,14 @@ main (int argc, char **argv)
else if (eval)
{
/* Read expressions interactively. */
- while (fgets (string, BUFSIZ, stdin))
+ char *line = NULL;
+ size_t linesize;
+ for (ssize_t len; 0 <= (len = getline (&line, &linesize, stdin)); )
{
send_to_emacs (emacs_socket, "-eval ");
- quote_argument (emacs_socket, string);
+ quote_argument_len (emacs_socket, line, len);
}
+ free (line);
send_to_emacs (emacs_socket, " ");
}