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

systemd / systemd / 14630481637

23 Apr 2025 07:04PM UTC coverage: 72.178% (-0.002%) from 72.18%
14630481637

push

github

DaanDeMeyer
mkosi: Run clangd within the tools tree instead of the build container

Running within the build sandbox has a number of disadvantages:
- We have a separate clangd cache for each distribution/release combo
- It requires to build the full image before clangd can be used
- It breaks every time the image becomes out of date and requires a
  rebuild
- We can't look at system headers as we don't have the knowledge to map
  them from inside the build sandbox to the corresponding path on the host

Instead, let's have mkosi.clangd run clangd within the tools tree. We
already require building systemd for both the host and the target anyway,
and all the dependencies to build systemd are installed in the tools tree
already for that, as well as clangd since it's installed together with the
other clang tooling we install in the tools tree. Unlike the previous approach,
this approach only requires the mkosi tools tree to be built upfront, which has
a much higher chance of not invalidating its cache. We can also trivially map
system header lookups from within the sandbox to the path within mkosi.tools
on the host so that starts working as well.

297054 of 411557 relevant lines covered (72.18%)

686269.58 hits per line

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

3.64
/src/resolve/resolved-dnssd.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include "conf-files.h"
4
#include "conf-parser.h"
5
#include "constants.h"
6
#include "dns-domain.h"
7
#include "hexdecoct.h"
8
#include "path-util.h"
9
#include "resolved-conf.h"
10
#include "resolved-dns-rr.h"
11
#include "resolved-dns-zone.h"
12
#include "resolved-dnssd.h"
13
#include "resolved-manager.h"
14
#include "specifier.h"
15
#include "strv.h"
16

17
#define DNSSD_SERVICE_DIRS ((const char* const*) CONF_PATHS_STRV("systemd/dnssd"))
18

19
DnssdTxtData *dnssd_txtdata_free(DnssdTxtData *txt_data) {
×
20
        if (!txt_data)
×
21
                return NULL;
22

23
        dns_resource_record_unref(txt_data->rr);
×
24
        dns_txt_item_free_all(txt_data->txts);
×
25

26
        return mfree(txt_data);
×
27
}
28

29
DnssdTxtData *dnssd_txtdata_free_all(DnssdTxtData *txt_data) {
×
30
        DnssdTxtData *next;
×
31

32
        if (!txt_data)
×
33
                return NULL;
34

35
        next = txt_data->items_next;
×
36

37
        dnssd_txtdata_free(txt_data);
×
38

39
        return dnssd_txtdata_free_all(next);
×
40
}
41

42
DnssdService *dnssd_service_free(DnssdService *service) {
×
43
        if (!service)
×
44
                return NULL;
45

46
        if (service->manager)
×
47
                hashmap_remove(service->manager->dnssd_services, service->id);
×
48

49
        dns_resource_record_unref(service->ptr_rr);
×
50
        dns_resource_record_unref(service->sub_ptr_rr);
×
51
        dns_resource_record_unref(service->srv_rr);
×
52

53
        dnssd_txtdata_free_all(service->txt_data_items);
×
54

55
        free(service->path);
×
56
        free(service->id);
×
57
        free(service->type);
×
58
        free(service->subtype);
×
59
        free(service->name_template);
×
60

61
        return mfree(service);
×
62
}
63

64
void dnssd_service_clear_on_reload(Hashmap *services) {
18✔
65
        DnssdService *service;
18✔
66

67
        HASHMAP_FOREACH(service, services)
36✔
68
                if (service->config_source == RESOLVE_CONFIG_SOURCE_FILE) {
×
69
                        hashmap_remove(services, service->id);
×
70
                        dnssd_service_free(service);
×
71
                }
72
}
18✔
73

74
static int dnssd_id_from_path(const char *path, char **ret_id) {
×
75
        int r;
×
76

77
        assert(path);
×
78
        assert(ret_id);
×
79

80
        _cleanup_free_ char *fn = NULL;
×
81
        r = path_extract_filename(path, &fn);
×
82
        if (r < 0)
×
83
                return r;
84

85
        char *d = endswith(fn, ".dnssd");
×
86
        if (!d)
×
87
                return -EINVAL;
88

89
        *d = '\0';
×
90

91
        *ret_id = TAKE_PTR(fn);
×
92
        return 0;
×
93
}
94

95
static int dnssd_service_load(Manager *manager, const char *path) {
×
96
        _cleanup_(dnssd_service_freep) DnssdService *service = NULL;
×
97
        _cleanup_(dnssd_txtdata_freep) DnssdTxtData *txt_data = NULL;
×
98
        _cleanup_free_ char *dropin_dirname = NULL;
×
99
        int r;
×
100

101
        assert(manager);
×
102
        assert(path);
×
103

104
        service = new0(DnssdService, 1);
×
105
        if (!service)
×
106
                return log_oom();
×
107

108
        service->path = strdup(path);
×
109
        if (!service->path)
×
110
                return log_oom();
×
111

112
        r = dnssd_id_from_path(path, &service->id);
×
113
        if (r < 0)
×
114
                return log_error_errno(r, "Failed to extract DNS-SD service id from filename: %m");
×
115

116
        dropin_dirname = strjoin(service->id, ".dnssd.d");
×
117
        if (!dropin_dirname)
×
118
                return log_oom();
×
119

120
        r = config_parse_many(
×
121
                        STRV_MAKE_CONST(path), DNSSD_SERVICE_DIRS, dropin_dirname, /* root = */ NULL,
×
122
                        "Service\0",
123
                        config_item_perf_lookup, resolved_dnssd_gperf_lookup,
124
                        CONFIG_PARSE_WARN,
125
                        service,
126
                        NULL,
127
                        NULL);
128
        if (r < 0)
×
129
                return r;
130

131
        if (!service->name_template)
×
132
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
133
                                       "%s doesn't define service instance name",
134
                                       service->id);
135

136
        if (!service->type)
×
137
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
138
                                       "%s doesn't define service type",
139
                                       service->id);
140

141
        if (!service->txt_data_items) {
×
142
                txt_data = new0(DnssdTxtData, 1);
×
143
                if (!txt_data)
×
144
                        return log_oom();
×
145

146
                r = dns_txt_item_new_empty(&txt_data->txts);
×
147
                if (r < 0)
×
148
                        return r;
149

150
                LIST_PREPEND(items, service->txt_data_items, txt_data);
×
151
                TAKE_PTR(txt_data);
×
152
        }
153

154
        r = hashmap_ensure_put(&manager->dnssd_services, &string_hash_ops, service->id, service);
×
155
        if (r < 0)
×
156
                return r;
157

158
        service->manager = manager;
×
159

160
        r = dnssd_update_rrs(service);
×
161
        if (r < 0)
×
162
                return r;
163

164
        TAKE_PTR(service);
×
165

166
        return 0;
×
167
}
168

169
static int specifier_dnssd_hostname(char specifier, const void *data, const char *root, const void *userdata, char **ret) {
×
170
        const Manager *m = ASSERT_PTR(userdata);
×
171

172
        assert(m->llmnr_hostname);
×
173

174
        return strdup_to(ret, m->llmnr_hostname);
×
175
}
176

177
int dnssd_render_instance_name(Manager *m, DnssdService *s, char **ret) {
×
178
        static const Specifier specifier_table[] = {
×
179
                { 'a', specifier_architecture,   NULL },
180
                { 'b', specifier_boot_id,        NULL },
181
                { 'B', specifier_os_build_id,    NULL },
182
                { 'H', specifier_dnssd_hostname, NULL },
183
                { 'm', specifier_machine_id,     NULL },
184
                { 'o', specifier_os_id,          NULL },
185
                { 'v', specifier_kernel_release, NULL },
186
                { 'w', specifier_os_version_id,  NULL },
187
                { 'W', specifier_os_variant_id,  NULL },
188
                {}
189
        };
190
        _cleanup_free_ char *name = NULL;
×
191
        int r;
×
192

193
        assert(m);
×
194
        assert(s);
×
195
        assert(s->name_template);
×
196

197
        r = specifier_printf(s->name_template, DNS_LABEL_MAX, specifier_table, NULL, m, &name);
×
198
        if (r < 0)
×
199
                return log_debug_errno(r, "Failed to replace specifiers: %m");
×
200

201
        if (!dns_service_name_is_valid(name))
×
202
                return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
×
203
                                       "Service instance name '%s' is invalid.",
204
                                       name);
205

206
        if (ret)
×
207
                *ret = TAKE_PTR(name);
×
208

209
        return 0;
210
}
211

212
int dnssd_load(Manager *manager) {
180✔
213
        _cleanup_strv_free_ char **files = NULL;
180✔
214
        int r;
180✔
215

216
        assert(manager);
180✔
217

218
        if (manager->mdns_support != RESOLVE_SUPPORT_YES)
180✔
219
                return 0;
220

221
        r = conf_files_list_strv(&files, ".dnssd", NULL, 0, DNSSD_SERVICE_DIRS);
177✔
222
        if (r < 0)
177✔
223
                return log_error_errno(r, "Failed to enumerate .dnssd files: %m");
×
224

225
        STRV_FOREACH_BACKWARDS(f, files) {
354✔
226
                r = dnssd_service_load(manager, *f);
×
227
                if (r < 0)
×
228
                        log_warning_errno(r, "Failed to load '%s': %m", *f);
×
229
        }
230

231
        return 0;
232
}
233

234
int dnssd_update_rrs(DnssdService *s) {
×
235
        _cleanup_free_ char *n = NULL, *service_name = NULL, *full_name = NULL, *sub_name = NULL, *selective_name = NULL;
×
236
        int r;
×
237

238
        assert(s);
×
239
        assert(s->txt_data_items);
×
240
        assert(s->manager);
×
241

242
        s->ptr_rr = dns_resource_record_unref(s->ptr_rr);
×
243
        s->sub_ptr_rr = dns_resource_record_unref(s->sub_ptr_rr);
×
244
        s->srv_rr = dns_resource_record_unref(s->srv_rr);
×
245
        LIST_FOREACH(items, txt_data, s->txt_data_items)
×
246
                txt_data->rr = dns_resource_record_unref(txt_data->rr);
×
247

248
        r = dnssd_render_instance_name(s->manager, s, &n);
×
249
        if (r < 0)
×
250
                return r;
251

252
        r = dns_name_concat(s->type, "local", 0, &service_name);
×
253
        if (r < 0)
×
254
                return r;
255
        r = dns_name_concat(n, service_name, 0, &full_name);
×
256
        if (r < 0)
×
257
                return r;
258
        if (s->subtype) {
×
259
                r = dns_name_concat("_sub", service_name, 0, &sub_name);
×
260
                if (r < 0)
×
261
                        return r;
262
                r = dns_name_concat(s->subtype, sub_name, 0, &selective_name);
×
263
                if (r < 0)
×
264
                        return r;
265
        }
266

267
        LIST_FOREACH(items, txt_data, s->txt_data_items) {
×
268
                txt_data->rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_TXT,
×
269
                                                            full_name);
270
                if (!txt_data->rr)
×
271
                        goto oom;
×
272

273
                txt_data->rr->ttl = MDNS_DEFAULT_TTL;
×
274
                txt_data->rr->txt.items = dns_txt_item_copy(txt_data->txts);
×
275
                if (!txt_data->rr->txt.items)
×
276
                        goto oom;
×
277
        }
278

279
        s->ptr_rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_PTR,
×
280
                                                 service_name);
281
        if (!s->ptr_rr)
×
282
                goto oom;
×
283

284
        s->ptr_rr->ttl = MDNS_DEFAULT_TTL;
×
285
        s->ptr_rr->ptr.name = strdup(full_name);
×
286
        if (!s->ptr_rr->ptr.name)
×
287
                goto oom;
×
288

289
        if (selective_name) {
×
290
                s->sub_ptr_rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_PTR, selective_name);
×
291
                if (!s->sub_ptr_rr)
×
292
                        goto oom;
×
293

294
                s->sub_ptr_rr->ttl = MDNS_DEFAULT_TTL;
×
295
                s->sub_ptr_rr->ptr.name = strdup(full_name);
×
296
                if (!s->sub_ptr_rr->ptr.name)
×
297
                        goto oom;
×
298
        }
299

300
        s->srv_rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_SRV,
×
301
                                                 full_name);
302
        if (!s->srv_rr)
×
303
                goto oom;
×
304

305
        s->srv_rr->ttl = MDNS_DEFAULT_TTL;
×
306
        s->srv_rr->srv.priority = s->priority;
×
307
        s->srv_rr->srv.weight = s->weight;
×
308
        s->srv_rr->srv.port = s->port;
×
309
        s->srv_rr->srv.name = strdup(s->manager->mdns_hostname);
×
310
        if (!s->srv_rr->srv.name)
×
311
                goto oom;
×
312

313
        return 0;
314

315
oom:
×
316
        LIST_FOREACH(items, txt_data, s->txt_data_items)
×
317
                txt_data->rr = dns_resource_record_unref(txt_data->rr);
×
318
        s->ptr_rr = dns_resource_record_unref(s->ptr_rr);
×
319
        s->sub_ptr_rr = dns_resource_record_unref(s->sub_ptr_rr);
×
320
        s->srv_rr = dns_resource_record_unref(s->srv_rr);
×
321
        return -ENOMEM;
×
322
}
323

324
int dnssd_txt_item_new_from_string(const char *key, const char *value, DnsTxtItem **ret_item) {
×
325
        size_t length;
×
326
        DnsTxtItem *i;
×
327

328
        length = strlen(key);
×
329

330
        if (!isempty(value))
×
331
                length += strlen(value) + 1; /* length of value plus '=' */
×
332

333
        i = malloc0(offsetof(DnsTxtItem, data) + length + 1); /* for safety reasons we add an extra NUL byte */
×
334
        if (!i)
×
335
                return -ENOMEM;
×
336

337
        memcpy(i->data, key, strlen(key));
×
338
        if (!isempty(value)) {
×
339
                memcpy(i->data + strlen(key), "=", 1);
×
340
                memcpy(i->data + strlen(key) + 1, value, strlen(value));
×
341
        }
342
        i->length = length;
×
343

344
        *ret_item = TAKE_PTR(i);
×
345

346
        return 0;
×
347
}
348

349
int dnssd_txt_item_new_from_data(const char *key, const void *data, const size_t size, DnsTxtItem **ret_item) {
×
350
        size_t length;
×
351
        DnsTxtItem *i;
×
352

353
        length = strlen(key);
×
354

355
        if (size > 0)
×
356
                length += size + 1; /* size of date plus '=' */
×
357

358
        i = malloc0(offsetof(DnsTxtItem, data) + length + 1); /* for safety reasons we add an extra NUL byte */
×
359
        if (!i)
×
360
                return -ENOMEM;
361

362
        memcpy(i->data, key, strlen(key));
×
363
        if (size > 0) {
×
364
                memcpy(i->data + strlen(key), "=", 1);
×
365
                memcpy(i->data + strlen(key) + 1, data, size);
×
366
        }
367
        i->length = length;
×
368

369
        *ret_item = TAKE_PTR(i);
×
370

371
        return 0;
×
372
}
373

374
int dnssd_signal_conflict(Manager *manager, const char *name) {
×
375
        DnssdService *s;
×
376
        int r;
×
377

378
        if (sd_bus_is_ready(manager->bus) <= 0)
×
379
                return 0;
×
380

381
        HASHMAP_FOREACH(s, manager->dnssd_services) {
×
382
                if (s->withdrawn)
×
383
                        continue;
×
384

385
                if (dns_name_equal(dns_resource_key_name(s->srv_rr->key), name) > 0) {
×
386
                        _cleanup_free_ char *path = NULL;
×
387

388
                        s->withdrawn = true;
×
389

390
                        r = sd_bus_path_encode("/org/freedesktop/resolve1/dnssd", s->id, &path);
×
391
                        if (r < 0)
×
392
                                return log_error_errno(r, "Can't get D-BUS object path: %m");
×
393

394
                        r = sd_bus_emit_signal(manager->bus,
×
395
                                               path,
396
                                               "org.freedesktop.resolve1.DnssdService",
397
                                               "Conflicted",
398
                                               NULL);
399
                        if (r < 0)
×
400
                                return log_error_errno(r, "Cannot emit signal: %m");
×
401

402
                        break;
×
403
                }
404
        }
405

406
        return 0;
×
407
}
408

409
int config_parse_dnssd_service_name(
×
410
                const char *unit,
411
                const char *filename,
412
                unsigned line,
413
                const char *section,
414
                unsigned section_line,
415
                const char *lvalue,
416
                int ltype,
417
                const char *rvalue,
418
                void *data,
419
                void *userdata) {
420

421
        static const Specifier specifier_table[] = {
×
422
                { 'a', specifier_architecture,    NULL },
423
                { 'b', specifier_boot_id,         NULL },
424
                { 'B', specifier_os_build_id,     NULL },
425
                { 'H', specifier_hostname,        NULL }, /* We will use specifier_dnssd_hostname(). */
426
                { 'm', specifier_machine_id,      NULL },
427
                { 'o', specifier_os_id,           NULL },
428
                { 'v', specifier_kernel_release,  NULL },
429
                { 'w', specifier_os_version_id,   NULL },
430
                { 'W', specifier_os_variant_id,   NULL },
431
                {}
432
        };
433
        DnssdService *s = ASSERT_PTR(userdata);
×
434
        _cleanup_free_ char *name = NULL;
×
435
        int r;
×
436

437
        assert(filename);
×
438
        assert(lvalue);
×
439
        assert(rvalue);
×
440

441
        if (isempty(rvalue)) {
×
442
                s->name_template = mfree(s->name_template);
×
443
                return 0;
×
444
        }
445

446
        r = specifier_printf(rvalue, DNS_LABEL_MAX, specifier_table, NULL, NULL, &name);
×
447
        if (r < 0) {
×
448
                log_syntax(unit, LOG_WARNING, filename, line, r,
×
449
                           "Invalid service instance name template '%s', ignoring assignment: %m", rvalue);
450
                return 0;
×
451
        }
452

453
        if (!dns_service_name_is_valid(name)) {
×
454
                log_syntax(unit, LOG_WARNING, filename, line, 0,
×
455
                           "Service instance name template '%s' renders to invalid name '%s'. Ignoring assignment.",
456
                           rvalue, name);
457
                return 0;
×
458
        }
459

460
        return free_and_strdup_warn(&s->name_template, rvalue);
×
461
}
462

463
int config_parse_dnssd_service_type(
×
464
                const char *unit,
465
                const char *filename,
466
                unsigned line,
467
                const char *section,
468
                unsigned section_line,
469
                const char *lvalue,
470
                int ltype,
471
                const char *rvalue,
472
                void *data,
473
                void *userdata) {
474

475
        DnssdService *s = ASSERT_PTR(userdata);
×
476
        int r;
×
477

478
        assert(filename);
×
479
        assert(lvalue);
×
480
        assert(rvalue);
×
481

482
        if (isempty(rvalue)) {
×
483
                s->type = mfree(s->type);
×
484
                return 0;
×
485
        }
486

487
        if (!dnssd_srv_type_is_valid(rvalue)) {
×
488
                log_syntax(unit, LOG_WARNING, filename, line, 0, "Service type is invalid. Ignoring.");
×
489
                return 0;
×
490
        }
491

492
        r = free_and_strdup(&s->type, rvalue);
×
493
        if (r < 0)
×
494
                return log_oom();
×
495

496
        return 0;
497
}
498

499
int config_parse_dnssd_service_subtype(
×
500
                const char *unit,
501
                const char *filename,
502
                unsigned line,
503
                const char *section,
504
                unsigned section_line,
505
                const char *lvalue,
506
                int ltype,
507
                const char *rvalue,
508
                void *data,
509
                void *userdata) {
510

511
        DnssdService *s = ASSERT_PTR(userdata);
×
512

513
        assert(filename);
×
514
        assert(lvalue);
×
515
        assert(rvalue);
×
516

517
        if (isempty(rvalue)) {
×
518
                s->subtype = mfree(s->subtype);
×
519
                return 0;
×
520
        }
521

522
        if (!dns_subtype_name_is_valid(rvalue)) {
×
523
                log_syntax(unit, LOG_WARNING, filename, line, 0, "Service subtype is invalid. Ignoring.");
×
524
                return 0;
×
525
        }
526

527
        return free_and_strdup_warn(&s->subtype, rvalue);
×
528
}
529

530
int config_parse_dnssd_txt(
×
531
                const char *unit,
532
                const char *filename,
533
                unsigned line,
534
                const char *section,
535
                unsigned section_line,
536
                const char *lvalue,
537
                int ltype,
538
                const char *rvalue,
539
                void *data,
540
                void *userdata) {
541

542
        _cleanup_(dnssd_txtdata_freep) DnssdTxtData *txt_data = NULL;
×
543
        DnssdService *s = ASSERT_PTR(userdata);
×
544
        DnsTxtItem *last = NULL;
×
545

546
        assert(filename);
×
547
        assert(lvalue);
×
548
        assert(rvalue);
×
549

550
        if (isempty(rvalue)) {
×
551
                /* Flush out collected items */
552
                s->txt_data_items = dnssd_txtdata_free_all(s->txt_data_items);
×
553
                return 0;
×
554
        }
555

556
        txt_data = new0(DnssdTxtData, 1);
×
557
        if (!txt_data)
×
558
                return log_oom();
×
559

560
        for (;;) {
×
561
                _cleanup_free_ char *word = NULL, *key = NULL, *value = NULL;
×
562
                _cleanup_free_ void *decoded = NULL;
×
563
                size_t length = 0;
×
564
                DnsTxtItem *i;
×
565
                int r;
×
566

567
                r = extract_first_word(&rvalue, &word, NULL,
×
568
                                       EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_RELAX);
569
                if (r == 0)
×
570
                        break;
571
                if (r == -ENOMEM)
×
572
                        return log_oom();
×
573
                if (r < 0) {
×
574
                        log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
×
575
                        return 0;
×
576
                }
577

578
                r = split_pair(word, "=", &key, &value);
×
579
                if (r == -ENOMEM)
×
580
                        return log_oom();
×
581
                if (r == -EINVAL)
×
582
                        key = TAKE_PTR(word);
×
583

584
                if (!ascii_is_valid(key)) {
×
585
                        log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid key, ignoring: %s", key);
×
586
                        continue;
×
587
                }
588

589
                switch (ltype) {
×
590

591
                case DNS_TXT_ITEM_DATA:
×
592
                        if (value) {
×
593
                                r = unbase64mem(value, &decoded, &length);
×
594
                                if (r == -ENOMEM)
×
595
                                        return log_oom();
×
596
                                if (r < 0) {
×
597
                                        log_syntax(unit, LOG_WARNING, filename, line, r,
×
598
                                                   "Invalid base64 encoding, ignoring: %s", value);
599
                                        continue;
×
600
                                }
601
                        }
602

603
                        r = dnssd_txt_item_new_from_data(key, decoded, length, &i);
×
604
                        if (r < 0)
×
605
                                return log_oom();
×
606
                        break;
607

608
                case DNS_TXT_ITEM_TEXT:
×
609
                        r = dnssd_txt_item_new_from_string(key, value, &i);
×
610
                        if (r < 0)
×
611
                                return log_oom();
×
612
                        break;
613

614
                default:
×
615
                        assert_not_reached();
×
616
                }
617

618
                LIST_INSERT_AFTER(items, txt_data->txts, last, i);
×
619
                last = i;
×
620
        }
621

622
        if (txt_data->txts) {
×
623
                LIST_PREPEND(items, s->txt_data_items, txt_data);
×
624
                TAKE_PTR(txt_data);
×
625
        }
626

627
        return 0;
628
}
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