blob: 6268fcaa31d64221dc38e54da5230ad53feed3e2 [file] [log] [blame]
Jeremy Kerr9326d772016-03-17 17:15:02 +08001/**
2 * Copyright © 2016 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Jeremy Kerr2bd05182016-03-10 16:59:43 +080016
Jeremy Kerrce0e68b2016-03-18 13:55:46 +080017#include <assert.h>
Jeremy Kerr2bd05182016-03-10 16:59:43 +080018#include <err.h>
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +080019#include <errno.h>
Andrew Jeffery5c359cc2023-04-18 22:50:07 +093020#include <limits.h>
Jeremy Kerr2bd05182016-03-10 16:59:43 +080021#include <stdbool.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <termios.h>
26#include <unistd.h>
27#include <endian.h>
28
29#include <sys/socket.h>
30#include <sys/un.h>
Jonathan Domancc075302023-03-31 10:20:48 -070031#include <systemd/sd-daemon.h>
Jeremy Kerr2bd05182016-03-10 16:59:43 +080032
33#include "console-server.h"
34
Johnathan Mantey1cecc5d2019-02-28 15:01:46 -080035#define SOCKET_HANDLER_PKT_SIZE 512
36/* Set poll() timeout to 4000 uS, or 4 mS */
37#define SOCKET_HANDLER_PKT_US_TIMEOUT 4000
38
Jeremy Kerr2bd05182016-03-10 16:59:43 +080039struct client {
Andrew Jefferya72711a2023-04-18 18:19:41 +093040 struct socket_handler *sh;
41 struct poller *poller;
42 struct ringbuffer_consumer *rbc;
43 int fd;
44 bool blocked;
Jeremy Kerr2bd05182016-03-10 16:59:43 +080045};
46
47struct socket_handler {
Andrew Jefferya72711a2023-04-18 18:19:41 +093048 struct handler handler;
49 struct console *console;
50 struct poller *poller;
51 int sd;
Jeremy Kerr2bd05182016-03-10 16:59:43 +080052
Andrew Jefferya72711a2023-04-18 18:19:41 +093053 struct client **clients;
54 int n_clients;
Jeremy Kerr2bd05182016-03-10 16:59:43 +080055};
56
Johnathan Mantey1cecc5d2019-02-28 15:01:46 -080057static struct timeval const socket_handler_timeout = {
58 .tv_sec = 0,
59 .tv_usec = SOCKET_HANDLER_PKT_US_TIMEOUT
60};
61
Jeremy Kerr2bd05182016-03-10 16:59:43 +080062static struct socket_handler *to_socket_handler(struct handler *handler)
63{
64 return container_of(handler, struct socket_handler, handler);
65}
66
Jeremy Kerrc9775ce2017-02-07 16:25:34 +080067static void client_close(struct client *client)
Jeremy Kerr2bd05182016-03-10 16:59:43 +080068{
Jeremy Kerrc9775ce2017-02-07 16:25:34 +080069 struct socket_handler *sh = client->sh;
Jeremy Kerr2bd05182016-03-10 16:59:43 +080070 int idx;
71
72 close(client->fd);
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093073 if (client->poller) {
Jeremy Kerr55c97122017-02-07 17:06:46 +080074 console_poller_unregister(sh->console, client->poller);
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093075 }
Jeremy Kerr2bd05182016-03-10 16:59:43 +080076
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093077 if (client->rbc) {
Jeremy Kerrc9775ce2017-02-07 16:25:34 +080078 ringbuffer_consumer_unregister(client->rbc);
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093079 }
Jeremy Kerrc9775ce2017-02-07 16:25:34 +080080
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093081 for (idx = 0; idx < sh->n_clients; idx++) {
82 if (sh->clients[idx] == client) {
Jeremy Kerrce0e68b2016-03-18 13:55:46 +080083 break;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093084 }
85 }
Jeremy Kerrce0e68b2016-03-18 13:55:46 +080086
87 assert(idx < sh->n_clients);
88
89 free(client);
90 client = NULL;
Jeremy Kerr2bd05182016-03-10 16:59:43 +080091
92 sh->n_clients--;
Andrew Jeffery91b52172023-04-19 12:42:14 +093093 /*
94 * We're managing an array of pointers to aggregates, so don't warn about sizeof() on a
95 * pointer type.
96 */
97 /* NOLINTBEGIN(bugprone-sizeof-expression) */
Andrew Jefferya72711a2023-04-18 18:19:41 +093098 memmove(&sh->clients[idx], &sh->clients[idx + 1],
99 sizeof(*sh->clients) * (sh->n_clients - idx));
Andrew Jeffery7851a392024-07-09 16:30:22 +0930100 if (sh->n_clients == 0) {
101 free(sh->clients);
102 sh->clients = NULL;
103 } else {
104 sh->clients = reallocarray(sh->clients, sh->n_clients,
105 sizeof(*sh->clients));
106 }
Andrew Jeffery91b52172023-04-19 12:42:14 +0930107 /* NOLINTEND(bugprone-sizeof-expression) */
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800108}
109
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800110static void client_set_blocked(struct client *client, bool blocked)
Jeremy Kerr848fc872017-01-17 13:50:05 +0800111{
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800112 int events;
113
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930114 if (client->blocked == blocked) {
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800115 return;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930116 }
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800117
118 client->blocked = blocked;
119
120 events = POLLIN;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930121 if (client->blocked) {
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800122 events |= POLLOUT;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930123 }
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800124
125 console_poller_set_events(client->sh->console, client->poller, events);
126}
127
Andrew Jefferya72711a2023-04-18 18:19:41 +0930128static ssize_t send_all(struct client *client, void *buf, size_t len,
129 bool block)
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800130{
Andrew Jefferyb70f8712023-04-19 12:53:34 +0930131 int fd;
132 int flags;
Andrew Jeffery5c359cc2023-04-18 22:50:07 +0930133 ssize_t rc;
Jeremy Kerr848fc872017-01-17 13:50:05 +0800134 size_t pos;
135
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930136 if (len > SSIZE_MAX) {
Andrew Jeffery5c359cc2023-04-18 22:50:07 +0930137 return -EINVAL;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930138 }
Andrew Jeffery5c359cc2023-04-18 22:50:07 +0930139
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800140 fd = client->fd;
141
Jeremy Kerr848fc872017-01-17 13:50:05 +0800142 flags = MSG_NOSIGNAL;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930143 if (!block) {
Jeremy Kerr848fc872017-01-17 13:50:05 +0800144 flags |= MSG_DONTWAIT;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930145 }
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800146
147 for (pos = 0; pos < len; pos += rc) {
Andrew Jeffery21f4cb42023-04-18 14:38:37 +0930148 rc = send(fd, (char *)buf + pos, len - pos, flags);
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800149 if (rc < 0) {
Andrew Jefferya72711a2023-04-18 18:19:41 +0930150 if (!block &&
151 (errno == EAGAIN || errno == EWOULDBLOCK)) {
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800152 client_set_blocked(client, true);
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800153 break;
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800154 }
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800155
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930156 if (errno == EINTR) {
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800157 continue;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930158 }
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800159
160 return -1;
161 }
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930162 if (rc == 0) {
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800163 return -1;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930164 }
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800165 }
166
Andrew Jeffery5c359cc2023-04-18 22:50:07 +0930167 return (ssize_t)pos;
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800168}
169
Jeremy Kerr848fc872017-01-17 13:50:05 +0800170/* Drain the queue to the socket and update the queue buffer. If force_len is
171 * set, send at least that many bytes from the queue, possibly while blocking
172 */
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800173static int client_drain_queue(struct client *client, size_t force_len)
Jeremy Kerr848fc872017-01-17 13:50:05 +0800174{
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800175 uint8_t *buf;
Jeremy Kerr848fc872017-01-17 13:50:05 +0800176 ssize_t wlen;
Andrew Jefferyb70f8712023-04-19 12:53:34 +0930177 size_t len;
178 size_t total_len;
Jeremy Kerr848fc872017-01-17 13:50:05 +0800179 bool block;
180
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800181 total_len = 0;
182 wlen = 0;
183 block = !!force_len;
Jeremy Kerr848fc872017-01-17 13:50:05 +0800184
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800185 /* if we're already blocked, no need for the write */
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930186 if (!block && client->blocked) {
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800187 return 0;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930188 }
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800189
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800190 for (;;) {
191 len = ringbuffer_dequeue_peek(client->rbc, total_len, &buf);
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930192 if (!len) {
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800193 break;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930194 }
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800195
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800196 wlen = send_all(client, buf, len, block);
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930197 if (wlen <= 0) {
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800198 break;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930199 }
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800200
201 total_len += wlen;
202
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930203 if (force_len && total_len >= force_len) {
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800204 break;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930205 }
Jeremy Kerr848fc872017-01-17 13:50:05 +0800206 }
207
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930208 if (wlen < 0) {
Jeremy Kerr848fc872017-01-17 13:50:05 +0800209 return -1;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930210 }
Jeremy Kerr848fc872017-01-17 13:50:05 +0800211
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930212 if (force_len && total_len < force_len) {
Jeremy Kerr848fc872017-01-17 13:50:05 +0800213 return -1;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930214 }
Jeremy Kerr848fc872017-01-17 13:50:05 +0800215
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800216 ringbuffer_dequeue_commit(client->rbc, total_len);
Jeremy Kerr848fc872017-01-17 13:50:05 +0800217 return 0;
218}
219
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800220static enum ringbuffer_poll_ret client_ringbuffer_poll(void *arg,
Andrew Jefferya72711a2023-04-18 18:19:41 +0930221 size_t force_len)
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800222{
223 struct client *client = arg;
Andrew Jeffery5c359cc2023-04-18 22:50:07 +0930224 size_t len;
225 int rc;
Johnathan Mantey1cecc5d2019-02-28 15:01:46 -0800226
227 len = ringbuffer_len(client->rbc);
228 if (!force_len && (len < SOCKET_HANDLER_PKT_SIZE)) {
229 /* Do nothing until many small requests have accumulated, or
230 * the UART is idle for awhile (as determined by the timeout
231 * value supplied to the poll function call in console_server.c. */
232 console_poller_set_timeout(client->sh->console, client->poller,
233 &socket_handler_timeout);
234 return RINGBUFFER_POLL_OK;
235 }
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800236
237 rc = client_drain_queue(client, force_len);
238 if (rc) {
239 client->rbc = NULL;
240 client_close(client);
241 return RINGBUFFER_POLL_REMOVE;
242 }
243
244 return RINGBUFFER_POLL_OK;
245}
246
Andrew Jefferya72711a2023-04-18 18:19:41 +0930247static enum poller_ret
248client_timeout(struct handler *handler __attribute__((unused)), void *data)
Johnathan Mantey1cecc5d2019-02-28 15:01:46 -0800249{
250 struct client *client = data;
251 int rc = 0;
252
253 if (client->blocked) {
254 /* nothing to do here, we'll call client_drain_queue when
255 * we become unblocked */
256 return POLLER_OK;
257 }
258
259 rc = client_drain_queue(client, 0);
260 if (rc) {
261 client_close(client);
262 return POLLER_REMOVE;
263 }
264
265 return POLLER_OK;
266}
267
Andrew Jefferya72711a2023-04-18 18:19:41 +0930268static enum poller_ret client_poll(struct handler *handler, int events,
269 void *data)
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800270{
271 struct socket_handler *sh = to_socket_handler(handler);
272 struct client *client = data;
273 uint8_t buf[4096];
Andrew Jeffery5c359cc2023-04-18 22:50:07 +0930274 ssize_t rc;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800275
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800276 if (events & POLLIN) {
Jeremy Kerr68a2ece2017-01-17 13:52:41 +0800277 rc = recv(client->fd, buf, sizeof(buf), MSG_DONTWAIT);
Jeremy Kerr848fc872017-01-17 13:50:05 +0800278 if (rc < 0) {
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930279 if (errno == EAGAIN || errno == EWOULDBLOCK) {
Jeremy Kerr848fc872017-01-17 13:50:05 +0800280 return POLLER_OK;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930281 }
Andrew Jeffery0b7b0472023-04-19 12:48:51 +0930282 goto err_close;
Jeremy Kerr848fc872017-01-17 13:50:05 +0800283 }
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930284 if (rc == 0) {
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800285 goto err_close;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930286 }
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800287
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800288 console_data_out(sh->console, buf, rc);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800289 }
290
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800291 if (events & POLLOUT) {
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800292 client_set_blocked(client, false);
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800293 rc = client_drain_queue(client, 0);
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930294 if (rc) {
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800295 goto err_close;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930296 }
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800297 }
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800298
299 return POLLER_OK;
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800300
301err_close:
302 client->poller = NULL;
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800303 client_close(client);
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800304 return POLLER_REMOVE;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800305}
306
Andrew Jefferya72711a2023-04-18 18:19:41 +0930307static enum poller_ret socket_poll(struct handler *handler, int events,
308 void __attribute__((unused)) * data)
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800309{
310 struct socket_handler *sh = to_socket_handler(handler);
311 struct client *client;
Andrew Jefferyb70f8712023-04-19 12:53:34 +0930312 int fd;
313 int n;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800314
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930315 if (!(events & POLLIN)) {
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800316 return POLLER_OK;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930317 }
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800318
Jeremy Kerr68a2ece2017-01-17 13:52:41 +0800319 fd = accept(sh->sd, NULL, NULL);
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930320 if (fd < 0) {
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800321 return POLLER_OK;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930322 }
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800323
Jeremy Kerrce0e68b2016-03-18 13:55:46 +0800324 client = malloc(sizeof(*client));
325 memset(client, 0, sizeof(*client));
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800326
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800327 client->sh = sh;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800328 client->fd = fd;
Jeremy Kerr55c97122017-02-07 17:06:46 +0800329 client->poller = console_poller_register(sh->console, handler,
Andrew Jefferya72711a2023-04-18 18:19:41 +0930330 client_poll, client_timeout,
331 client->fd, POLLIN, client);
332 client->rbc = console_ringbuffer_consumer_register(
333 sh->console, client_ringbuffer_poll, client);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800334
Jeremy Kerrce0e68b2016-03-18 13:55:46 +0800335 n = sh->n_clients++;
Andrew Jeffery91b52172023-04-19 12:42:14 +0930336 /*
337 * We're managing an array of pointers to aggregates, so don't warn about sizeof() on a
338 * pointer type.
339 */
340 /* NOLINTBEGIN(bugprone-sizeof-expression) */
Andrew Jefferya72711a2023-04-18 18:19:41 +0930341 sh->clients =
Andrew Jeffery91b52172023-04-19 12:42:14 +0930342 reallocarray(sh->clients, sh->n_clients, sizeof(*sh->clients));
343 /* NOLINTEND(bugprone-sizeof-expression) */
Jeremy Kerrce0e68b2016-03-18 13:55:46 +0800344 sh->clients[n] = client;
345
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800346 return POLLER_OK;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800347}
348
Ninad Palsulebd992c92023-05-09 18:30:01 -0500349/* Create socket pair and register one end as poller/consumer and return
350 * the other end to the caller.
351 * Return file descriptor on success and negative value on error.
352 */
353int dbus_create_socket_consumer(struct console *console)
354{
355 struct socket_handler *sh = NULL;
356 struct client *client;
357 int fds[2];
358 int i;
359 int rc = -1;
360 int n;
361
362 for (i = 0; i < console->n_handlers; i++) {
Jeremy Kerre2826c72024-07-05 10:54:21 +0800363 if (strcmp(console->handlers[i]->type->name, "socket") == 0) {
Ninad Palsulebd992c92023-05-09 18:30:01 -0500364 sh = to_socket_handler(console->handlers[i]);
365 break;
366 }
367 }
368
369 if (!sh) {
370 return -ENOSYS;
371 }
372
373 /* Create a socketpair */
374 rc = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
375 if (rc < 0) {
376 warn("Failed to create socket pair");
377 return -errno;
378 }
379
380 client = malloc(sizeof(*client));
381 if (client == NULL) {
382 warnx("Failed to allocate client structure.");
383 rc = -ENOMEM;
384 goto close_fds;
385 }
386 memset(client, 0, sizeof(*client));
387
388 client->sh = sh;
389 client->fd = fds[0];
390 client->poller = console_poller_register(sh->console, &sh->handler,
391 client_poll, client_timeout,
392 client->fd, POLLIN, client);
393 client->rbc = console_ringbuffer_consumer_register(
394 sh->console, client_ringbuffer_poll, client);
395 if (client->rbc == NULL) {
396 warnx("Failed to register a consumer.\n");
397 rc = -ENOMEM;
398 goto free_client;
399 }
400
401 n = sh->n_clients++;
402
403 /*
404 * We're managing an array of pointers to aggregates, so don't warn about
405 * sizeof() on a pointer type.
406 */
407 /* NOLINTBEGIN(bugprone-sizeof-expression) */
408 sh->clients =
409 reallocarray(sh->clients, sh->n_clients, sizeof(*sh->clients));
410 /* NOLINTEND(bugprone-sizeof-expression) */
411 sh->clients[n] = client;
412
413 /* Return the second FD to caller. */
414 return fds[1];
415
416free_client:
417 free(client);
418close_fds:
419 close(fds[0]);
420 close(fds[1]);
421 return rc;
422}
423
Jeremy Kerre2826c72024-07-05 10:54:21 +0800424static struct handler *socket_init(const struct handler_type *type
425 __attribute__((unused)),
426 struct console *console,
427 struct config *config
428 __attribute__((unused)))
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800429{
Jeremy Kerre2826c72024-07-05 10:54:21 +0800430 struct socket_handler *sh;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800431 struct sockaddr_un addr;
Andrew Jeffery5e7c0782020-02-10 12:12:36 +1030432 size_t addrlen;
433 ssize_t len;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800434 int rc;
435
Jeremy Kerre2826c72024-07-05 10:54:21 +0800436 sh = malloc(sizeof(*sh));
437 if (!sh) {
438 return NULL;
439 }
440
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800441 sh->console = console;
442 sh->clients = NULL;
443 sh->n_clients = 0;
Jeremy Kerr5708dfb2017-01-19 15:11:19 +0800444
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800445 memset(&addr, 0, sizeof(addr));
446 addr.sun_family = AF_UNIX;
Andrew Jeffery954be0f2023-05-03 21:01:59 +0930447 len = console_socket_path(addr.sun_path, console->console_id);
Andrew Jeffery5e7c0782020-02-10 12:12:36 +1030448 if (len < 0) {
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930449 if (errno) {
Andrew Jeffery5e7c0782020-02-10 12:12:36 +1030450 warn("Failed to configure socket: %s", strerror(errno));
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930451 } else {
Andrew Jeffery5e7c0782020-02-10 12:12:36 +1030452 warn("Socket name length exceeds buffer limits");
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930453 }
Jeremy Kerre2826c72024-07-05 10:54:21 +0800454 goto err_free;
Andrew Jeffery5e7c0782020-02-10 12:12:36 +1030455 }
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800456
Jonathan Domancc075302023-03-31 10:20:48 -0700457 /* Try to take a socket from systemd first */
458 if (sd_listen_fds(0) == 1 &&
Andrew Jefferya72711a2023-04-18 18:19:41 +0930459 sd_is_socket_unix(SD_LISTEN_FDS_START, SOCK_STREAM, 1,
460 addr.sun_path, len) > 0) {
Jonathan Domancc075302023-03-31 10:20:48 -0700461 sh->sd = SD_LISTEN_FDS_START;
462 } else {
463 sh->sd = socket(AF_UNIX, SOCK_STREAM, 0);
Andrew Jefferya72711a2023-04-18 18:19:41 +0930464 if (sh->sd < 0) {
Jonathan Domancc075302023-03-31 10:20:48 -0700465 warn("Can't create socket");
Jeremy Kerre2826c72024-07-05 10:54:21 +0800466 goto err_free;
Jonathan Domancc075302023-03-31 10:20:48 -0700467 }
Andrew Jeffery5e7c0782020-02-10 12:12:36 +1030468
Jonathan Domancc075302023-03-31 10:20:48 -0700469 addrlen = sizeof(addr) - sizeof(addr.sun_path) + len;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800470
Jonathan Domancc075302023-03-31 10:20:48 -0700471 rc = bind(sh->sd, (struct sockaddr *)&addr, addrlen);
472 if (rc) {
473 socket_path_t name;
474 console_socket_path_readable(&addr, addrlen, name);
475 warn("Can't bind to socket path %s (terminated at first null)",
Andrew Jefferya72711a2023-04-18 18:19:41 +0930476 name);
Jeremy Kerre2826c72024-07-05 10:54:21 +0800477 goto err_close;
Jonathan Domancc075302023-03-31 10:20:48 -0700478 }
479
480 rc = listen(sh->sd, 1);
481 if (rc) {
482 warn("Can't listen for incoming connections");
Jeremy Kerre2826c72024-07-05 10:54:21 +0800483 goto err_close;
Jonathan Domancc075302023-03-31 10:20:48 -0700484 }
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800485 }
486
Jeremy Kerre2826c72024-07-05 10:54:21 +0800487 sh->poller = console_poller_register(console, &sh->handler, socket_poll,
Andrew Jefferya72711a2023-04-18 18:19:41 +0930488 NULL, sh->sd, POLLIN, NULL);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800489
Jeremy Kerre2826c72024-07-05 10:54:21 +0800490 return &sh->handler;
491
492err_close:
Andrew Jeffery5e7c0782020-02-10 12:12:36 +1030493 close(sh->sd);
Jeremy Kerre2826c72024-07-05 10:54:21 +0800494err_free:
495 free(sh);
496 return NULL;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800497}
498
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800499static void socket_fini(struct handler *handler)
500{
501 struct socket_handler *sh = to_socket_handler(handler);
Jeremy Kerr89ea8192016-03-15 17:57:43 +0800502
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930503 while (sh->n_clients) {
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800504 client_close(sh->clients[0]);
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930505 }
Jeremy Kerr89ea8192016-03-15 17:57:43 +0800506
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930507 if (sh->poller) {
Jeremy Kerr55c97122017-02-07 17:06:46 +0800508 console_poller_unregister(sh->console, sh->poller);
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930509 }
Jeremy Kerr89ea8192016-03-15 17:57:43 +0800510
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800511 close(sh->sd);
Jeremy Kerre2826c72024-07-05 10:54:21 +0800512 free(sh);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800513}
514
Jeremy Kerre2826c72024-07-05 10:54:21 +0800515static const struct handler_type socket_handler = {
516 .name = "socket",
517 .init = socket_init,
518 .fini = socket_fini,
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800519};
520
Jeremy Kerre2826c72024-07-05 10:54:21 +0800521console_handler_register(&socket_handler);