• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

systemd / systemd / 14815796853

02 May 2025 11:41AM UTC coverage: 72.24% (-0.003%) from 72.243%
14815796853

push

github

web-flow
Various changes to prepare for running IWYU on the repository (#37319)

These are various commits that were required to get things compiling
after running IWYU. I think all of them make sense on their own, hence
this split PR to merge them ahead of time.

81 of 96 new or added lines in 48 files covered. (84.38%)

209 existing lines in 39 files now uncovered.

297219 of 411432 relevant lines covered (72.24%)

693693.2 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/socket-proxy/socket-proxyd.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <errno.h>
4
#include <fcntl.h>
5
#include <getopt.h>
6
#include <netdb.h>
7
#include <stdio.h>
8
#include <stdlib.h>
9
#include <sys/un.h>
10
#include <unistd.h>
11

12
#include "sd-daemon.h"
13
#include "sd-event.h"
14
#include "sd-resolve.h"
15

16
#include "alloc-util.h"
17
#include "build.h"
18
#include "daemon-util.h"
19
#include "errno-util.h"
20
#include "event-util.h"
21
#include "fd-util.h"
22
#include "log.h"
23
#include "main-func.h"
24
#include "parse-util.h"
25
#include "path-util.h"
26
#include "pretty-print.h"
27
#include "resolve-private.h"
28
#include "set.h"
29
#include "socket-util.h"
30
#include "string-util.h"
31

32
#define BUFFER_SIZE (256 * 1024)
33

34
static unsigned arg_connections_max = 256;
35
static const char *arg_remote_host = NULL;
36
static usec_t arg_exit_idle_time = USEC_INFINITY;
37

38
typedef struct Context {
39
        sd_event *event;
40
        sd_resolve *resolve;
41
        sd_event_source *idle_time;
42

43
        Set *listen;
44
        Set *connections;
45
} Context;
46

47
typedef struct Connection {
48
        Context *context;
49

50
        int server_fd, client_fd;
51
        int server_to_client_buffer[2]; /* a pipe */
52
        int client_to_server_buffer[2]; /* a pipe */
53

54
        size_t server_to_client_buffer_full, client_to_server_buffer_full;
55
        size_t server_to_client_buffer_size, client_to_server_buffer_size;
56

57
        sd_event_source *server_event_source, *client_event_source;
58

59
        sd_resolve_query *resolve_query;
60
} Connection;
61

62
static Connection* connection_free(Connection *c) {
×
63
        if (!c)
×
64
                return NULL;
65

66
        if (c->context)
×
67
                set_remove(c->context->connections, c);
×
68

69
        sd_event_source_unref(c->server_event_source);
×
70
        sd_event_source_unref(c->client_event_source);
×
71

72
        safe_close(c->server_fd);
×
73
        safe_close(c->client_fd);
×
74

75
        safe_close_pair(c->server_to_client_buffer);
×
76
        safe_close_pair(c->client_to_server_buffer);
×
77

78
        sd_resolve_query_unref(c->resolve_query);
×
79

80
        return mfree(c);
×
81
}
82

83
DEFINE_TRIVIAL_CLEANUP_FUNC(Connection*, connection_free);
×
84

85
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
×
86
                connection_hash_ops,
87
                void, trivial_hash_func, trivial_compare_func,
88
                Connection, connection_free);
89

90
static void context_done(Context *context) {
×
91
        assert(context);
×
92

93
        set_free(context->listen);
×
94
        set_free(context->connections);
×
95

96
        sd_event_unref(context->event);
×
97
        sd_resolve_unref(context->resolve);
×
98
        sd_event_source_unref(context->idle_time);
×
99
}
×
100

101
static int idle_time_cb(sd_event_source *s, uint64_t usec, void *userdata) {
×
102
        Context *c = userdata;
×
103
        int r;
×
104

105
        if (!set_isempty(c->connections)) {
×
106
                log_warning("Idle timer fired even though there are connections, ignoring");
×
107
                return 0;
×
108
        }
109

110
        r = sd_event_exit(c->event, 0);
×
111
        if (r < 0) {
×
112
                log_warning_errno(r, "Error while stopping event loop, ignoring: %m");
×
113
                return 0;
×
114
        }
115
        return 0;
116
}
117

118
static void context_reset_timer(Context *context) {
×
119
        int r;
×
120

121
        assert(context);
×
122

123
        if (arg_exit_idle_time < USEC_INFINITY && set_isempty(context->connections)) {
×
124
                r = event_reset_time_relative(
×
125
                                context->event, &context->idle_time, CLOCK_MONOTONIC,
126
                                arg_exit_idle_time, 0, idle_time_cb, context,
127
                                SD_EVENT_PRIORITY_NORMAL, "idle-timer", /* force = */ true);
128
                if (r < 0)
×
129
                        log_warning_errno(r, "Failed to reset idle timer, ignoring: %m");
×
130
        }
131
}
×
132

133
static void connection_release(Connection *c) {
×
134
        Context *context = ASSERT_PTR(ASSERT_PTR(c)->context);
×
135

136
        connection_free(c);
×
137
        context_reset_timer(context);
×
138
}
×
139

140
static int connection_create_pipes(Connection *c, int buffer[static 2], size_t *sz) {
×
141
        int r;
×
142

143
        assert(c);
×
144
        assert(buffer);
×
145
        assert(sz);
×
146

147
        if (buffer[0] >= 0)
×
148
                return 0;
149

150
        r = pipe2(buffer, O_CLOEXEC|O_NONBLOCK);
×
151
        if (r < 0)
×
152
                return log_error_errno(errno, "Failed to allocate pipe buffer: %m");
×
153

154
        (void) fcntl(buffer[0], F_SETPIPE_SZ, BUFFER_SIZE);
×
155

156
        r = fcntl(buffer[0], F_GETPIPE_SZ);
×
157
        if (r < 0)
×
158
                return log_error_errno(errno, "Failed to get pipe buffer size: %m");
×
159

160
        assert(r > 0);
×
161
        *sz = r;
×
162

163
        return 0;
×
164
}
165

166
static int connection_shovel(
×
167
                Connection *c,
168
                int *from, int buffer[2], int *to,
169
                size_t *full, size_t *sz,
170
                sd_event_source **from_source, sd_event_source **to_source) {
171

172
        bool shoveled;
×
173

174
        assert(c);
×
175
        assert(from);
×
176
        assert(buffer);
×
177
        assert(buffer[0] >= 0);
×
178
        assert(buffer[1] >= 0);
×
179
        assert(to);
×
180
        assert(full);
×
181
        assert(sz);
×
182
        assert(from_source);
×
183
        assert(to_source);
×
184

185
        do {
×
186
                ssize_t z;
×
187

188
                shoveled = false;
×
189

190
                if (*full < *sz && *from >= 0 && *to >= 0) {
×
191
                        z = splice(*from, NULL, buffer[1], NULL, *sz - *full, SPLICE_F_MOVE|SPLICE_F_NONBLOCK);
×
192
                        if (z > 0) {
×
193
                                *full += z;
×
194
                                shoveled = true;
×
195
                        } else if (z == 0 || ERRNO_IS_DISCONNECT(errno)) {
×
196
                                *from_source = sd_event_source_unref(*from_source);
×
197
                                *from = safe_close(*from);
×
198
                        } else if (!ERRNO_IS_TRANSIENT(errno))
×
199
                                return log_error_errno(errno, "Failed to splice: %m");
×
200
                }
201

202
                if (*full > 0 && *to >= 0) {
×
203
                        z = splice(buffer[0], NULL, *to, NULL, *full, SPLICE_F_MOVE|SPLICE_F_NONBLOCK);
×
204
                        if (z > 0) {
×
205
                                *full -= z;
×
206
                                shoveled = true;
×
207
                        } else if (z == 0 || ERRNO_IS_DISCONNECT(errno)) {
×
208
                                *to_source = sd_event_source_unref(*to_source);
×
209
                                *to = safe_close(*to);
×
210
                        } else if (!ERRNO_IS_TRANSIENT(errno))
×
211
                                return log_error_errno(errno, "Failed to splice: %m");
×
212
                }
213
        } while (shoveled);
×
214

215
        return 0;
216
}
217

218
static int connection_enable_event_sources(Connection *c);
219

220
static int traffic_cb(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
×
221
        Connection *c = ASSERT_PTR(userdata);
×
222
        int r;
×
223

224
        assert(s);
×
225
        assert(fd >= 0);
×
226

227
        r = connection_shovel(c,
×
228
                              &c->server_fd, c->server_to_client_buffer, &c->client_fd,
×
229
                              &c->server_to_client_buffer_full, &c->server_to_client_buffer_size,
230
                              &c->server_event_source, &c->client_event_source);
231
        if (r < 0)
×
232
                goto quit;
×
233

234
        r = connection_shovel(c,
×
235
                              &c->client_fd, c->client_to_server_buffer, &c->server_fd,
×
236
                              &c->client_to_server_buffer_full, &c->client_to_server_buffer_size,
237
                              &c->client_event_source, &c->server_event_source);
238
        if (r < 0)
×
239
                goto quit;
×
240

241
        /* EOF on both sides? */
242
        if (c->server_fd < 0 && c->client_fd < 0)
×
243
                goto quit;
×
244

245
        /* Server closed, and all data written to client? */
246
        if (c->server_fd < 0 && c->server_to_client_buffer_full <= 0)
×
247
                goto quit;
×
248

249
        /* Client closed, and all data written to server? */
250
        if (c->client_fd < 0 && c->client_to_server_buffer_full <= 0)
×
251
                goto quit;
×
252

253
        r = connection_enable_event_sources(c);
×
254
        if (r < 0)
×
255
                goto quit;
×
256

257
        return 1;
258

259
quit:
×
260
        connection_release(c);
×
261
        return 0; /* ignore errors, continue serving */
×
262
}
263

264
static int connection_enable_event_sources(Connection *c) {
×
265
        uint32_t a = 0, b = 0;
×
266
        int r;
×
267

268
        assert(c);
×
269

270
        if (c->server_to_client_buffer_full > 0)
×
271
                b |= EPOLLOUT;
×
272
        if (c->server_to_client_buffer_full < c->server_to_client_buffer_size)
×
273
                a |= EPOLLIN;
×
274

275
        if (c->client_to_server_buffer_full > 0)
×
276
                a |= EPOLLOUT;
×
277
        if (c->client_to_server_buffer_full < c->client_to_server_buffer_size)
×
278
                b |= EPOLLIN;
×
279

280
        if (c->server_event_source)
×
281
                r = sd_event_source_set_io_events(c->server_event_source, a);
×
282
        else if (c->server_fd >= 0)
×
283
                r = sd_event_add_io(c->context->event, &c->server_event_source, c->server_fd, a, traffic_cb, c);
×
284
        else
285
                r = 0;
286

287
        if (r < 0)
×
288
                return log_error_errno(r, "Failed to set up server event source: %m");
×
289

290
        if (c->client_event_source)
×
291
                r = sd_event_source_set_io_events(c->client_event_source, b);
×
292
        else if (c->client_fd >= 0)
×
293
                r = sd_event_add_io(c->context->event, &c->client_event_source, c->client_fd, b, traffic_cb, c);
×
294
        else
295
                r = 0;
296

297
        if (r < 0)
×
298
                return log_error_errno(r, "Failed to set up client event source: %m");
×
299

300
        return 0;
301
}
302

303
static int connection_complete(Connection *c) {
×
304
        int r;
×
305

306
        assert(c);
×
307

308
        r = connection_create_pipes(c, c->server_to_client_buffer, &c->server_to_client_buffer_size);
×
309
        if (r < 0)
×
310
                return r;
311

312
        r = connection_create_pipes(c, c->client_to_server_buffer, &c->client_to_server_buffer_size);
×
313
        if (r < 0)
×
314
                return r;
315

316
        r = connection_enable_event_sources(c);
×
317
        if (r < 0)
×
318
                return r;
×
319

320
        return 0;
321
}
322

323
static int connect_cb(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
×
324
        Connection *c = ASSERT_PTR(userdata);
×
325
        socklen_t solen;
×
326
        int error;
×
327

328
        assert(s);
×
329
        assert(fd >= 0);
×
330

331
        solen = sizeof(error);
×
332
        if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &solen) < 0) {
×
333
                log_error_errno(errno, "Failed to issue SO_ERROR: %m");
×
334
                goto fail;
×
335
        }
336

337
        if (error != 0) {
×
338
                log_error_errno(error, "Failed to connect to remote host: %m");
×
339
                goto fail;
×
340
        }
341

342
        c->client_event_source = sd_event_source_unref(c->client_event_source);
×
343

344
        if (connection_complete(c) < 0)
×
345
                goto fail;
×
346

347
        return 0;
×
348

349
fail:
×
350
        connection_release(c);
×
351
        return 0; /* ignore errors, continue serving */
352
}
353

354
static int connection_start(Connection *c, struct sockaddr *sa, socklen_t salen) {
×
355
        int r;
×
356

357
        assert(c);
×
358
        assert(sa);
×
359
        assert(salen);
×
360

361
        c->client_fd = socket(sa->sa_family, SOCK_STREAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0);
×
362
        if (c->client_fd < 0)
×
363
                return log_error_errno(errno, "Failed to get remote socket: %m");
×
364

365
        r = connect(c->client_fd, sa, salen);
×
366
        if (r < 0) {
×
367
                if (errno != EINPROGRESS)
×
368
                        return log_error_errno(errno, "Failed to connect to remote host: %m");
×
369

370
                r = sd_event_add_io(c->context->event, &c->client_event_source, c->client_fd, EPOLLOUT, connect_cb, c);
×
371
                if (r < 0)
×
372
                        return log_error_errno(r, "Failed to add connection socket: %m");
×
373

374
                r = sd_event_source_set_enabled(c->client_event_source, SD_EVENT_ONESHOT);
×
375
                if (r < 0)
×
376
                        return log_error_errno(r, "Failed to enable oneshot event source: %m");
×
377

378
                return 0;
379
        }
380

381
        return connection_complete(c);
×
382
}
383

384
static int resolve_handler(sd_resolve_query *q, int ret, const struct addrinfo *ai, Connection *c) {
×
385
        assert(q);
×
386
        assert(c);
×
387

388
        if (ret != 0) {
×
389
                log_error("Failed to resolve host: %s", gai_strerror(ret));
×
390
                goto fail;
×
391
        }
392

393
        c->resolve_query = sd_resolve_query_unref(c->resolve_query);
×
394

395
        if (connection_start(c, ai->ai_addr, ai->ai_addrlen) < 0)
×
396
                goto fail;
×
397

398
        return 0;
399

400
fail:
×
401
        connection_release(c);
×
402
        return 0; /* ignore errors, continue serving */
×
403
}
404

405
static int resolve_remote(Connection *c) {
×
406

407
        static const struct addrinfo hints = {
×
408
                .ai_family = AF_UNSPEC,
409
                .ai_socktype = SOCK_STREAM,
410
        };
411

412
        const char *node, *service;
×
413
        int r;
×
414

415
        if (IN_SET(arg_remote_host[0], '/', '@')) {
×
416
                union sockaddr_union sa;
×
417
                int sa_len;
×
418

419
                r = sockaddr_un_set_path(&sa.un, arg_remote_host);
×
420
                if (r < 0)
×
421
                        return log_error_errno(r, "Specified address doesn't fit in an AF_UNIX address, refusing: %m");
×
422
                sa_len = r;
×
423

424
                return connection_start(c, &sa.sa, sa_len);
×
425
        }
426

427
        service = strrchr(arg_remote_host, ':');
×
428
        if (service) {
×
429
                node = strndupa_safe(arg_remote_host,
×
430
                                     service - arg_remote_host);
431
                service++;
×
432
        } else {
433
                node = arg_remote_host;
434
                service = "80";
435
        }
436

437
        log_debug("Looking up address info for %s:%s", node, service);
×
438
        r = resolve_getaddrinfo(c->context->resolve, &c->resolve_query, node, service, &hints, resolve_handler, NULL, c);
×
439
        if (r < 0)
×
440
                return log_error_errno(r, "Failed to resolve remote host: %m");
×
441

442
        return 0;
443
}
444

445
static int context_add_connection(Context *context, int fd) {
×
446
        int r;
×
447

448
        assert(context);
×
449

450
        _cleanup_close_ int nfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
×
451
        if (nfd < 0) {
×
452
                if (!ERRNO_IS_ACCEPT_AGAIN(errno))
×
453
                        log_warning_errno(errno, "Failed to accept() socket, ignoring: %m");
×
454

455
                return -errno;
×
456
        }
457

458
        if (DEBUG_LOGGING) {
×
459
                _cleanup_free_ char *peer = NULL;
×
460
                (void) getpeername_pretty(nfd, true, &peer);
×
461
                log_debug("New connection from %s", strna(peer));
×
462
        }
463

464
        if (set_size(context->connections) > arg_connections_max)
×
465
                return log_warning_errno(SYNTHETIC_ERRNO(EBUSY), "Hit connection limit, refusing connection.");
×
466

467
        r = sd_event_source_set_enabled(context->idle_time, SD_EVENT_OFF);
×
468
        if (r < 0)
×
469
                log_warning_errno(r, "Unable to disable idle timer, continuing: %m");
×
470

471
        _cleanup_(connection_freep) Connection *c = new(Connection, 1);
×
472
        if (!c)
×
473
                return log_oom();
×
474

475
        *c = (Connection) {
×
476
                .server_fd = TAKE_FD(nfd),
×
477
                .client_fd = -EBADF,
478
                .server_to_client_buffer = EBADF_PAIR,
479
                .client_to_server_buffer = EBADF_PAIR,
480
        };
481

482
        r = set_ensure_put(&context->connections, &connection_hash_ops, c);
×
483
        if (r < 0)
×
484
                return log_oom();
×
485

486
        c->context = context;
×
487

488
        r = resolve_remote(c);
×
489
        if (r < 0)
×
490
                return r;
491

492
        TAKE_PTR(c);
×
493
        return 0;
×
494
}
495

496
static int accept_cb(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
×
497
        Context *context = ASSERT_PTR(userdata);
×
498
        int r;
×
499

500
        assert(s);
×
501
        assert(fd >= 0);
×
502
        assert(revents & EPOLLIN);
×
503

504
        if (context_add_connection(context, fd) < 0)
×
505
                context_reset_timer(context);
×
506

507
        r = sd_event_source_set_enabled(s, SD_EVENT_ONESHOT);
×
508
        if (r < 0)
×
509
                return log_error_errno(r, "Error while re-enabling listener with ONESHOT: %m");
×
510

511
        return 1;
512
}
513

514
static int add_listen_socket(Context *context, int fd) {
×
515
        int r;
×
516

517
        assert(context);
×
518
        assert(fd >= 0);
×
519

520
        r = sd_is_socket(fd, 0, SOCK_STREAM, 1);
×
521
        if (r < 0)
×
522
                return log_error_errno(r, "Failed to determine socket type: %m");
×
523
        if (r == 0)
×
524
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
525
                                       "Passed in socket is not a stream socket.");
526

527
        r = fd_nonblock(fd, true);
×
528
        if (r < 0)
×
529
                return log_error_errno(r, "Failed to mark file descriptor non-blocking: %m");
×
530

531
        _cleanup_(sd_event_source_unrefp) sd_event_source *source = NULL;
×
532
        r = sd_event_add_io(context->event, &source, fd, EPOLLIN, accept_cb, context);
×
533
        if (r < 0)
×
534
                return log_error_errno(r, "Failed to add event source: %m");
×
535

536
        r = sd_event_source_set_exit_on_failure(source, true);
×
537
        if (r < 0)
×
538
                return log_error_errno(r, "Failed to enable exit-on-failure logic: %m");
×
539

540
        /* Set the watcher to oneshot in case other processes are also
541
         * watching to accept(). */
542
        r = sd_event_source_set_enabled(source, SD_EVENT_ONESHOT);
×
543
        if (r < 0)
×
544
                return log_error_errno(r, "Failed to enable oneshot mode: %m");
×
545

546
        r = set_ensure_consume(&context->listen, &event_source_hash_ops, TAKE_PTR(source));
×
547
        if (r < 0)
×
548
                return log_error_errno(r, "Failed to add source to set: %m");
×
549

550
        return 0;
551
}
552

553
static int help(void) {
×
554
        _cleanup_free_ char *link = NULL;
×
555
        _cleanup_free_ char *time_link = NULL;
×
556
        int r;
×
557

558
        r = terminal_urlify_man("systemd-socket-proxyd", "8", &link);
×
559
        if (r < 0)
×
560
                return log_oom();
×
561
        r = terminal_urlify_man("systemd.time", "7", &time_link);
×
562
        if (r < 0)
×
563
                return log_oom();
×
564

565
        printf("%1$s [HOST:PORT]\n"
×
566
               "%1$s [SOCKET]\n\n"
567
               "%2$sBidirectionally proxy local sockets to another (possibly remote) socket.%3$s\n\n"
568
               "  -c --connections-max=  Set the maximum number of connections to be accepted\n"
569
               "     --exit-idle-time=   Exit when without a connection for this duration. See\n"
570
               "                         the %4$s for time span format\n"
571
               "  -h --help              Show this help\n"
572
               "     --version           Show package version\n"
573
               "\nSee the %5$s for details.\n",
574
               program_invocation_short_name,
575
               ansi_highlight(),
576
               ansi_normal(),
577
               time_link,
578
               link);
579

580
        return 0;
581
}
582

583
static int parse_argv(int argc, char *argv[]) {
×
584

585
        enum {
×
586
                ARG_VERSION = 0x100,
587
                ARG_EXIT_IDLE,
588
                ARG_IGNORE_ENV
589
        };
590

591
        static const struct option options[] = {
×
592
                { "connections-max", required_argument, NULL, 'c'           },
593
                { "exit-idle-time",  required_argument, NULL, ARG_EXIT_IDLE },
594
                { "help",            no_argument,       NULL, 'h'           },
595
                { "version",         no_argument,       NULL, ARG_VERSION   },
596
                {}
597
        };
598

599
        int c, r;
×
600

601
        assert(argc >= 0);
×
602
        assert(argv);
×
603

604
        while ((c = getopt_long(argc, argv, "c:h", options, NULL)) >= 0)
×
605

606
                switch (c) {
×
607

608
                case 'h':
×
609
                        return help();
×
610

611
                case ARG_VERSION:
×
612
                        return version();
×
613

614
                case 'c':
×
615
                        r = safe_atou(optarg, &arg_connections_max);
×
616
                        if (r < 0) {
×
617
                                log_error("Failed to parse --connections-max= argument: %s", optarg);
×
618
                                return r;
×
619
                        }
620

621
                        if (arg_connections_max < 1)
×
622
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
623
                                                       "Connection limit is too low.");
624

625
                        break;
626

627
                case ARG_EXIT_IDLE:
×
628
                        r = parse_sec(optarg, &arg_exit_idle_time);
×
629
                        if (r < 0)
×
630
                                return log_error_errno(r, "Failed to parse --exit-idle-time= argument: %s", optarg);
×
631
                        break;
632

633
                case '?':
634
                        return -EINVAL;
635

636
                default:
×
637
                        assert_not_reached();
×
638
                }
639

640
        if (optind >= argc)
×
641
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
642
                                       "Not enough parameters.");
643

644
        if (argc != optind+1)
×
645
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
646
                                       "Too many parameters.");
647

648
        arg_remote_host = argv[optind];
×
649
        return 1;
×
650
}
651

652
static int run(int argc, char *argv[]) {
×
653
        _cleanup_(context_done) Context context = {};
×
654
        _unused_ _cleanup_(notify_on_cleanup) const char *notify_stop = NULL;
×
655
        int r, n, fd;
×
656

657
        log_setup();
×
658

659
        r = parse_argv(argc, argv);
×
660
        if (r <= 0)
×
661
                return r;
662

663
        r = sd_event_default(&context.event);
×
664
        if (r < 0)
×
665
                return log_error_errno(r, "Failed to allocate event loop: %m");
×
666

667
        r = sd_resolve_default(&context.resolve);
×
668
        if (r < 0)
×
669
                return log_error_errno(r, "Failed to allocate resolver: %m");
×
670

671
        r = sd_resolve_attach_event(context.resolve, context.event, 0);
×
672
        if (r < 0)
×
673
                return log_error_errno(r, "Failed to attach resolver: %m");
×
674

675
        sd_event_set_watchdog(context.event, true);
×
676

677
        r = sd_listen_fds(1);
×
678
        if (r < 0)
×
679
                return log_error_errno(r, "Failed to receive sockets from parent.");
×
680
        if (r == 0)
×
681
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Didn't get any sockets passed in.");
×
682

683
        n = r;
684

685
        for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
×
686
                r = add_listen_socket(&context, fd);
×
687
                if (r < 0)
×
688
                        return r;
689
        }
690

NEW
691
        notify_stop = notify_start(NOTIFY_READY_MESSAGE, NOTIFY_STOPPING_MESSAGE);
×
692
        r = sd_event_loop(context.event);
×
693
        if (r < 0)
×
694
                return log_error_errno(r, "Failed to run event loop: %m");
×
695

696
        return 0;
697
}
698

699
DEFINE_MAIN_FUNCTION(run);
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc