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

systemd / systemd / 24373971178

14 Apr 2026 12:08AM UTC coverage: 72.291% (+0.2%) from 72.107%
24373971178

push

github

web-flow
hwdb: Add extended SteelSeries Arctis headset device support (#41628)

Add USB device IDs for additional SteelSeries Arctis headset models to
the sound card hardware database.

Newly added device IDs:

- Arctis Nova 7x v2 (22AD)
- Arctis Nova 7 Diablo IV (22A9)
- Arctis Nova 7X (22A4)
- Arctis Nova 7X (22A5)
- Arctis Nova 7P V2 (22A7)

321138 of 444232 relevant lines covered (72.29%)

1277257.29 hits per line

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

76.8
/src/basic/build-path.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <elf.h>
4
#include <fcntl.h>
5
#include <link.h>
6
#include <stdlib.h>
7
#include <sys/auxv.h>
8

9
#include "alloc-util.h"
10
#include "build-path.h"
11
#include "path-util.h"
12
#include "process-util.h"
13
#include "string-util.h"
14
#include "unistd.h"
15

16
static int get_runpath_from_dynamic(const ElfW(Dyn) *d, ElfW(Addr) bias, const char **ret) {
4,405✔
17
        size_t runpath_index = SIZE_MAX, rpath_index = SIZE_MAX;
4,405✔
18
        const char *strtab = NULL;
4,405✔
19

20
        assert(d);
4,405✔
21

22
        /* Iterates through the PT_DYNAMIC section to find the DT_RUNPATH/DT_RPATH entries */
23

24
        for (; d->d_tag != DT_NULL; d++) {
53,697✔
25

26
                switch (d->d_tag) {
53,697✔
27

28
                case DT_RUNPATH:
4,405✔
29
                        runpath_index = (size_t) d->d_un.d_val;
4,405✔
30
                        break;
4,405✔
31

32
                case DT_RPATH:
×
33
                        rpath_index = (size_t) d->d_un.d_val;
×
34
                        break;
×
35

36
                case DT_STRTAB:
4,405✔
37
                        /* On MIPS, RISC-V, or with musl, DT_STRTAB records an offset, not a valid address,
38
                         * so it has to be adjusted using the bias calculated earlier. */
39
                        if (d->d_un.d_val != 0)
4,405✔
40
                                strtab = (const char *) ((uintptr_t) d->d_un.d_val
4,405✔
41
#if defined(__mips__) || defined(__riscv) || !defined(__GLIBC__)
42
                                         + bias
43
#endif
44
                                );
45
                        break;
46
                }
47

48
                /* runpath wins, hence if we have the table and runpath we can exit the loop early */
49
                if (strtab && runpath_index != SIZE_MAX)
53,697✔
50
                        break;
51
        }
52

53
        if (!strtab)
4,405✔
54
                return -ENOTRECOVERABLE;
55

56
        /* According to ld.so runpath wins if both runpath and rpath are defined. */
57
        if (runpath_index != SIZE_MAX) {
4,405✔
58
                if (ret)
4,405✔
59
                        *ret = strtab + runpath_index;
4,405✔
60
                return 1;
4,405✔
61
        }
62

63
        if (rpath_index != SIZE_MAX) {
×
64
                if (ret)
×
65
                        *ret = strtab + rpath_index;
×
66
                return 1;
×
67
        }
68

69
        if (ret)
×
70
                *ret = NULL;
×
71

72
        return 0;
73
}
74

75
static int get_runpath(const char **ret) {
4,405✔
76
        unsigned long phdr, phent, phnum;
4,405✔
77

78
        /* Finds the rpath/runpath in the program headers of the main executable we are running in */
79

80
        phdr = getauxval(AT_PHDR);      /* Start offset of phdr */
4,405✔
81
        if (phdr == 0)
4,405✔
82
                return -ENOTRECOVERABLE;
83

84
        phnum = getauxval(AT_PHNUM);    /* Number of entries in phdr */
4,405✔
85
        if (phnum == 0)
4,405✔
86
                return -ENOTRECOVERABLE;
87

88
        phent = getauxval(AT_PHENT);    /* Size of entries in phdr */
4,405✔
89
        if (phent < sizeof(ElfW(Phdr))) /* Safety check, that our idea of the structure matches the file */
4,405✔
90
                return -ENOTRECOVERABLE;
91

92
        ElfW(Addr) bias = 0, dyn = 0;
93
        bool found_bias = false, found_dyn = false;
94

95
        /* Iterate through the Phdr structures to find the PT_PHDR and PT_DYNAMIC sections */
96
        for (unsigned long i = 0; i < phnum; i++) {
30,835✔
97
                const ElfW(Phdr) *p = (const ElfW(Phdr)*) (phdr + (i * phent));
30,835✔
98

99
                switch (p->p_type) {
30,835✔
100

101
                case PT_PHDR:
4,405✔
102
                        if (p->p_vaddr > phdr) /* safety overflow check */
4,405✔
103
                                return -ENOTRECOVERABLE;
104

105
                        bias = (ElfW(Addr)) phdr - p->p_vaddr;
4,405✔
106
                        found_bias = true;
4,405✔
107
                        break;
4,405✔
108

109
                case PT_DYNAMIC:
4,405✔
110
                        dyn = p->p_vaddr;
4,405✔
111
                        found_dyn = true;
4,405✔
112
                        break;
4,405✔
113
                }
114

115
                if (found_bias && found_dyn)
30,835✔
116
                        break;
117
        }
118

119
        if (!found_dyn)
4,405✔
120
                return -ENOTRECOVERABLE;
121

122
        return get_runpath_from_dynamic((const ElfW(Dyn)*) (bias + dyn), bias, ret);
4,405✔
123
}
124

125
int get_build_exec_dir(char **ret) {
16,297✔
126
        int r;
16,297✔
127

128
        /* Returns the build execution directory if we are invoked in a build environment. Specifically, this
129
         * checks if the main program binary has an rpath/runpath set (i.e. an explicit directory where to
130
         * look for shared libraries) to $ORIGIN. If so we know that this is not a regular installed binary,
131
         * but one which shall acquire its libraries from below a directory it is located in, i.e. a build
132
         * directory or similar. In that case it typically makes sense to also search for our auxiliary
133
         * executables we fork() off in a directory close to our main program binary, rather than in the
134
         * system.
135
         *
136
         * This function is supposed to be used when looking for "callout" binaries that are closely related
137
         * to the main program (i.e. speak a specific protocol between each other). And where it's generally
138
         * a good idea to use the binary from the build tree (if there is one) instead of the system.
139
         *
140
         * Note that this does *not* actually return the rpath/runpath but the instead the directory the main
141
         * executable was found in. This follows the logic that the result is supposed to be used for
142
         * executable binaries (i.e. stuff in bindir), not for shared libraries (i.e. stuff in libdir), and
143
         * hence the literal shared library path would just be wrong.
144
         *
145
         * TLDR: if we look for callouts in this dir first, running binaries from the meson build tree
146
         * automatically uses the right callout.
147
         *
148
         * Returns:
149
         *     -ENOEXEC         → We are not running in an rpath/runpath $ORIGIN environment
150
         *     -ENOENT          → We don't know our own binary path
151
         *     -NOTRECOVERABLE  → Dynamic binary information missing?
152
         */
153

154
        static int runpath_cached = -ERRNO_MAX-1;
16,297✔
155
        if (runpath_cached == -ERRNO_MAX-1) {
16,297✔
156
                const char *runpath = NULL;
4,405✔
157

158
                runpath_cached = get_runpath(&runpath);
4,405✔
159

160
                /* We only care if the runpath starts with $ORIGIN/ */
161
                if (runpath_cached > 0 && !startswith(runpath, "$ORIGIN/"))
4,405✔
162
                        runpath_cached = 0;
4,405✔
163
        }
164
        if (runpath_cached < 0)
16,297✔
165
                return runpath_cached;
16,297✔
166
        if (runpath_cached == 0)
16,297✔
167
                return -ENOEXEC;
168

169
        _cleanup_free_ char *exe = NULL;
×
170
        r = get_process_exe(0, &exe);
×
171
        if (r < 0)
×
172
                return runpath_cached = r;
×
173

174
        return path_extract_directory(exe, ret);
×
175
}
176

177
static int find_build_dir_binary(const char *fn, char **ret) {
16,296✔
178
        int r;
16,296✔
179

180
        assert(fn);
16,296✔
181
        assert(ret);
16,296✔
182

183
        _cleanup_free_ char *build_dir = NULL;
16,296✔
184
        r = get_build_exec_dir(&build_dir);
16,296✔
185
        if (r < 0)
16,296✔
186
                return r;
187

188
        _cleanup_free_ char *np = path_join(build_dir, fn);
×
189
        if (!np)
×
190
                return -ENOMEM;
191

192
        *ret = TAKE_PTR(np);
×
193
        return 0;
×
194
}
195

196
static int find_environment_binary(const char *fn, const char **ret) {
16,296✔
197

198
        assert(ret);
16,296✔
199

200
        /* If a path such as /usr/lib/systemd/systemd-foobar is specified, then this will check for an
201
         * environment variable SYSTEMD_FOOBAR_PATH and return it if set. */
202

203
        _cleanup_free_ char *s = strdup(fn);
16,296✔
204
        if (!s)
16,296✔
205
                return -ENOMEM;
206

207
        ascii_strupper(s);
16,296✔
208
        string_replace_char(s, '-', '_');
16,296✔
209

210
        if (!strextend(&s, "_PATH"))
16,296✔
211
                return -ENOMEM;
212

213
        const char *e;
16,296✔
214
        e = secure_getenv(s);
16,296✔
215
        if (!e)
16,296✔
216
                return -ENXIO;
217

218
        *ret = e;
×
219
        return 0;
×
220
}
221

222
int invoke_callout_binary(const char *path, char *const argv[]) {
2,949✔
223
        int r;
2,949✔
224

225
        assert(path);
2,949✔
226

227
        /* Just like execv(), but tries to execute the specified binary in the build dir instead, if known */
228

229
        _cleanup_free_ char *fn = NULL;
2,949✔
230
        r = path_extract_filename(path, &fn);
2,949✔
231
        if (r < 0)
2,949✔
232
                return r;
233
        if (r == O_DIRECTORY) /* Uh? */
2,949✔
234
                return -EISDIR;
235

236
        const char *e;
2,949✔
237
        if (find_environment_binary(fn, &e) >= 0) {
2,949✔
238
                /* If there's an explicit environment variable set for this binary, prefer it */
239
                execv(e, argv);
×
240
                return -errno; /* The environment variable counts, let's fail otherwise */
×
241
        }
242

243
        _cleanup_free_ char *np = NULL;
2,949✔
244
        if (find_build_dir_binary(fn, &np) >= 0)
2,949✔
245
                execv(np, argv);
×
246

247
        execvp(path, argv);
2,949✔
248
        return -errno;
2,949✔
249
}
250

251
int pin_callout_binary(const char *path, char **ret_path) {
13,347✔
252
        int r, fd;
13,347✔
253

254
        assert(path);
13,347✔
255

256
        /* Similar to invoke_callout_binary(), but pins (i.e. O_PATH opens) the binary instead of executing
257
         * it, also optionally provides the path to the binary. */
258

259
        _cleanup_free_ char *fn = NULL;
13,347✔
260
        r = path_extract_filename(path, &fn);
13,347✔
261
        if (r < 0)
13,347✔
262
                return r;
263
        if (r == O_DIRECTORY) /* Uh? */
13,347✔
264
                return -EISDIR;
265

266
        const char *e;
13,347✔
267
        if (find_environment_binary(fn, &e) >= 0) {
13,347✔
268
                /* The environment variable counts. We'd fail if the executable is not available/invalid. */
269
                r = open_and_check_executable(e, /* root= */ NULL, ret_path, &fd);
×
270
                if (r < 0)
×
271
                        return r;
272

273
                return fd;
×
274
        }
275

276
        _cleanup_free_ char *np = NULL;
13,347✔
277
        if (find_build_dir_binary(fn, &np) >= 0) {
13,347✔
278
                r = open_and_check_executable(np, /* root= */ NULL, ret_path, &fd);
×
279
                if (r >= 0)
×
280
                        return fd;
×
281
        }
282

283
        r = find_executable_full(path, /* root= */ NULL,
13,347✔
284
                                 /* exec_search_path= */ NULL, /* use_path_envvar= */ true,
285
                                 ret_path, &fd);
286
        if (r < 0)
13,347✔
287
                return r;
288

289
        return fd;
13,347✔
290
}
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