]> git.ipfire.org Git - thirdparty/dracut.git/blame - src/install/dracut-install.c
fix(dracut-install): protect against broken links pointing to themselves
[thirdparty/dracut.git] / src / install / dracut-install.c
CommitLineData
026b81e9
HH
1/* dracut-install.c -- install files and executables
2
3 Copyright (C) 2012 Harald Hoyer
4 Copyright (C) 2012 Red Hat, Inc. All rights reserved.
5
6 This program is free software: you can redistribute it and/or modify
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with this program; If not, see <http://www.gnu.org/licenses/>.
18*/
19
b14b039e 20#define PROGRAM_VERSION_STRING "2"
026b81e9
HH
21
22#ifndef _GNU_SOURCE
23#define _GNU_SOURCE
24#endif
026b81e9
HH
25#include <ctype.h>
26#include <errno.h>
27#include <fcntl.h>
28#include <getopt.h>
1a5845b4 29#include <glob.h>
026b81e9
HH
30#include <libgen.h>
31#include <limits.h>
32#include <stdbool.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36#include <sys/stat.h>
37#include <sys/types.h>
38#include <sys/wait.h>
39#include <unistd.h>
85854b24 40#include <sys/ioctl.h>
794b2d2c
HH
41#include <libkmod.h>
42#include <fts.h>
43#include <regex.h>
3ad12c7b 44#include <sys/utsname.h>
026b81e9
HH
45
46#include "log.h"
47#include "hashmap.h"
48#include "util.h"
2f461da2 49#include "strv.h"
026b81e9 50
e2a61595
SS
51#define _asprintf(strp, fmt, ...) \
52 do { \
53 if (dracut_asprintf(strp, fmt, __VA_ARGS__) < 0) { \
54 log_error("Out of memory\n"); \
55 exit(EXIT_FAILURE); \
56 } \
57 } while (0)
58
026b81e9
HH
59static bool arg_hmac = false;
60static bool arg_createdir = false;
61static int arg_loglevel = -1;
62static bool arg_optional = false;
794b2d2c 63static bool arg_silent = false;
026b81e9 64static bool arg_all = false;
794b2d2c 65static bool arg_module = false;
3ad12c7b 66static bool arg_modalias = false;
026b81e9
HH
67static bool arg_resolvelazy = false;
68static bool arg_resolvedeps = false;
26cd262a 69static bool arg_hostonly = false;
93be2bc6 70static bool no_xattr = false;
026b81e9 71static char *destrootdir = NULL;
a0120420
BZ
72static char *sysrootdir = NULL;
73static size_t sysrootdirlen = 0;
794b2d2c 74static char *kerneldir = NULL;
be5025bf 75static size_t kerneldirlen = 0;
794b2d2c
HH
76static char **firmwaredirs = NULL;
77static char **pathdirs;
a0120420 78static char *ldd = NULL;
37383f71
HH
79static char *logdir = NULL;
80static char *logfile = NULL;
81FILE *logfile_f = NULL;
026b81e9
HH
82static Hashmap *items = NULL;
83static Hashmap *items_failed = NULL;
eab32bda 84static Hashmap *modules_loaded = NULL;
3de4c731 85static Hashmap *modules_suppliers = NULL;
131822e2 86static Hashmap *processed_suppliers = NULL;
794b2d2c
HH
87static regex_t mod_filter_path;
88static regex_t mod_filter_nopath;
89static regex_t mod_filter_symbol;
90static regex_t mod_filter_nosymbol;
91static regex_t mod_filter_noname;
92static bool arg_mod_filter_path = false;
93static bool arg_mod_filter_nopath = false;
94static bool arg_mod_filter_symbol = false;
95static bool arg_mod_filter_nosymbol = false;
96static bool arg_mod_filter_noname = false;
026b81e9 97
e74944ee 98static int dracut_install(const char *src, const char *dst, bool isdir, bool resolvedeps, bool hashdst);
3de4c731 99static int install_dependent_modules(struct kmod_ctx *ctx, struct kmod_list *modlist, Hashmap *suppliers_paths);
026b81e9 100
f0c3b683
AT
101static void item_free(char *i)
102{
103 assert(i);
104 free(i);
105}
106
9bc5282e
HH
107static inline void kmod_module_unrefp(struct kmod_module **p)
108{
c38f9e98
HH
109 if (*p)
110 kmod_module_unref(*p);
111}
9bc5282e 112
c38f9e98 113#define _cleanup_kmod_module_unref_ _cleanup_(kmod_module_unrefp)
eab32bda 114
9bc5282e
HH
115static inline void kmod_module_unref_listp(struct kmod_list **p)
116{
eab32bda
HH
117 if (*p)
118 kmod_module_unref_list(*p);
119}
9bc5282e 120
eab32bda
HH
121#define _cleanup_kmod_module_unref_list_ _cleanup_(kmod_module_unref_listp)
122
9bc5282e
HH
123static inline void kmod_module_info_free_listp(struct kmod_list **p)
124{
eab32bda
HH
125 if (*p)
126 kmod_module_info_free_list(*p);
127}
9bc5282e 128
eab32bda
HH
129#define _cleanup_kmod_module_info_free_list_ _cleanup_(kmod_module_info_free_listp)
130
9bc5282e
HH
131static inline void kmod_unrefp(struct kmod_ctx **p)
132{
eab32bda
HH
133 kmod_unref(*p);
134}
9bc5282e 135
eab32bda
HH
136#define _cleanup_kmod_unref_ _cleanup_(kmod_unrefp)
137
9bc5282e
HH
138static inline void kmod_module_dependency_symbols_free_listp(struct kmod_list **p)
139{
eab32bda
HH
140 if (*p)
141 kmod_module_dependency_symbols_free_list(*p);
142}
9bc5282e 143
eab32bda
HH
144#define _cleanup_kmod_module_dependency_symbols_free_list_ _cleanup_(kmod_module_dependency_symbols_free_listp)
145
f1ed92c3 146static inline void fts_closep(FTS **p)
9bc5282e 147{
eab32bda
HH
148 if (*p)
149 fts_close(*p);
150}
9bc5282e 151
eab32bda
HH
152#define _cleanup_fts_close_ _cleanup_(fts_closep)
153
1a5845b4 154#define _cleanup_globfree_ _cleanup_(globfree)
eab32bda 155
f0c3b683
AT
156static inline void destroy_hashmap(Hashmap **hashmap)
157{
158 void *i = NULL;
159
160 while ((i = hashmap_steal_first(*hashmap)))
161 item_free(i);
162
163 hashmap_free(*hashmap);
164}
165
166#define _cleanup_destroy_hashmap_ _cleanup_(destroy_hashmap)
167
026b81e9
HH
168static size_t dir_len(char const *file)
169{
170 size_t length;
3ed08d1e 171
93f44f28 172 if (!file)
3ed08d1e
HH
173 return 0;
174
026b81e9 175 /* Strip the basename and any redundant slashes before it. */
93f44f28
HH
176 for (length = strlen(file) - 1; 0 < length; length--)
177 if (file[length] == '/' && file[length - 1] != '/')
026b81e9
HH
178 break;
179 return length;
180}
181
182static char *convert_abs_rel(const char *from, const char *target)
183{
184 /* we use the 4*MAXPATHLEN, which should not overrun */
53dd6a9b 185 char buf[MAXPATHLEN * 4];
186 _cleanup_free_ char *realtarget = NULL, *realfrom = NULL, *from_dir_p = NULL;
d2648f6d 187 _cleanup_free_ char *target_dir_p = NULL;
599182b1
KR
188 size_t level = 0, fromlevel = 0, targetlevel = 0;
189 int l;
190 size_t i, rl, dirlen;
026b81e9 191
53dd6a9b 192 dirlen = dir_len(from);
193 from_dir_p = strndup(from, dirlen);
194 if (!from_dir_p)
195 return strdup(from + strlen(destrootdir));
196 if (realpath(from_dir_p, buf) == NULL) {
197 log_warning("convert_abs_rel(): from '%s' directory has no realpath: %m", from);
198 return strdup(from + strlen(destrootdir));
199 }
200 /* dir_len() skips double /'s e.g. //lib64, so we can't skip just one
201 * character - need to skip all leading /'s */
202 for (i = dirlen + 1; from[i] == '/'; ++i)
203 ;
204 _asprintf(&realfrom, "%s/%s", buf, from + i);
205
e7d6a1e3 206 dirlen = dir_len(target);
207 target_dir_p = strndup(target, dirlen);
3ed08d1e 208 if (!target_dir_p)
06d31617 209 return strdup(from + strlen(destrootdir));
d2648f6d 210 if (realpath(target_dir_p, buf) == NULL) {
53dd6a9b 211 log_warning("convert_abs_rel(): target '%s' directory has no realpath: %m", target);
06d31617 212 return strdup(from + strlen(destrootdir));
026b81e9
HH
213 }
214
e7d6a1e3 215 for (i = dirlen + 1; target[i] == '/'; ++i)
216 ;
d2648f6d 217 _asprintf(&realtarget, "%s/%s", buf, target + i);
026b81e9
HH
218
219 /* now calculate the relative path from <from> to <target> and
53dd6a9b 220 store it in <buf>
026b81e9 221 */
026b81e9
HH
222 rl = 0;
223
224 /* count the pathname elements of realtarget */
225 for (targetlevel = 0, i = 0; realtarget[i]; i++)
226 if (realtarget[i] == '/')
227 targetlevel++;
228
229 /* count the pathname elements of realfrom */
230 for (fromlevel = 0, i = 0; realfrom[i]; i++)
231 if (realfrom[i] == '/')
232 fromlevel++;
233
234 /* count the pathname elements, which are common for both paths */
235 for (level = 0, i = 0; realtarget[i] && (realtarget[i] == realfrom[i]); i++)
236 if (realtarget[i] == '/')
237 level++;
238
53dd6a9b 239 /* add "../" to the buf path, until the common pathname is
026b81e9
HH
240 reached */
241 for (i = level; i < targetlevel; i++) {
242 if (i != level)
53dd6a9b 243 buf[rl++] = '/';
244 buf[rl++] = '.';
245 buf[rl++] = '.';
026b81e9
HH
246 }
247
248 /* set l to the next uncommon pathname element in realfrom */
249 for (l = 1, i = 1; i < level; i++)
250 for (l++; realfrom[l] && realfrom[l] != '/'; l++) ;
251 /* skip next '/' */
252 l++;
253
53dd6a9b 254 /* append the uncommon rest of realfrom to the buf path */
026b81e9
HH
255 for (i = level; i <= fromlevel; i++) {
256 if (rl)
53dd6a9b 257 buf[rl++] = '/';
026b81e9 258 while (realfrom[l] && realfrom[l] != '/')
53dd6a9b 259 buf[rl++] = realfrom[l++];
026b81e9
HH
260 l++;
261 }
262
53dd6a9b 263 buf[rl] = 0;
264 return strdup(buf);
026b81e9
HH
265}
266
267static int ln_r(const char *src, const char *dst)
268{
269 int ret;
3ed08d1e
HH
270 _cleanup_free_ const char *points_to = convert_abs_rel(src, dst);
271
026b81e9
HH
272 log_info("ln -s '%s' '%s'", points_to, dst);
273 ret = symlink(points_to, dst);
274
275 if (ret != 0) {
276 log_error("ERROR: ln -s '%s' '%s': %m", points_to, dst);
026b81e9
HH
277 return 1;
278 }
279
026b81e9
HH
280 return 0;
281}
282
85854b24
HH
283/* Perform the O(1) btrfs clone operation, if possible.
284 Upon success, return 0. Otherwise, return -1 and set errno. */
285static inline int clone_file(int dest_fd, int src_fd)
286{
287#undef BTRFS_IOCTL_MAGIC
288#define BTRFS_IOCTL_MAGIC 0x94
289#undef BTRFS_IOC_CLONE
290#define BTRFS_IOC_CLONE _IOW (BTRFS_IOCTL_MAGIC, 9, int)
291 return ioctl(dest_fd, BTRFS_IOC_CLONE, src_fd);
292}
293
294static bool use_clone = true;
295
026b81e9
HH
296static int cp(const char *src, const char *dst)
297{
298 int pid;
3ed08d1e 299 int ret = 0;
85854b24 300
f6c2faeb 301 if (use_clone) {
85854b24 302 struct stat sb;
3ed08d1e 303 _cleanup_close_ int dest_desc = -1, source_desc = -1;
85854b24
HH
304
305 if (lstat(src, &sb) != 0)
306 goto normal_copy;
307
308 if (S_ISLNK(sb.st_mode))
309 goto normal_copy;
310
311 source_desc = open(src, O_RDONLY | O_CLOEXEC);
312 if (source_desc < 0)
313 goto normal_copy;
026b81e9 314
85854b24 315 dest_desc =
f1ed92c3
HH
316 open(dst, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC,
317 (sb.st_mode) & (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO));
85854b24
HH
318
319 if (dest_desc < 0) {
85854b24
HH
320 goto normal_copy;
321 }
322
323 ret = clone_file(dest_desc, source_desc);
3ed08d1e 324
85854b24 325 if (ret == 0) {
6f4c2dad 326 struct timeval tv[2];
85854b24 327 if (fchown(dest_desc, sb.st_uid, sb.st_gid) != 0)
9bc5282e 328 if (fchown(dest_desc, (uid_t) - 1, sb.st_gid) != 0) {
076fcd16
HH
329 if (geteuid() == 0)
330 log_error("Failed to chown %s: %m", dst);
331 else
332 log_info("Failed to chown %s: %m", dst);
333 }
334
6f4c2dad
HH
335 tv[0].tv_sec = sb.st_atime;
336 tv[0].tv_usec = 0;
337 tv[1].tv_sec = sb.st_mtime;
338 tv[1].tv_usec = 0;
339 futimes(dest_desc, tv);
85854b24
HH
340 return ret;
341 }
342 close(dest_desc);
3ed08d1e 343 dest_desc = -1;
85854b24
HH
344 /* clone did not work, remove the file */
345 unlink(dst);
346 /* do not try clone again */
347 use_clone = false;
348 }
349
f1ed92c3 350normal_copy:
026b81e9 351 pid = fork();
13736c50 352 const char *preservation = (geteuid() == 0
353 && no_xattr == false) ? "--preserve=mode,xattr,timestamps,ownership" : "--preserve=mode,timestamps,ownership";
026b81e9 354 if (pid == 0) {
13736c50 355 execlp("cp", "cp", "--reflink=auto", "--sparse=auto", preservation, "-fL", src, dst, NULL);
356 _exit(errno == ENOENT ? 127 : 126);
026b81e9
HH
357 }
358
13736c50 359 while (waitpid(pid, &ret, 0) == -1) {
026b81e9 360 if (errno != EINTR) {
13736c50 361 log_error("ERROR: waitpid() failed: %m");
362 return 1;
026b81e9
HH
363 }
364 }
13736c50 365 ret = WIFSIGNALED(ret) ? 128 + WTERMSIG(ret) : WEXITSTATUS(ret);
366 if (ret != 0)
367 log_error("ERROR: 'cp --reflink=auto --sparse=auto %s -fL %s %s' failed with %d", preservation, src, dst, ret);
3ed08d1e 368 log_debug("cp ret = %d", ret);
85854b24 369 return ret;
026b81e9
HH
370}
371
791532b0
HH
372static int library_install(const char *src, const char *lib)
373{
374 _cleanup_free_ char *p = NULL;
10ed204f
DT
375 _cleanup_free_ char *pdir = NULL, *ppdir = NULL, *pppdir = NULL, *clib = NULL;
376 char *q, *clibdir;
791532b0
HH
377 int r, ret = 0;
378
a20556f0 379 r = dracut_install(lib, lib, false, false, true);
791532b0 380 if (r != 0)
a20556f0 381 log_error("ERROR: failed to install '%s' for '%s'", lib, src);
791532b0 382 else
a20556f0 383 log_debug("Lib install: '%s'", lib);
791532b0
HH
384 ret += r;
385
386 /* also install lib.so for lib.so.* files */
a20556f0 387 q = strstr(lib, ".so.");
791532b0 388 if (q) {
a20556f0 389 p = strndup(lib, q - lib + 3);
791532b0
HH
390
391 /* ignore errors for base lib symlink */
392 if (dracut_install(p, p, false, false, true) == 0)
393 log_debug("Lib install: '%s'", p);
a20556f0 394
395 free(p);
791532b0
HH
396 }
397
10ed204f
DT
398 /* Also try to install the same library from one directory above
399 * or from one directory above glibc-hwcaps.
791532b0 400 This fixes the case, where only the HWCAP lib would be installed
9430ae30 401 # ldconfig -p|grep -F libc.so
791532b0
HH
402 libc.so.6 (libc6,64bit, hwcap: 0x0000001000000000, OS ABI: Linux 2.6.32) => /lib64/power6/libc.so.6
403 libc.so.6 (libc6,64bit, hwcap: 0x0000000000000200, OS ABI: Linux 2.6.32) => /lib64/power6x/libc.so.6
404 libc.so.6 (libc6,64bit, OS ABI: Linux 2.6.32) => /lib64/libc.so.6
93f44f28 405 */
791532b0 406
791532b0
HH
407 p = strdup(lib);
408
7f2b0933 409 pdir = dirname_malloc(p);
791532b0
HH
410 if (!pdir)
411 return ret;
412
7f2b0933 413 ppdir = dirname_malloc(pdir);
ebbcf97d
MM
414 /* only one parent directory, not HWCAP library */
415 if (!ppdir || streq(ppdir, "/"))
791532b0
HH
416 return ret;
417
7f2b0933 418 pppdir = dirname_malloc(ppdir);
10ed204f
DT
419 if (!pppdir)
420 return ret;
421
10ed204f
DT
422 clibdir = streq(basename(ppdir), "glibc-hwcaps") ? pppdir : ppdir;
423 clib = strjoin(clibdir, "/", basename(p), NULL);
791532b0
HH
424 if (dracut_install(clib, clib, false, false, true) == 0)
425 log_debug("Lib install: '%s'", clib);
426 /* also install lib.so for lib.so.* files */
427 q = strstr(clib, ".so.");
428 if (q) {
429 q[3] = '\0';
430
431 /* ignore errors for base lib symlink */
432 if (dracut_install(clib, clib, false, false, true) == 0)
433 log_debug("Lib install: '%s'", p);
434 }
435
436 return ret;
437}
438
a0120420
BZ
439static char *get_real_file(const char *src, bool fullyresolve)
440{
e2a61595 441 struct stat sb;
a0120420 442 ssize_t linksz;
e2a61595 443 char linktarget[PATH_MAX + 1];
e7d6a1e3 444 _cleanup_free_ char *fullsrcpath_a = NULL;
445 const char *fullsrcpath;
e2a61595 446 _cleanup_free_ char *abspath = NULL;
a0120420
BZ
447
448 if (sysrootdirlen) {
e2a61595 449 if (strncmp(src, sysrootdir, sysrootdirlen) == 0) {
e7d6a1e3 450 fullsrcpath = src;
e2a61595 451 } else {
e7d6a1e3 452 _asprintf(&fullsrcpath_a, "%s/%s",
e2a61595
SS
453 (sysrootdirlen ? sysrootdir : ""),
454 (src[0] == '/' ? src + 1 : src));
e7d6a1e3 455 fullsrcpath = fullsrcpath_a;
e2a61595
SS
456 }
457 } else {
e7d6a1e3 458 fullsrcpath = src;
e2a61595 459 }
a0120420
BZ
460
461 log_debug("get_real_file('%s')", fullsrcpath);
462
463 if (lstat(fullsrcpath, &sb) < 0)
9bc5282e 464 return NULL;
a0120420
BZ
465
466 switch (sb.st_mode & S_IFMT) {
467 case S_IFDIR:
468 case S_IFREG:
9bc5282e 469 return strdup(fullsrcpath);
a0120420 470 case S_IFLNK:
9bc5282e 471 break;
a0120420 472 default:
9bc5282e 473 return NULL;
a0120420
BZ
474 }
475
476 linksz = readlink(fullsrcpath, linktarget, sizeof(linktarget));
477 if (linksz < 0)
478 return NULL;
479 linktarget[linksz] = '\0';
480
481 log_debug("get_real_file: readlink('%s') returns '%s'", fullsrcpath, linktarget);
482
32f6f364
AAF
483 if (streq(fullsrcpath, linktarget)) {
484 log_error("ERROR: '%s' is pointing to itself", fullsrcpath);
485 return NULL;
486 }
487
a0120420 488 if (linktarget[0] == '/') {
e2a61595 489 _asprintf(&abspath, "%s%s", (sysrootdirlen ? sysrootdir : ""), linktarget);
a0120420 490 } else {
e7d6a1e3 491 _asprintf(&abspath, "%.*s/%s", (int)dir_len(fullsrcpath), fullsrcpath, linktarget);
a0120420
BZ
492 }
493
494 if (fullyresolve) {
495 struct stat st;
496 if (lstat(abspath, &st) < 0) {
1beeaf3b 497 if (errno != ENOENT) {
a0120420 498 return NULL;
1beeaf3b
ZB
499 }
500 }
501 if (S_ISLNK(st.st_mode)) {
e2a61595 502 return get_real_file(abspath, fullyresolve);
a0120420 503 }
a0120420
BZ
504 }
505
506 log_debug("get_real_file('%s') => '%s'", src, abspath);
e2a61595 507 return TAKE_PTR(abspath);
a0120420
BZ
508}
509
026b81e9
HH
510static int resolve_deps(const char *src)
511{
d010fa0d 512 int ret = 0, err;
026b81e9 513
e7ba1392 514 _cleanup_free_ char *buf = NULL;
d010fa0d 515 size_t linesize = LINE_MAX + 1;
a0120420
BZ
516 _cleanup_free_ char *fullsrcpath = NULL;
517
518 fullsrcpath = get_real_file(src, true);
519 log_debug("resolve_deps('%s') -> get_real_file('%s', true) = '%s'", src, src, fullsrcpath);
520 if (!fullsrcpath)
521 return 0;
026b81e9 522
d010fa0d 523 buf = malloc(linesize);
731b37e9
HH
524 if (buf == NULL)
525 return -errno;
e7ba1392 526
b0bf8187 527 if (strstr(src, ".so") == NULL) {
3ed08d1e 528 _cleanup_close_ int fd = -1;
a0120420 529 fd = open(fullsrcpath, O_RDONLY | O_CLOEXEC);
3ed08d1e
HH
530 if (fd < 0)
531 return -errno;
532
d010fa0d 533 ret = read(fd, buf, linesize - 1);
e7ba1392
HH
534 if (ret == -1)
535 return -errno;
536
d010fa0d 537 buf[ret] = '\0';
026b81e9
HH
538 if (buf[0] == '#' && buf[1] == '!') {
539 /* we have a shebang */
540 char *p, *q;
541 for (p = &buf[2]; *p && isspace(*p); p++) ;
542 for (q = p; *q && (!isspace(*q)); q++) ;
543 *q = '\0';
544 log_debug("Script install: '%s'", p);
e74944ee 545 ret = dracut_install(p, p, false, true, false);
026b81e9
HH
546 if (ret != 0)
547 log_error("ERROR: failed to install '%s'", p);
548 return ret;
549 }
550 }
551
d010fa0d 552 int fds[2];
553 FILE *fptr;
554 if (pipe2(fds, O_CLOEXEC) == -1 || (fptr = fdopen(fds[0], "r")) == NULL) {
144279a5 555 log_error("ERROR: pipe stream initialization for '%s' failed: %m", ldd);
d010fa0d 556 exit(EXIT_FAILURE);
557 }
d9eff33c 558
d010fa0d 559 log_debug("%s %s", ldd, fullsrcpath);
560 pid_t ldd_pid;
561 if ((ldd_pid = fork()) == 0) {
562 dup2(fds[1], 1);
563 dup2(fds[1], 2);
564 putenv("LC_ALL=C");
565 execlp(ldd, ldd, fullsrcpath, (char *)NULL);
566 _exit(errno == ENOENT ? 127 : 126);
567 }
568 close(fds[1]);
a0120420 569
3ed08d1e
HH
570 ret = 0;
571
d010fa0d 572 while (getline(&buf, &linesize, fptr) >= 0) {
e7ba1392 573 char *p;
026b81e9 574
026b81e9
HH
575 log_debug("ldd: '%s'", buf);
576
b4dc22ca 577 if (strstr(buf, "you do not have execution permission")) {
599182b1 578 log_error("%s", buf);
93f44f28 579 ret += 1;
b4dc22ca
HH
580 break;
581 }
582
a0120420 583 /* errors from cross-compiler-ldd */
d010fa0d 584 if (strstr(buf, "unable to find sysroot")) {
a0120420
BZ
585 log_error("%s", buf);
586 ret += 1;
587 break;
588 }
589
731b37e9
HH
590 /* musl ldd */
591 if (strstr(buf, "Not a valid dynamic program"))
592 break;
69641693 593
731b37e9 594 /* glibc */
b127294d 595 if (strstr(buf, "cannot execute binary file"))
9a531ca0 596 continue;
b127294d 597
026b81e9
HH
598 if (strstr(buf, "not a dynamic executable"))
599 break;
600
a9231107
HH
601 if (strstr(buf, "loader cannot load itself"))
602 break;
603
43a050e5
HH
604 if (strstr(buf, "not regular file"))
605 break;
87dc81a1
HH
606
607 if (strstr(buf, "cannot read header"))
608 break;
609
4916dfc2
DT
610 if (strstr(buf, "cannot be preloaded"))
611 break;
612
87dc81a1
HH
613 if (strstr(buf, destrootdir))
614 break;
43a050e5 615
d1a36d3d
JJ
616 p = buf;
617 if (strchr(p, '$')) {
618 /* take ldd variable expansion into account */
619 p = strstr(p, "=>");
620 if (!p)
621 p = buf;
622 }
623 p = strchr(p, '/');
624
026b81e9 625 if (p) {
e7ba1392
HH
626 char *q;
627
026b81e9
HH
628 for (q = p; *q && *q != ' ' && *q != '\n'; q++) ;
629 *q = '\0';
791532b0
HH
630
631 ret += library_install(src, p);
632
026b81e9
HH
633 }
634 }
026b81e9 635
d010fa0d 636 fclose(fptr);
637 while (waitpid(ldd_pid, &err, 0) == -1) {
638 if (errno != EINTR) {
639 log_error("ERROR: waitpid() failed: %m");
640 return 1;
641 }
642 }
643 err = WIFSIGNALED(err) ? 128 + WTERMSIG(err) : WEXITSTATUS(err);
644 /* ldd has error conditions we largely don't care about ("not a dynamic executable", &c.):
645 only error out on hard errors (ENOENT, ENOEXEC, signals) */
646 if (err >= 126) {
647 log_error("ERROR: '%s %s' failed with %d", ldd, fullsrcpath, err);
648 return err;
649 } else
650 return ret;
026b81e9
HH
651}
652
653/* Install ".<filename>.hmac" file for FIPS self-checks */
cce471c9 654static int hmac_install(const char *src, const char *dst, const char *hmacpath)
026b81e9 655{
3ed08d1e
HH
656 _cleanup_free_ char *srchmacname = NULL;
657 _cleanup_free_ char *dsthmacname = NULL;
658
026b81e9
HH
659 size_t dlen = dir_len(src);
660
661 if (endswith(src, ".hmac"))
662 return 0;
663
93f44f28 664 if (!hmacpath) {
cce471c9
MB
665 hmac_install(src, dst, "/lib/fipscheck");
666 hmac_install(src, dst, "/lib64/fipscheck");
6f4c2dad
HH
667 hmac_install(src, dst, "/lib/hmaccalc");
668 hmac_install(src, dst, "/lib64/hmaccalc");
cce471c9
MB
669 }
670
cce471c9 671 if (hmacpath) {
e2a61595
SS
672 _asprintf(&srchmacname, "%s/%s.hmac", hmacpath, &src[dlen + 1]);
673 _asprintf(&dsthmacname, "%s/%s.hmac", hmacpath, &src[dlen + 1]);
cce471c9 674 } else {
77226cb4 675 _asprintf(&srchmacname, "%.*s/.%s.hmac", (int)dlen, src, &src[dlen + 1]);
676 _asprintf(&dsthmacname, "%.*s/.%s.hmac", (int)dir_len(dst), dst, &src[dlen + 1]);
cce471c9 677 }
77226cb4 678 log_debug("hmac cp '%s' '%s'", srchmacname, dsthmacname);
e74944ee 679 dracut_install(srchmacname, dsthmacname, false, false, true);
026b81e9
HH
680 return 0;
681}
682
26cd262a
HH
683void mark_hostonly(const char *path)
684{
685 _cleanup_free_ char *fulldstpath = NULL;
686 _cleanup_fclose_ FILE *f = NULL;
26cd262a 687
e2a61595 688 _asprintf(&fulldstpath, "%s/lib/dracut/hostonly-files", destrootdir);
26cd262a
HH
689
690 f = fopen(fulldstpath, "a");
691
692 if (f == NULL) {
693 log_error("Could not open '%s' for writing.", fulldstpath);
694 return;
695 }
696
697 fprintf(f, "%s\n", path);
26cd262a
HH
698}
699
37383f71
HH
700void dracut_log_cp(const char *path)
701{
702 int ret;
703 ret = fprintf(logfile_f, "%s\n", path);
704 if (ret < 0)
705 log_error("Could not append '%s' to logfile '%s': %m", path, logfile);
706}
707
f1ed92c3 708static bool check_hashmap(Hashmap *hm, const char *item)
794b2d2c
HH
709{
710 char *existing;
711 existing = hashmap_get(hm, item);
712 if (existing) {
713 if (strcmp(existing, item) == 0) {
714 return true;
715 }
716 }
717 return false;
718}
719
9bc5282e
HH
720static int dracut_mkdir(const char *src)
721{
a0120420 722 _cleanup_free_ char *parent = NULL;
3d2a6d29 723 char *path;
a0120420
BZ
724 struct stat sb;
725
726 parent = strdup(src);
727 if (!parent)
728 return 1;
729
9bc5282e 730 path = parent[0] == '/' ? parent + 1 : parent;
3d2a6d29
LVR
731 while (path) {
732 path = strstr(path, "/");
733 if (path)
734 *path = '\0';
735
736 if (stat(parent, &sb) == 0) {
737 if (!S_ISDIR(sb.st_mode)) {
738 log_error("%s exists but is not a directory!", parent);
739 return 1;
740 }
741 } else if (errno != ENOENT) {
94dcac7c 742 log_error("ERROR: stat '%s': %m", parent);
a0120420 743 return 1;
3d2a6d29
LVR
744 } else {
745 if (mkdir(parent, 0755) < 0) {
94dcac7c 746 log_error("ERROR: mkdir '%s': %m", parent);
3d2a6d29
LVR
747 return 1;
748 }
a0120420
BZ
749 }
750
3d2a6d29
LVR
751 if (path) {
752 *path = '/';
753 path++;
754 }
a0120420
BZ
755 }
756
3d2a6d29 757 return 0;
a0120420
BZ
758}
759
760static int dracut_install(const char *orig_src, const char *orig_dst, bool isdir, bool resolvedeps, bool hashdst)
026b81e9 761{
e7ed8337 762 struct stat sb;
a0120420 763 _cleanup_free_ char *fullsrcpath = NULL;
3ed08d1e
HH
764 _cleanup_free_ char *fulldstpath = NULL;
765 _cleanup_free_ char *fulldstdir = NULL;
026b81e9 766 int ret;
a0120420
BZ
767 bool src_islink = false;
768 bool src_isdir = false;
769 mode_t src_mode = 0;
770 bool dst_exists = true;
3ed08d1e 771 char *i = NULL;
a20556f0 772 const char *src, *dst;
a0120420
BZ
773
774 if (sysrootdirlen) {
775 if (strncmp(orig_src, sysrootdir, sysrootdirlen) == 0) {
a20556f0 776 src = orig_src + sysrootdirlen;
a0120420
BZ
777 fullsrcpath = strdup(orig_src);
778 } else {
a20556f0 779 src = orig_src;
e2a61595 780 _asprintf(&fullsrcpath, "%s%s", sysrootdir, src);
a0120420
BZ
781 }
782 if (strncmp(orig_dst, sysrootdir, sysrootdirlen) == 0)
a20556f0 783 dst = orig_dst + sysrootdirlen;
a0120420 784 else
a20556f0 785 dst = orig_dst;
a0120420 786 } else {
a20556f0 787 src = orig_src;
a0120420 788 fullsrcpath = strdup(src);
a20556f0 789 dst = orig_dst;
a0120420 790 }
026b81e9 791
a0120420 792 log_debug("dracut_install('%s', '%s', %d, %d, %d)", src, dst, isdir, resolvedeps, hashdst);
026b81e9 793
794b2d2c
HH
794 if (check_hashmap(items_failed, src)) {
795 log_debug("hash hit items_failed for '%s'", src);
796 return 1;
026b81e9
HH
797 }
798
794b2d2c
HH
799 if (hashdst && check_hashmap(items, dst)) {
800 log_debug("hash hit items for '%s'", dst);
801 return 0;
026b81e9
HH
802 }
803
a0120420 804 if (lstat(fullsrcpath, &sb) < 0) {
026b81e9
HH
805 if (!isdir) {
806 i = strdup(src);
807 hashmap_put(items_failed, i, i);
808 /* src does not exist */
809 return 1;
810 }
a0120420
BZ
811 } else {
812 src_islink = S_ISLNK(sb.st_mode);
813 src_isdir = S_ISDIR(sb.st_mode);
814 src_mode = sb.st_mode;
026b81e9
HH
815 }
816
e2a61595 817 _asprintf(&fulldstpath, "%s/%s", destrootdir, (dst[0] == '/' ? (dst + 1) : dst));
026b81e9
HH
818
819 ret = stat(fulldstpath, &sb);
a0120420
BZ
820 if (ret != 0) {
821 dst_exists = false;
822 if (errno != ENOENT) {
823 log_error("ERROR: stat '%s': %m", fulldstpath);
824 return 1;
825 }
026b81e9
HH
826 }
827
828 if (ret == 0) {
43a050e5 829 if (resolvedeps && S_ISREG(sb.st_mode) && (sb.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) {
68318328 830 log_debug("'%s' already exists, but checking for any deps", fulldstpath);
5ac581ef 831 ret = resolve_deps(fulldstpath + sysrootdirlen);
68318328
CG
832 } else
833 log_debug("'%s' already exists", fulldstpath);
834
026b81e9 835 /* dst does already exist */
ee9b9b12 836 } else {
026b81e9 837
ee9b9b12 838 /* check destination directory */
e7d6a1e3 839 fulldstdir = strndup(fulldstpath, dir_len(fulldstpath));
ee9b9b12
DM
840 if (!fulldstdir) {
841 log_error("Out of memory!");
842 return 1;
843 }
026b81e9 844
e7ed8337 845 ret = access(fulldstdir, F_OK);
026b81e9 846
ee9b9b12
DM
847 if (ret < 0) {
848 _cleanup_free_ char *dname = NULL;
3ed08d1e 849
ee9b9b12
DM
850 if (errno != ENOENT) {
851 log_error("ERROR: stat '%s': %m", fulldstdir);
852 return 1;
853 }
854 /* create destination directory */
855 log_debug("dest dir '%s' does not exist", fulldstdir);
e7d6a1e3 856
857 dname = strndup(dst, dir_len(dst));
ee9b9b12
DM
858 if (!dname)
859 return 1;
ee9b9b12 860 ret = dracut_install(dname, dname, true, false, true);
026b81e9 861
ee9b9b12
DM
862 if (ret != 0) {
863 log_error("ERROR: failed to create directory '%s'", fulldstdir);
864 return 1;
865 }
026b81e9 866 }
026b81e9 867
ee9b9b12
DM
868 if (src_isdir) {
869 if (dst_exists) {
870 if (S_ISDIR(sb.st_mode)) {
871 log_debug("dest dir '%s' already exists", fulldstpath);
872 return 0;
873 }
874 log_error("dest dir '%s' already exists but is not a directory", fulldstpath);
875 return 1;
a0120420 876 }
a0120420 877
ee9b9b12
DM
878 log_info("mkdir '%s'", fulldstpath);
879 ret = dracut_mkdir(fulldstpath);
880 if (ret == 0) {
881 i = strdup(dst);
882 if (!i)
883 return -ENOMEM;
a0120420 884
ee9b9b12
DM
885 hashmap_put(items, i, i);
886 }
887 return ret;
a0120420 888 }
026b81e9 889
ee9b9b12 890 /* ready to install src */
026b81e9 891
ee9b9b12
DM
892 if (src_islink) {
893 _cleanup_free_ char *abspath = NULL;
026b81e9 894
ee9b9b12 895 abspath = get_real_file(src, false);
026b81e9 896
ee9b9b12
DM
897 if (abspath == NULL)
898 return 1;
026b81e9 899
ee9b9b12
DM
900 if (dracut_install(abspath, abspath, false, resolvedeps, hashdst)) {
901 log_debug("'%s' install error", abspath);
902 return 1;
903 }
026b81e9 904
e7ed8337 905 if (faccessat(AT_FDCWD, abspath, F_OK, AT_SYMLINK_NOFOLLOW) != 0) {
ee9b9b12
DM
906 log_debug("lstat '%s': %m", abspath);
907 return 1;
908 }
026b81e9 909
e7ed8337 910 if (faccessat(AT_FDCWD, fulldstpath, F_OK, AT_SYMLINK_NOFOLLOW) != 0) {
ee9b9b12 911 _cleanup_free_ char *absdestpath = NULL;
026b81e9 912
e2a61595
SS
913 _asprintf(&absdestpath, "%s/%s", destrootdir,
914 (abspath[0] == '/' ? (abspath + 1) : abspath) + sysrootdirlen);
ee9b9b12
DM
915
916 ln_r(absdestpath, fulldstpath);
d9eff33c 917 }
026b81e9 918
ee9b9b12
DM
919 if (arg_hmac) {
920 /* copy .hmac files also */
921 hmac_install(src, dst, NULL);
922 }
026b81e9 923
ee9b9b12 924 return 0;
026b81e9
HH
925 }
926
ee9b9b12
DM
927 if (src_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
928 if (resolvedeps)
929 ret += resolve_deps(fullsrcpath + sysrootdirlen);
930 if (arg_hmac) {
931 /* copy .hmac files also */
932 hmac_install(src, dst, NULL);
933 }
026b81e9 934 }
026b81e9 935
ee9b9b12 936 log_debug("dracut_install ret = %d", ret);
26cd262a 937
ee9b9b12
DM
938 if (arg_hostonly && !arg_module)
939 mark_hostonly(dst);
26cd262a 940
ee9b9b12
DM
941 if (isdir) {
942 log_info("mkdir '%s'", fulldstpath);
943 ret += dracut_mkdir(fulldstpath);
944 } else {
945 log_info("cp '%s' '%s'", fullsrcpath, fulldstpath);
946 ret += cp(fullsrcpath, fulldstpath);
947 }
a0120420
BZ
948 }
949
950 if (ret == 0) {
951 i = strdup(dst);
952 if (!i)
953 return -ENOMEM;
954
955 hashmap_put(items, i, i);
956
957 if (logfile_f)
958 dracut_log_cp(src);
959 }
3ed08d1e
HH
960
961 log_debug("dracut_install ret = %d", ret);
962
026b81e9
HH
963 return ret;
964}
965
026b81e9 966static void usage(int status)
93f44f28 967{
9bc5282e 968 /* */
a0120420
BZ
969 printf("Usage: %s -D DESTROOTDIR [-r SYSROOTDIR] [OPTION]... -a SOURCE...\n"
970 "or: %s -D DESTROOTDIR [-r SYSROOTDIR] [OPTION]... SOURCE DEST\n"
971 "or: %s -D DESTROOTDIR [-r SYSROOTDIR] [OPTION]... -m KERNELMODULE [KERNELMODULE …]\n"
3ed08d1e 972 "\n"
a0120420 973 "Install SOURCE (from rootfs or SYSROOTDIR) to DEST in DESTROOTDIR with all needed dependencies.\n"
3ed08d1e 974 "\n"
b14b039e
HH
975 " KERNELMODULE can have the format:\n"
976 " <absolute path> with a leading /\n"
977 " =<kernel subdir>[/<kernel subdir>…] like '=drivers/hid'\n"
978 " <module name>\n"
3ed08d1e 979 "\n"
b14b039e 980 " -D --destrootdir Install all files to DESTROOTDIR as the root\n"
a0120420 981 " -r --sysrootdir Install all files from SYSROOTDIR\n"
b14b039e
HH
982 " -a --all Install all SOURCE arguments to DESTROOTDIR\n"
983 " -o --optional If SOURCE does not exist, do not fail\n"
984 " -d --dir SOURCE is a directory\n"
985 " -l --ldd Also install shebang executables and libraries\n"
986 " -L --logdir <DIR> Log files, which were installed from the host to <DIR>\n"
987 " -R --resolvelazy Only install shebang executables and libraries\n"
988 " for all SOURCE files\n"
989 " -H --hostonly Mark all SOURCE files as hostonly\n\n"
990 " -f --fips Also install all '.SOURCE.hmac' files\n"
991 "\n"
992 " --module,-m Install kernel modules, instead of files\n"
993 " --kerneldir Specify the kernel module directory\n"
95aeed89 994 " (default: /lib/modules/$(uname -r))\n"
b14b039e 995 " --firmwaredirs Specify the firmware directory search path with : separation\n"
95aeed89 996 " (default: $DRACUT_FIRMWARE_PATH, otherwise kernel-compatible\n"
997 " $(</sys/module/firmware_class/parameters/path),\n"
998 " /lib/firmware/updates/$(uname -r), /lib/firmware/updates\n"
999 " /lib/firmware/$(uname -r), /lib/firmware)\n"
b14b039e 1000 " --silent Don't display error messages for kernel module install\n"
3ad12c7b 1001 " --modalias Only generate module list from /sys/devices modalias list\n"
b14b039e
HH
1002 " -o --optional If kernel module does not exist, do not fail\n"
1003 " -p --mod-filter-path Filter kernel modules by path regexp\n"
1004 " -P --mod-filter-nopath Exclude kernel modules by path regexp\n"
1005 " -s --mod-filter-symbol Filter kernel modules by symbol regexp\n"
1006 " -S --mod-filter-nosymbol Exclude kernel modules by symbol regexp\n"
1007 " -N --mod-filter-noname Exclude kernel modules by name regexp\n"
1008 "\n"
1009 " -v --verbose Show more output\n"
1010 " --debug Show debug output\n"
1011 " --version Show package version\n"
1012 " -h --help Show this help\n"
9bc5282e 1013 "\n", program_invocation_short_name, program_invocation_short_name, program_invocation_short_name);
026b81e9
HH
1014 exit(status);
1015}
1016
1017static int parse_argv(int argc, char *argv[])
1018{
1019 int c;
1020
1021 enum {
1022 ARG_VERSION = 0x100,
794b2d2c 1023 ARG_SILENT,
3ad12c7b 1024 ARG_MODALIAS,
794b2d2c
HH
1025 ARG_KERNELDIR,
1026 ARG_FIRMWAREDIRS,
026b81e9
HH
1027 ARG_DEBUG
1028 };
1029
3ed08d1e 1030 static struct option const options[] = {
026b81e9
HH
1031 {"help", no_argument, NULL, 'h'},
1032 {"version", no_argument, NULL, ARG_VERSION},
1033 {"dir", no_argument, NULL, 'd'},
1034 {"debug", no_argument, NULL, ARG_DEBUG},
1035 {"verbose", no_argument, NULL, 'v'},
1036 {"ldd", no_argument, NULL, 'l'},
1037 {"resolvelazy", no_argument, NULL, 'R'},
1038 {"optional", no_argument, NULL, 'o'},
26cd262a 1039 {"hostonly", no_argument, NULL, 'H'},
026b81e9 1040 {"all", no_argument, NULL, 'a'},
794b2d2c 1041 {"module", no_argument, NULL, 'm'},
26cd262a 1042 {"fips", no_argument, NULL, 'f'},
026b81e9 1043 {"destrootdir", required_argument, NULL, 'D'},
a0120420 1044 {"sysrootdir", required_argument, NULL, 'r'},
37383f71 1045 {"logdir", required_argument, NULL, 'L'},
794b2d2c
HH
1046 {"mod-filter-path", required_argument, NULL, 'p'},
1047 {"mod-filter-nopath", required_argument, NULL, 'P'},
1048 {"mod-filter-symbol", required_argument, NULL, 's'},
1049 {"mod-filter-nosymbol", required_argument, NULL, 'S'},
1050 {"mod-filter-noname", required_argument, NULL, 'N'},
3ad12c7b 1051 {"modalias", no_argument, NULL, ARG_MODALIAS},
794b2d2c
HH
1052 {"silent", no_argument, NULL, ARG_SILENT},
1053 {"kerneldir", required_argument, NULL, ARG_KERNELDIR},
1054 {"firmwaredirs", required_argument, NULL, ARG_FIRMWAREDIRS},
026b81e9
HH
1055 {NULL, 0, NULL, 0}
1056 };
1057
a0120420 1058 while ((c = getopt_long(argc, argv, "madfhlL:oD:Hr:Rp:P:s:S:N:v", options, NULL)) != -1) {
026b81e9
HH
1059 switch (c) {
1060 case ARG_VERSION:
1061 puts(PROGRAM_VERSION_STRING);
1062 return 0;
1063 case 'd':
1064 arg_createdir = true;
1065 break;
1066 case ARG_DEBUG:
1067 arg_loglevel = LOG_DEBUG;
1068 break;
794b2d2c
HH
1069 case ARG_SILENT:
1070 arg_silent = true;
1071 break;
3ad12c7b
HH
1072 case ARG_MODALIAS:
1073 arg_modalias = true;
1074 return 1;
1075 break;
026b81e9
HH
1076 case 'v':
1077 arg_loglevel = LOG_INFO;
1078 break;
1079 case 'o':
1080 arg_optional = true;
1081 break;
1082 case 'l':
1083 arg_resolvedeps = true;
1084 break;
1085 case 'R':
1086 arg_resolvelazy = true;
1087 break;
1088 case 'a':
1089 arg_all = true;
1090 break;
794b2d2c
HH
1091 case 'm':
1092 arg_module = true;
1093 break;
026b81e9 1094 case 'D':
efd4ca27 1095 destrootdir = optarg;
026b81e9 1096 break;
a0120420 1097 case 'r':
efd4ca27 1098 sysrootdir = optarg;
a0120420
BZ
1099 sysrootdirlen = strlen(sysrootdir);
1100 break;
794b2d2c 1101 case 'p':
9bc5282e 1102 if (regcomp(&mod_filter_path, optarg, REG_NOSUB | REG_EXTENDED) != 0) {
794b2d2c
HH
1103 log_error("Module path filter %s is not a regular expression", optarg);
1104 exit(EXIT_FAILURE);
1105 }
1106 arg_mod_filter_path = true;
1107 break;
1108 case 'P':
9bc5282e 1109 if (regcomp(&mod_filter_nopath, optarg, REG_NOSUB | REG_EXTENDED) != 0) {
794b2d2c
HH
1110 log_error("Module path filter %s is not a regular expression", optarg);
1111 exit(EXIT_FAILURE);
1112 }
1113 arg_mod_filter_nopath = true;
1114 break;
1115 case 's':
9bc5282e 1116 if (regcomp(&mod_filter_symbol, optarg, REG_NOSUB | REG_EXTENDED) != 0) {
794b2d2c
HH
1117 log_error("Module symbol filter %s is not a regular expression", optarg);
1118 exit(EXIT_FAILURE);
1119 }
1120 arg_mod_filter_symbol = true;
1121 break;
1122 case 'S':
9bc5282e 1123 if (regcomp(&mod_filter_nosymbol, optarg, REG_NOSUB | REG_EXTENDED) != 0) {
794b2d2c
HH
1124 log_error("Module symbol filter %s is not a regular expression", optarg);
1125 exit(EXIT_FAILURE);
1126 }
1127 arg_mod_filter_nosymbol = true;
1128 break;
1129 case 'N':
9bc5282e 1130 if (regcomp(&mod_filter_noname, optarg, REG_NOSUB | REG_EXTENDED) != 0) {
794b2d2c
HH
1131 log_error("Module symbol filter %s is not a regular expression", optarg);
1132 exit(EXIT_FAILURE);
1133 }
1134 arg_mod_filter_noname = true;
1135 break;
37383f71 1136 case 'L':
efd4ca27 1137 logdir = optarg;
37383f71 1138 break;
794b2d2c 1139 case ARG_KERNELDIR:
efd4ca27 1140 kerneldir = optarg;
794b2d2c
HH
1141 break;
1142 case ARG_FIRMWAREDIRS:
1143 firmwaredirs = strv_split(optarg, ":");
1144 break;
26cd262a 1145 case 'f':
026b81e9
HH
1146 arg_hmac = true;
1147 break;
26cd262a
HH
1148 case 'H':
1149 arg_hostonly = true;
1150 break;
026b81e9
HH
1151 case 'h':
1152 usage(EXIT_SUCCESS);
1153 break;
1154 default:
1155 usage(EXIT_FAILURE);
1156 }
1157 }
1158
5eb24aa2
MM
1159 if (arg_loglevel >= 0) {
1160 log_set_max_level(arg_loglevel);
1161 }
1162
95aeed89 1163 struct utsname buf = {0};
3ad12c7b 1164 if (!kerneldir) {
3ad12c7b 1165 uname(&buf);
95aeed89 1166 _asprintf(&kerneldir, "/lib/modules/%s", buf.release);
3ad12c7b
HH
1167 }
1168
1169 if (arg_modalias) {
1170 return 1;
1171 }
1172
794b2d2c
HH
1173 if (arg_module) {
1174 if (!firmwaredirs) {
95aeed89 1175 char *path = getenv("DRACUT_FIRMWARE_PATH");
794b2d2c 1176
4cb086fa
MM
1177 if (path) {
1178 log_debug("DRACUT_FIRMWARE_PATH=%s", path);
1179 firmwaredirs = strv_split(path, ":");
1180 } else {
95aeed89 1181 if (!*buf.release)
1182 uname(&buf);
1183
1184 char fw_path_para[PATH_MAX + 1] = "";
1185 int path = open("/sys/module/firmware_class/parameters/path", O_RDONLY | O_CLOEXEC);
1186 if (path != -1) {
1187 ssize_t rd = read(path, fw_path_para, PATH_MAX);
1188 if (rd != -1)
1189 fw_path_para[rd - 1] = '\0';
1190 close(path);
1191 }
1192 char uk[22 + sizeof(buf.release)], fk[14 + sizeof(buf.release)];
1193 sprintf(uk, "/lib/firmware/updates/%s", buf.release);
1194 sprintf(fk, "/lib/firmware/%s", buf.release);
1195 firmwaredirs = strv_new(STRV_IFNOTNULL(*fw_path_para ? fw_path_para : NULL),
1196 uk,
1197 "/lib/firmware/updates",
1198 fk,
1199 "/lib/firmware",
1200 NULL);
794b2d2c 1201 }
794b2d2c
HH
1202 }
1203 }
3ad12c7b 1204
026b81e9 1205 if (!optind || optind == argc) {
bd1a5ca9
PV
1206 if (!arg_optional) {
1207 log_error("No SOURCE argument given");
1208 usage(EXIT_FAILURE);
1209 } else {
1210 exit(EXIT_SUCCESS);
1211 }
026b81e9
HH
1212 }
1213
1214 return 1;
1215}
1216
1217static int resolve_lazy(int argc, char **argv)
1218{
1219 int i;
599182b1 1220 size_t destrootdirlen = strlen(destrootdir);
026b81e9
HH
1221 int ret = 0;
1222 char *item;
1223 for (i = 0; i < argc; i++) {
1224 const char *src = argv[i];
1225 char *p = argv[i];
026b81e9
HH
1226
1227 log_debug("resolve_deps('%s')", src);
1228
1229 if (strstr(src, destrootdir)) {
1230 p = &argv[i][destrootdirlen];
1231 }
1232
96f3177c
DD
1233 if (check_hashmap(items, p)) {
1234 continue;
026b81e9
HH
1235 }
1236
1237 item = strdup(p);
1238 hashmap_put(items, item, item);
1239
1240 ret += resolve_deps(src);
1241 }
1242 return ret;
1243}
1244
2f461da2 1245static char **find_binary(const char *src)
868eba13 1246{
2f461da2
HH
1247 char **ret = NULL;
1248 char **q;
868eba13 1249 char *newsrc = NULL;
d9eff33c 1250
794b2d2c 1251 STRV_FOREACH(q, pathdirs) {
b0bf8187 1252 char *fullsrcpath;
868eba13 1253
e2a61595 1254 _asprintf(&newsrc, "%s/%s", *q, src);
3ed08d1e 1255
a0120420 1256 fullsrcpath = get_real_file(newsrc, false);
a0120420
BZ
1257 if (!fullsrcpath) {
1258 log_debug("get_real_file(%s) not found", newsrc);
1259 free(newsrc);
1260 newsrc = NULL;
1261 continue;
1262 }
1263
e7ed8337 1264 if (faccessat(AT_FDCWD, fullsrcpath, F_OK, AT_SYMLINK_NOFOLLOW) != 0) {
1265 log_debug("lstat(%s) != 0", fullsrcpath);
868eba13
HH
1266 free(newsrc);
1267 newsrc = NULL;
a0120420
BZ
1268 free(fullsrcpath);
1269 fullsrcpath = NULL;
868eba13
HH
1270 continue;
1271 }
1272
2f461da2 1273 strv_push(&ret, newsrc);
868eba13 1274
a0120420
BZ
1275 free(fullsrcpath);
1276 fullsrcpath = NULL;
2f461da2 1277 };
868eba13 1278
2f461da2
HH
1279 if (ret) {
1280 STRV_FOREACH(q, ret) {
1281 log_debug("find_binary(%s) == %s", src, *q);
1282 }
1283 }
3ed08d1e 1284
2f461da2 1285 return ret;
868eba13
HH
1286}
1287
1288static int install_one(const char *src, const char *dst)
1289{
8974102f 1290 int r = EXIT_SUCCESS;
2f461da2 1291 int ret = 0;
868eba13
HH
1292
1293 if (strchr(src, '/') == NULL) {
2f461da2
HH
1294 char **p = find_binary(src);
1295 if (p) {
731b37e9 1296 char **q = NULL;
2f461da2
HH
1297 STRV_FOREACH(q, p) {
1298 char *newsrc = *q;
1299 log_debug("dracut_install '%s' '%s'", newsrc, dst);
1300 ret = dracut_install(newsrc, dst, arg_createdir, arg_resolvedeps, true);
1301 if (ret == 0) {
1302 log_debug("dracut_install '%s' '%s' OK", newsrc, dst);
1303 }
868eba13 1304 }
2f461da2 1305 strv_free(p);
868eba13
HH
1306 } else {
1307 ret = -1;
1308 }
1309 } else {
1310 ret = dracut_install(src, dst, arg_createdir, arg_resolvedeps, true);
1311 }
1312
1313 if ((ret != 0) && (!arg_optional)) {
1314 log_error("ERROR: installing '%s' to '%s'", src, dst);
1315 r = EXIT_FAILURE;
1316 }
1317
1318 return r;
1319}
1320
026b81e9
HH
1321static int install_all(int argc, char **argv)
1322{
8974102f 1323 int r = EXIT_SUCCESS;
026b81e9
HH
1324 int i;
1325 for (i = 0; i < argc; i++) {
2f461da2 1326 int ret = 0;
026b81e9
HH
1327 log_debug("Handle '%s'", argv[i]);
1328
1329 if (strchr(argv[i], '/') == NULL) {
2f461da2
HH
1330 char **p = find_binary(argv[i]);
1331 if (p) {
731b37e9 1332 char **q = NULL;
2f461da2
HH
1333 STRV_FOREACH(q, p) {
1334 char *newsrc = *q;
1335 log_debug("dracut_install '%s'", newsrc);
1336 ret = dracut_install(newsrc, newsrc, arg_createdir, arg_resolvedeps, true);
1337 if (ret == 0) {
1338 log_debug("dracut_install '%s' OK", newsrc);
1339 }
026b81e9 1340 }
2f461da2 1341 strv_free(p);
868eba13
HH
1342 } else {
1343 ret = -1;
1344 }
1345
026b81e9 1346 } else {
ddcdee91 1347 if (strchr(argv[i], '*') == NULL) {
a20556f0 1348 ret = dracut_install(argv[i], argv[i], arg_createdir, arg_resolvedeps, true);
ddcdee91
ZB
1349 } else {
1350 _cleanup_free_ char *realsrc = NULL;
1351 _cleanup_globfree_ glob_t globbuf;
1352
e2a61595 1353 _asprintf(&realsrc, "%s%s", sysrootdir ? sysrootdir : "", argv[i]);
ddcdee91
ZB
1354
1355 ret = glob(realsrc, 0, NULL, &globbuf);
1356 if (ret == 0) {
55468a2d 1357 size_t j;
ddcdee91
ZB
1358
1359 for (j = 0; j < globbuf.gl_pathc; j++) {
a20556f0 1360 ret |= dracut_install(globbuf.gl_pathv[j] + sysrootdirlen,
1361 globbuf.gl_pathv[j] + sysrootdirlen,
1362 arg_createdir, arg_resolvedeps, true);
ddcdee91
ZB
1363 }
1364 }
1365 }
026b81e9
HH
1366 }
1367
85854b24 1368 if ((ret != 0) && (!arg_optional)) {
026b81e9
HH
1369 log_error("ERROR: installing '%s'", argv[i]);
1370 r = EXIT_FAILURE;
1371 }
1372 }
1373 return r;
1374}
1375
1a5845b4 1376static int install_firmware_fullpath(const char *fwpath)
794b2d2c 1377{
9d8387ed 1378 const char *fw = fwpath;
1379 _cleanup_free_ char *fwpath_compressed = NULL;
b0bf8187 1380 int ret;
e7ed8337 1381 if (access(fwpath, F_OK) != 0) {
9d8387ed 1382 _asprintf(&fwpath_compressed, "%s.zst", fwpath);
1383 if (access(fwpath_compressed, F_OK) != 0) {
1384 strcpy(fwpath_compressed + strlen(fwpath) + 1, "xz");
1385 if (access(fwpath_compressed, F_OK) != 0) {
1386 log_debug("stat(%s) != 0", fwpath);
1387 return 1;
1388 }
1a5845b4 1389 }
9d8387ed 1390 fw = fwpath_compressed;
1a5845b4
DM
1391 }
1392 ret = dracut_install(fw, fw, false, false, true);
1393 if (ret == 0) {
1394 log_debug("dracut_install '%s' OK", fwpath);
1395 }
1396 return ret;
1397}
1398
9bc5282e
HH
1399static int install_firmware(struct kmod_module *mod)
1400{
b0bf8187 1401 struct kmod_list *l = NULL;
eab32bda 1402 _cleanup_kmod_module_info_free_list_ struct kmod_list *list = NULL;
794b2d2c 1403 int ret;
794b2d2c
HH
1404 char **q;
1405
1406 ret = kmod_module_get_info(mod, &list);
1407 if (ret < 0) {
9bc5282e 1408 log_error("could not get modinfo from '%s': %s\n", kmod_module_get_name(mod), strerror(-ret));
794b2d2c
HH
1409 return ret;
1410 }
1411 kmod_list_foreach(l, list) {
1412 const char *key = kmod_module_info_get_key(l);
1413 const char *value = NULL;
16855765 1414 bool found_this = false;
794b2d2c
HH
1415
1416 if (!streq("firmware", key))
1417 continue;
1418
1419 value = kmod_module_info_get_value(l);
1420 log_debug("Firmware %s", value);
1421 ret = -1;
1422 STRV_FOREACH(q, firmwaredirs) {
eab32bda 1423 _cleanup_free_ char *fwpath = NULL;
794b2d2c 1424
e2a61595 1425 _asprintf(&fwpath, "%s/%s", *q, value);
794b2d2c 1426
751a110f 1427 if (strpbrk(value, "*?[") != NULL
e7ed8337 1428 && access(fwpath, F_OK) != 0) {
55468a2d 1429 size_t i;
1a5845b4 1430 _cleanup_globfree_ glob_t globbuf;
55468a2d 1431
1a5845b4
DM
1432 glob(fwpath, 0, NULL, &globbuf);
1433 for (i = 0; i < globbuf.gl_pathc; i++) {
6a444261 1434 ret = install_firmware_fullpath(globbuf.gl_pathv[i]);
16855765
DD
1435 if (ret == 0)
1436 found_this = true;
999cfa84 1437 }
1a5845b4 1438 } else {
6a444261 1439 ret = install_firmware_fullpath(fwpath);
16855765
DD
1440 if (ret == 0)
1441 found_this = true;
794b2d2c 1442 }
794b2d2c 1443 }
16855765
DD
1444 if (!found_this) {
1445 /* firmware path was not found in any firmwaredirs */
1446 log_info("Missing firmware %s for kernel module %s",
1447 value, kmod_module_get_name(mod));
1448 }
794b2d2c
HH
1449 }
1450 return 0;
1451}
1452
1453static bool check_module_symbols(struct kmod_module *mod)
1454{
b0bf8187 1455 struct kmod_list *itr = NULL;
eab32bda 1456 _cleanup_kmod_module_dependency_symbols_free_list_ struct kmod_list *deplist = NULL;
794b2d2c
HH
1457
1458 if (!arg_mod_filter_symbol && !arg_mod_filter_nosymbol)
1459 return true;
1460
1461 if (kmod_module_get_dependency_symbols(mod, &deplist) < 0) {
1462 log_debug("kmod_module_get_dependency_symbols failed");
1463 if (arg_mod_filter_symbol)
1464 return false;
1465 return true;
1466 }
1467
1468 if (arg_mod_filter_nosymbol) {
1469 kmod_list_foreach(itr, deplist) {
1470 const char *symbol = kmod_module_symbol_get_symbol(itr);
1471 // log_debug("Checking symbol %s", symbol);
1472 if (regexec(&mod_filter_nosymbol, symbol, 0, NULL, 0) == 0) {
9bc5282e
HH
1473 log_debug("Module %s: symbol %s matched exclusion filter", kmod_module_get_name(mod),
1474 symbol);
794b2d2c
HH
1475 return false;
1476 }
1477 }
1478 }
1479
1480 if (arg_mod_filter_symbol) {
1481 kmod_list_foreach(itr, deplist) {
1482 const char *symbol = kmod_module_dependency_symbol_get_symbol(itr);
1483 // log_debug("Checking symbol %s", symbol);
1484 if (regexec(&mod_filter_symbol, symbol, 0, NULL, 0) == 0) {
9bc5282e
HH
1485 log_debug("Module %s: symbol %s matched inclusion filter", kmod_module_get_name(mod),
1486 symbol);
794b2d2c
HH
1487 return true;
1488 }
1489 }
794b2d2c
HH
1490 return false;
1491 }
1492
794b2d2c
HH
1493 return true;
1494}
1495
794b2d2c
HH
1496static bool check_module_path(const char *path)
1497{
1498 if (arg_mod_filter_nopath && (regexec(&mod_filter_nopath, path, 0, NULL, 0) == 0)) {
1499 log_debug("Path %s matched exclusion filter", path);
1500 return false;
1501 }
1502
1503 if (arg_mod_filter_path && (regexec(&mod_filter_path, path, 0, NULL, 0) != 0)) {
1504 log_debug("Path %s matched inclusion filter", path);
1505 return false;
1506 }
1507 return true;
1508}
1509
3de4c731
AT
1510static int find_kmod_module_from_sysfs_node(struct kmod_ctx *ctx, const char *sysfs_node, int sysfs_node_len,
1511 struct kmod_list **modules)
1512{
1513 char modalias_path[PATH_MAX];
1514 if (snprintf(modalias_path, sizeof(modalias_path), "%.*s/modalias", sysfs_node_len,
1515 sysfs_node) >= sizeof(modalias_path))
1516 return -1;
1517
1518 _cleanup_close_ int modalias_file = -1;
1519 if ((modalias_file = open(modalias_path, O_RDONLY | O_CLOEXEC)) == -1)
1520 return 0;
1521
1522 char alias[page_size()];
1523 ssize_t len = read(modalias_file, alias, sizeof(alias));
1524 alias[len - 1] = '\0';
1525
1526 return kmod_module_new_from_lookup(ctx, alias, modules);
1527}
1528
1529static int find_modules_from_sysfs_node(struct kmod_ctx *ctx, const char *sysfs_node, Hashmap *modules)
1530{
1531 _cleanup_kmod_module_unref_list_ struct kmod_list *list = NULL;
1532 struct kmod_list *l = NULL;
1533
1534 if (find_kmod_module_from_sysfs_node(ctx, sysfs_node, strlen(sysfs_node), &list) >= 0) {
1535 kmod_list_foreach(l, list) {
1536 struct kmod_module *mod = kmod_module_get_module(l);
1537 char *module = strdup(kmod_module_get_name(mod));
1538 kmod_module_unref(mod);
1539
1540 if (hashmap_put(modules, module, module) < 0)
1541 free(module);
1542 }
1543 }
1544
1545 return 0;
1546}
1547
1548static void find_suppliers_for_sys_node(struct kmod_ctx *ctx, Hashmap *suppliers, const char *node_path_raw,
1549 size_t node_path_len)
1550{
1551 char node_path[PATH_MAX];
1552 char real_path[PATH_MAX];
1553
1554 memcpy(node_path, node_path_raw, node_path_len);
1555 node_path[node_path_len] = '\0';
1556
1557 DIR *d;
1558 struct dirent *dir;
1559 while (realpath(node_path, real_path) != NULL && strcmp(real_path, "/sys/devices")) {
1560 d = opendir(node_path);
1561 if (d) {
1562 size_t real_path_len = strlen(real_path);
1563 while ((dir = readdir(d)) != NULL) {
1564 if (strstr(dir->d_name, "supplier:platform") != NULL) {
1565 if (snprintf(real_path + real_path_len, sizeof(real_path) - real_path_len, "/%s/supplier",
1566 dir->d_name) < sizeof(real_path) - real_path_len) {
1567 char *real_supplier_path = realpath(real_path, NULL);
1568 if (real_supplier_path != NULL)
1569 if (hashmap_put(suppliers, real_supplier_path, real_supplier_path) < 0)
1570 free(real_supplier_path);
1571 }
1572 }
1573 }
1574 closedir(d);
1575 }
1576 strncat(node_path, "/..", 3); // Also find suppliers of parents
1577 }
1578}
1579
1580static void find_suppliers(struct kmod_ctx *ctx)
1581{
1582 _cleanup_fts_close_ FTS *fts;
1583 char *paths[] = { "/sys/devices/platform", NULL };
1584 fts = fts_open(paths, FTS_NOSTAT | FTS_PHYSICAL, NULL);
1585
1586 for (FTSENT *ftsent = fts_read(fts); ftsent != NULL; ftsent = fts_read(fts)) {
1587 if (strcmp(ftsent->fts_name, "modalias") == 0) {
1588 _cleanup_kmod_module_unref_list_ struct kmod_list *list = NULL;
1589 struct kmod_list *l;
1590
1591 if (find_kmod_module_from_sysfs_node(ctx, ftsent->fts_parent->fts_path, ftsent->fts_parent->fts_pathlen, &list) < 0)
1592 continue;
1593
1594 kmod_list_foreach(l, list) {
1595 _cleanup_kmod_module_unref_ struct kmod_module *mod = kmod_module_get_module(l);
1596 const char *name = kmod_module_get_name(mod);
1597 Hashmap *suppliers = hashmap_get(modules_suppliers, name);
1598 if (suppliers == NULL) {
1599 suppliers = hashmap_new(string_hash_func, string_compare_func);
1600 hashmap_put(modules_suppliers, strdup(name), suppliers);
1601 }
1602
1603 find_suppliers_for_sys_node(ctx, suppliers, ftsent->fts_parent->fts_path, ftsent->fts_parent->fts_pathlen);
1604 }
1605 }
1606 }
1607}
1608
1609static Hashmap *find_suppliers_paths_for_module(const char *module)
1610{
1611 return hashmap_get(modules_suppliers, module);
1612}
1613
1614static int install_dependent_module(struct kmod_ctx *ctx, struct kmod_module *mod, Hashmap *suppliers_paths, int *err)
4cdee66c 1615{
4cdee66c
JL
1616 const char *path = NULL;
1617 const char *name = NULL;
4cdee66c 1618
8ea8cf5f 1619 path = kmod_module_get_path(mod);
4cdee66c 1620
8ea8cf5f
AT
1621 if (path == NULL)
1622 return 0;
fc141f22 1623
8ea8cf5f
AT
1624 if (check_hashmap(items_failed, path))
1625 return -1;
c38f9e98 1626
8ea8cf5f
AT
1627 if (check_hashmap(items, &path[kerneldirlen])) {
1628 return 0;
1629 }
c38f9e98 1630
8ea8cf5f 1631 name = kmod_module_get_name(mod);
c38f9e98 1632
8ea8cf5f
AT
1633 if (arg_mod_filter_noname && (regexec(&mod_filter_noname, name, 0, NULL, 0) == 0)) {
1634 return 0;
1635 }
c38f9e98 1636
8ea8cf5f
AT
1637 *err = dracut_install(path, &path[kerneldirlen], false, false, true);
1638 if (*err == 0) {
1639 _cleanup_kmod_module_unref_list_ struct kmod_list *modlist = NULL;
1640 _cleanup_kmod_module_unref_list_ struct kmod_list *modpre = NULL;
1641 _cleanup_kmod_module_unref_list_ struct kmod_list *modpost = NULL;
1642 log_debug("dracut_install '%s' '%s' OK", path, &path[kerneldirlen]);
1643 install_firmware(mod);
1644 modlist = kmod_module_get_dependencies(mod);
3de4c731 1645 *err = install_dependent_modules(ctx, modlist, suppliers_paths);
8ea8cf5f
AT
1646 if (*err == 0) {
1647 *err = kmod_module_get_softdeps(mod, &modpre, &modpost);
1648 if (*err == 0) {
1649 int r;
3de4c731
AT
1650 *err = install_dependent_modules(ctx, modpre, NULL);
1651 r = install_dependent_modules(ctx, modpost, NULL);
8ea8cf5f 1652 *err = *err ? : r;
6dafdda4 1653 }
4cdee66c 1654 }
8ea8cf5f
AT
1655 } else {
1656 log_error("dracut_install '%s' '%s' ERROR", path, &path[kerneldirlen]);
1657 }
1658
1659 return 0;
1660}
1661
3de4c731 1662static int install_dependent_modules(struct kmod_ctx *ctx, struct kmod_list *modlist, Hashmap *suppliers_paths)
8ea8cf5f
AT
1663{
1664 struct kmod_list *itr = NULL;
1665 int ret = 0;
1666
1667 kmod_list_foreach(itr, modlist) {
1668 _cleanup_kmod_module_unref_ struct kmod_module *mod = NULL;
1669 mod = kmod_module_get_module(itr);
3de4c731 1670 if (install_dependent_module(ctx, mod, find_suppliers_paths_for_module(kmod_module_get_name(mod)), &ret))
8ea8cf5f 1671 return -1;
4cdee66c
JL
1672 }
1673
3de4c731
AT
1674 const char *supplier_path;
1675 Iterator i;
1676 HASHMAP_FOREACH(supplier_path, suppliers_paths, i) {
131822e2
AT
1677 if (check_hashmap(processed_suppliers, supplier_path))
1678 continue;
1679
1680 char *path = strdup(supplier_path);
1681 hashmap_put(processed_suppliers, path, path);
1682
3de4c731
AT
1683 _cleanup_destroy_hashmap_ Hashmap *modules = hashmap_new(string_hash_func, string_compare_func);
1684 find_modules_from_sysfs_node(ctx, supplier_path, modules);
1685
1686 _cleanup_destroy_hashmap_ Hashmap *suppliers = hashmap_new(string_hash_func, string_compare_func);
1687 find_suppliers_for_sys_node(ctx, suppliers, supplier_path, strlen(supplier_path));
1688
1689 if (!hashmap_isempty(modules)) { // Supplier is a module
1690 const char *module;
1691 Iterator j;
1692 HASHMAP_FOREACH(module, modules, j) {
1693 _cleanup_kmod_module_unref_ struct kmod_module *mod = NULL;
1694 if (!kmod_module_new_from_name(ctx, module, &mod)) {
1695 if (install_dependent_module(ctx, mod, suppliers, &ret))
1696 return -1;
1697 }
1698 }
1699 } else { // Supplier is builtin
1700 install_dependent_modules(ctx, NULL, suppliers);
1701 }
1702 }
1703
4cdee66c
JL
1704 return ret;
1705}
1706
3de4c731 1707static int install_module(struct kmod_ctx *ctx, struct kmod_module *mod)
794b2d2c
HH
1708{
1709 int ret = 0;
eab32bda 1710 _cleanup_kmod_module_unref_list_ struct kmod_list *modlist = NULL;
4cdee66c
JL
1711 _cleanup_kmod_module_unref_list_ struct kmod_list *modpre = NULL;
1712 _cleanup_kmod_module_unref_list_ struct kmod_list *modpost = NULL;
794b2d2c
HH
1713 const char *path = NULL;
1714 const char *name = NULL;
794b2d2c
HH
1715
1716 name = kmod_module_get_name(mod);
2536a9ea
HH
1717
1718 path = kmod_module_get_path(mod);
1719 if (!path) {
1720 log_debug("dracut_install '%s' is a builtin kernel module", name);
1721 return 0;
1722 }
1723
fe6e0c23
HH
1724 if (arg_mod_filter_noname && (regexec(&mod_filter_noname, name, 0, NULL, 0) == 0)) {
1725 log_debug("dracut_install '%s' is excluded", name);
794b2d2c 1726 return 0;
fe6e0c23 1727 }
794b2d2c 1728
2b909b9a 1729 if (arg_hostonly && !check_hashmap(modules_loaded, name)) {
794b2d2c
HH
1730 log_debug("dracut_install '%s' not hostonly", name);
1731 return 0;
1732 }
1733
794b2d2c 1734 if (check_hashmap(items_failed, path))
fe6e0c23 1735 return -1;
794b2d2c
HH
1736
1737 if (check_hashmap(items, path))
1738 return 0;
1739
1740 if (!check_module_path(path) || !check_module_symbols(mod)) {
ed25fb0e 1741 log_debug("No symbol or path match for '%s'", path);
fe6e0c23 1742 return 1;
794b2d2c
HH
1743 }
1744
1bef2934 1745 log_debug("dracut_install '%s' '%s'", path, &path[kerneldirlen]);
be5025bf 1746
1bef2934 1747 ret = dracut_install(path, &path[kerneldirlen], false, false, true);
794b2d2c
HH
1748 if (ret == 0) {
1749 log_debug("dracut_install '%s' OK", kmod_module_get_name(mod));
1750 } else if (!arg_optional) {
1751 if (!arg_silent)
1752 log_error("dracut_install '%s' ERROR", kmod_module_get_name(mod));
1753 return ret;
1754 }
1755 install_firmware(mod);
1756
3de4c731 1757 Hashmap *suppliers = find_suppliers_paths_for_module(name);
794b2d2c 1758 modlist = kmod_module_get_dependencies(mod);
3de4c731 1759 ret = install_dependent_modules(ctx, modlist, suppliers);
be5025bf 1760
4cdee66c
JL
1761 if (ret == 0) {
1762 ret = kmod_module_get_softdeps(mod, &modpre, &modpost);
9bc5282e 1763 if (ret == 0) {
6dafdda4 1764 int r;
3de4c731
AT
1765 ret = install_dependent_modules(ctx, modpre, NULL);
1766 r = install_dependent_modules(ctx, modpost, NULL);
6dafdda4
LN
1767 ret = ret ? : r;
1768 }
794b2d2c 1769 }
794b2d2c
HH
1770
1771 return ret;
1772}
1773
3ad12c7b 1774static int modalias_list(struct kmod_ctx *ctx)
794b2d2c 1775{
3ad12c7b 1776 int err;
eab32bda 1777 struct kmod_list *loaded_list = NULL;
b0bf8187
SS
1778 struct kmod_list *l = NULL;
1779 struct kmod_list *itr = NULL;
3ad12c7b
HH
1780 _cleanup_fts_close_ FTS *fts = NULL;
1781
1782 {
1783 char *paths[] = { "/sys/devices", NULL };
9bc5282e 1784 fts = fts_open(paths, FTS_NOCHDIR | FTS_NOSTAT, NULL);
3ad12c7b 1785 }
f1ed92c3 1786 for (FTSENT *ftsent = fts_read(fts); ftsent != NULL; ftsent = fts_read(fts)) {
3ad12c7b
HH
1787 _cleanup_fclose_ FILE *f = NULL;
1788 _cleanup_kmod_module_unref_list_ struct kmod_list *list = NULL;
3ad12c7b
HH
1789
1790 int err;
1791
b0bf8187 1792 char alias[2048] = {0};
3ad12c7b
HH
1793 size_t len;
1794
1795 if (strncmp("modalias", ftsent->fts_name, 8) != 0)
1796 continue;
1797 if (!(f = fopen(ftsent->fts_accpath, "r")))
1798 continue;
1799
9bc5282e 1800 if (!fgets(alias, sizeof(alias), f))
3ad12c7b
HH
1801 continue;
1802
1803 len = strlen(alias);
1804
1805 if (len == 0)
1806 continue;
1807
9bc5282e
HH
1808 if (alias[len - 1] == '\n')
1809 alias[len - 1] = 0;
3ad12c7b
HH
1810
1811 err = kmod_module_new_from_lookup(ctx, alias, &list);
1812 if (err < 0)
1813 continue;
1814
1815 kmod_list_foreach(l, list) {
1816 struct kmod_module *mod = kmod_module_get_module(l);
1817 char *name = strdup(kmod_module_get_name(mod));
1818 kmod_module_unref(mod);
1819 hashmap_put(modules_loaded, name, name);
1820 }
1821 }
1822
1823 err = kmod_module_new_from_loaded(ctx, &loaded_list);
1824 if (err < 0) {
1825 errno = err;
1826 log_error("Could not get list of loaded modules: %m. Switching to non-hostonly mode.");
1827 arg_hostonly = false;
1828 } else {
1829 kmod_list_foreach(itr, loaded_list) {
1830 _cleanup_kmod_module_unref_list_ struct kmod_list *modlist = NULL;
1831
1832 struct kmod_module *mod = kmod_module_get_module(itr);
1833 char *name = strdup(kmod_module_get_name(mod));
1834 hashmap_put(modules_loaded, name, name);
1835 kmod_module_unref(mod);
1836
1837 /* also put the modules from the new kernel in the hashmap,
1838 * which resolve the name as an alias, in case a kernel module is
1839 * renamed.
1840 */
1841 err = kmod_module_new_from_lookup(ctx, name, &modlist);
1842 if (err < 0)
1843 continue;
1844 if (!modlist)
1845 continue;
1846 kmod_list_foreach(l, modlist) {
1847 mod = kmod_module_get_module(l);
1848 char *name = strdup(kmod_module_get_name(mod));
1849 hashmap_put(modules_loaded, name, name);
1850 kmod_module_unref(mod);
1851 }
1852 }
1853 kmod_module_unref_list(loaded_list);
1854 }
1855 return 0;
1856}
1857
1858static int install_modules(int argc, char **argv)
1859{
1860 _cleanup_kmod_unref_ struct kmod_ctx *ctx = NULL;
b0bf8187 1861 struct kmod_list *itr = NULL;
eab32bda 1862
794b2d2c
HH
1863 struct kmod_module *mod = NULL, *mod_o = NULL;
1864
2c9bcac1 1865 const char *abskpath = NULL;
ef84ce25 1866 char *p;
794b2d2c 1867 int i;
8ad32155 1868 int modinst = 0;
794b2d2c
HH
1869
1870 ctx = kmod_new(kerneldir, NULL);
ef84ce25
AS
1871 abskpath = kmod_get_dirname(ctx);
1872
1873 p = strstr(abskpath, "/lib/modules/");
1874 if (p != NULL)
1875 kerneldirlen = p - abskpath;
1876
3de4c731
AT
1877 modules_suppliers = hashmap_new(string_hash_func, string_compare_func);
1878 find_suppliers(ctx);
1879
bb47ec54 1880 if (arg_hostonly) {
3ad12c7b
HH
1881 char *modalias_file;
1882 modalias_file = getenv("DRACUT_KERNEL_MODALIASES");
1883
1884 if (modalias_file == NULL) {
1885 modalias_list(ctx);
bb47ec54 1886 } else {
3ad12c7b
HH
1887 _cleanup_fclose_ FILE *f = NULL;
1888 if ((f = fopen(modalias_file, "r"))) {
1889 char name[2048];
bb47ec54 1890
3ad12c7b
HH
1891 while (!feof(f)) {
1892 size_t len;
2b909b9a 1893 char *dupname = NULL;
bb47ec54 1894
9bc5282e 1895 if (!(fgets(name, sizeof(name), f)))
3ad12c7b
HH
1896 continue;
1897 len = strlen(name);
1898
1899 if (len == 0)
1900 continue;
1901
9bc5282e
HH
1902 if (name[len - 1] == '\n')
1903 name[len - 1] = 0;
3ad12c7b 1904
2b909b9a
HH
1905 log_debug("Adding module '%s' to hostonly module list", name);
1906 dupname = strdup(name);
1907 hashmap_put(modules_loaded, dupname, dupname);
bb47ec54
HH
1908 }
1909 }
eab32bda 1910 }
3ad12c7b 1911
eab32bda 1912 }
eab32bda 1913
794b2d2c
HH
1914 for (i = 0; i < argc; i++) {
1915 int r = 0;
fe6e0c23 1916 int ret = -1;
794b2d2c
HH
1917 log_debug("Handle module '%s'", argv[i]);
1918
1919 if (argv[i][0] == '/') {
eab32bda 1920 _cleanup_kmod_module_unref_list_ struct kmod_list *modlist = NULL;
731b37e9 1921 _cleanup_free_ const char *modname = NULL;
eab32bda 1922
794b2d2c
HH
1923 r = kmod_module_new_from_path(ctx, argv[i], &mod_o);
1924 if (r < 0) {
1925 log_debug("Failed to lookup modules path '%s': %m", argv[i]);
1926 if (!arg_optional)
1927 return -ENOENT;
1928 continue;
1929 }
1930 /* Check, if we have to load another module with that name instead */
6c7776e3 1931 modname = strdup(kmod_module_get_name(mod_o));
eab32bda 1932
794b2d2c
HH
1933 if (!modname) {
1934 if (!arg_optional) {
1935 if (!arg_silent)
1936 log_error("Failed to get name for module '%s'", argv[i]);
1937 return -ENOENT;
1938 }
1939 log_info("Failed to get name for module '%s'", argv[i]);
1940 continue;
1941 }
eab32bda 1942
794b2d2c
HH
1943 r = kmod_module_new_from_lookup(ctx, modname, &modlist);
1944 kmod_module_unref(mod_o);
eab32bda
HH
1945 mod_o = NULL;
1946
794b2d2c
HH
1947 if (r < 0) {
1948 if (!arg_optional) {
1949 if (!arg_silent)
1950 log_error("3 Failed to lookup alias '%s': %d", modname, r);
1951 return -ENOENT;
1952 }
1953 log_info("3 Failed to lookup alias '%s': %d", modname, r);
1954 continue;
1955 }
1956 if (!modlist) {
1957 if (!arg_optional) {
1958 if (!arg_silent)
1959 log_error("Failed to find module '%s' %s", modname, argv[i]);
1960 return -ENOENT;
1961 }
1962 log_info("Failed to find module '%s' %s", modname, argv[i]);
1963 continue;
1964 }
1965 kmod_list_foreach(itr, modlist) {
1966 mod = kmod_module_get_module(itr);
3de4c731 1967 r = install_module(ctx, mod);
fe6e0c23
HH
1968 kmod_module_unref(mod);
1969 if ((r < 0) && !arg_optional) {
1970 if (!arg_silent)
1971 log_error("ERROR: installing module '%s'", modname);
1972 return -ENOENT;
1973 };
9bc5282e 1974 ret = (ret == 0 ? 0 : r);
8ad32155 1975 modinst = 1;
794b2d2c 1976 }
794b2d2c 1977 } else if (argv[i][0] == '=') {
eab32bda
HH
1978 _cleanup_free_ char *path1 = NULL, *path2 = NULL, *path3 = NULL;
1979 _cleanup_fts_close_ FTS *fts = NULL;
1980
794b2d2c 1981 log_debug("Handling =%s", &argv[i][1]);
9bc5282e 1982 /* FIXME and add more paths */
e2a61595
SS
1983 _asprintf(&path2, "%s/kernel/%s", kerneldir, &argv[i][1]);
1984 _asprintf(&path1, "%s/extra/%s", kerneldir, &argv[i][1]);
1985 _asprintf(&path3, "%s/updates/%s", kerneldir, &argv[i][1]);
794b2d2c 1986
eab32bda 1987 {
794b2d2c 1988 char *paths[] = { path1, path2, path3, NULL };
9bc5282e 1989 fts = fts_open(paths, FTS_COMFOLLOW | FTS_NOCHDIR | FTS_NOSTAT | FTS_LOGICAL, NULL);
794b2d2c 1990 }
eab32bda 1991
f1ed92c3 1992 for (FTSENT *ftsent = fts_read(fts); ftsent != NULL; ftsent = fts_read(fts)) {
eab32bda 1993 _cleanup_kmod_module_unref_list_ struct kmod_list *modlist = NULL;
731b37e9 1994 _cleanup_free_ const char *modname = NULL;
eab32bda 1995
9bc5282e 1996 if ((ftsent->fts_info == FTS_D) && !check_module_path(ftsent->fts_accpath)) {
794b2d2c
HH
1997 fts_set(fts, ftsent, FTS_SKIP);
1998 log_debug("Skipping %s", ftsent->fts_accpath);
1999 continue;
2000 }
9bc5282e 2001 if ((ftsent->fts_info != FTS_F) && (ftsent->fts_info != FTS_SL)) {
794b2d2c
HH
2002 log_debug("Ignoring %s", ftsent->fts_accpath);
2003 continue;
2004 }
2005 log_debug("Handling %s", ftsent->fts_accpath);
2006 r = kmod_module_new_from_path(ctx, ftsent->fts_accpath, &mod_o);
2007 if (r < 0) {
9bc5282e 2008 log_debug("Failed to lookup modules path '%s': %m", ftsent->fts_accpath);
fe6e0c23
HH
2009 if (!arg_optional) {
2010 return -ENOENT;
2011 }
794b2d2c
HH
2012 continue;
2013 }
fe6e0c23 2014
794b2d2c 2015 /* Check, if we have to load another module with that name instead */
6c7776e3 2016 modname = strdup(kmod_module_get_name(mod_o));
eab32bda 2017
794b2d2c
HH
2018 if (!modname) {
2019 log_error("Failed to get name for module '%s'", ftsent->fts_accpath);
fe6e0c23
HH
2020 if (!arg_optional) {
2021 return -ENOENT;
2022 }
794b2d2c
HH
2023 continue;
2024 }
2025 r = kmod_module_new_from_lookup(ctx, modname, &modlist);
2026 kmod_module_unref(mod_o);
eab32bda
HH
2027 mod_o = NULL;
2028
794b2d2c 2029 if (r < 0) {
fe6e0c23 2030 log_error("Failed to lookup alias '%s': %m", modname);
fe6e0c23
HH
2031 if (!arg_optional) {
2032 return -ENOENT;
2033 }
794b2d2c
HH
2034 continue;
2035 }
eab32bda 2036
794b2d2c 2037 if (!modlist) {
9bc5282e 2038 log_error("Failed to find module '%s' %s", modname, ftsent->fts_accpath);
fe6e0c23
HH
2039 if (!arg_optional) {
2040 return -ENOENT;
2041 }
794b2d2c
HH
2042 continue;
2043 }
2044 kmod_list_foreach(itr, modlist) {
2045 mod = kmod_module_get_module(itr);
3de4c731 2046 r = install_module(ctx, mod);
794b2d2c 2047 kmod_module_unref(mod);
fe6e0c23
HH
2048 if ((r < 0) && !arg_optional) {
2049 if (!arg_silent)
2050 log_error("ERROR: installing module '%s'", modname);
2051 return -ENOENT;
2052 };
9bc5282e 2053 ret = (ret == 0 ? 0 : r);
8ad32155 2054 modinst = 1;
794b2d2c 2055 }
794b2d2c
HH
2056 }
2057 if (errno) {
2058 log_error("FTS ERROR: %m");
2059 }
794b2d2c 2060 } else {
eab32bda 2061 _cleanup_kmod_module_unref_list_ struct kmod_list *modlist = NULL;
731b37e9 2062 char *modname = argv[i];
eab32bda 2063
794b2d2c
HH
2064 if (endswith(modname, ".ko")) {
2065 int len = strlen(modname);
9bc5282e 2066 modname[len - 3] = 0;
794b2d2c
HH
2067 }
2068 if (endswith(modname, ".ko.xz") || endswith(modname, ".ko.gz")) {
2069 int len = strlen(modname);
9bc5282e 2070 modname[len - 6] = 0;
794b2d2c 2071 }
ce9af251
MN
2072 if (endswith(modname, ".ko.zst")) {
2073 int len = strlen(modname);
2074 modname[len - 7] = 0;
2075 }
794b2d2c
HH
2076 r = kmod_module_new_from_lookup(ctx, modname, &modlist);
2077 if (r < 0) {
2078 if (!arg_optional) {
2079 if (!arg_silent)
2080 log_error("Failed to lookup alias '%s': %m", modname);
2081 return -ENOENT;
2082 }
2083 log_info("Failed to lookup alias '%s': %m", modname);
2084 continue;
2085 }
2086 if (!modlist) {
2087 if (!arg_optional) {
2088 if (!arg_silent)
2089 log_error("Failed to find module '%s'", modname);
2090 return -ENOENT;
2091 }
2092 log_info("Failed to find module '%s'", modname);
2093 continue;
2094 }
2095 kmod_list_foreach(itr, modlist) {
2096 mod = kmod_module_get_module(itr);
3de4c731 2097 r = install_module(ctx, mod);
794b2d2c 2098 kmod_module_unref(mod);
fe6e0c23
HH
2099 if ((r < 0) && !arg_optional) {
2100 if (!arg_silent)
2101 log_error("ERROR: installing '%s'", argv[i]);
2102 return -ENOENT;
2103 };
9bc5282e 2104 ret = (ret == 0 ? 0 : r);
8ad32155 2105 modinst = 1;
794b2d2c 2106 }
794b2d2c
HH
2107 }
2108
8ad32155 2109 if ((modinst != 0) && (ret != 0) && (!arg_optional)) {
794b2d2c
HH
2110 if (!arg_silent)
2111 log_error("ERROR: installing '%s'", argv[i]);
2112 return EXIT_FAILURE;
2113 }
2114 }
fe6e0c23 2115
794b2d2c
HH
2116 return EXIT_SUCCESS;
2117}
2118
026b81e9
HH
2119int main(int argc, char **argv)
2120{
2121 int r;
2122 char *i;
794b2d2c 2123 char *path = NULL;
93be2bc6 2124 char *env_no_xattr = NULL;
026b81e9 2125
026b81e9
HH
2126 log_set_target(LOG_TARGET_CONSOLE);
2127 log_parse_environment();
026b81e9
HH
2128 log_open();
2129
5eb24aa2
MM
2130 r = parse_argv(argc, argv);
2131 if (r <= 0)
2132 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
2133
3ad12c7b
HH
2134 modules_loaded = hashmap_new(string_hash_func, string_compare_func);
2135 if (arg_modalias) {
2136 Iterator i;
2137 char *name;
2138 _cleanup_kmod_unref_ struct kmod_ctx *ctx = NULL;
2139 ctx = kmod_new(kerneldir, NULL);
2140
2141 modalias_list(ctx);
2142 HASHMAP_FOREACH(name, modules_loaded, i) {
2143 printf("%s\n", name);
2144 }
2145 exit(0);
2146 }
2147
a0120420
BZ
2148 log_debug("Program arguments:");
2149 for (r = 0; r < argc; r++)
2150 log_debug("%s", argv[r]);
2151
2152 path = getenv("DRACUT_INSTALL_PATH");
2153 if (path == NULL)
2154 path = getenv("PATH");
794b2d2c
HH
2155
2156 if (path == NULL) {
2157 log_error("PATH is not set");
2158 exit(EXIT_FAILURE);
2159 }
2160
2161 log_debug("PATH=%s", path);
2162
a0120420
BZ
2163 ldd = getenv("DRACUT_LDD");
2164 if (ldd == NULL)
2165 ldd = "ldd";
2166 log_debug("LDD=%s", ldd);
2167
93be2bc6
HH
2168 env_no_xattr = getenv("DRACUT_NO_XATTR");
2169 if (env_no_xattr != NULL)
2170 no_xattr = true;
2171
794b2d2c
HH
2172 pathdirs = strv_split(path, ":");
2173
026b81e9
HH
2174 umask(0022);
2175
f6c2faeb 2176 if (destrootdir == NULL || strlen(destrootdir) == 0) {
026b81e9 2177 destrootdir = getenv("DESTROOTDIR");
f6c2faeb 2178 if (destrootdir == NULL || strlen(destrootdir) == 0) {
026b81e9
HH
2179 log_error("Environment DESTROOTDIR or argument -D is not set!");
2180 usage(EXIT_FAILURE);
2181 }
026b81e9
HH
2182 }
2183
f6c2faeb
HH
2184 if (strcmp(destrootdir, "/") == 0) {
2185 log_error("Environment DESTROOTDIR or argument -D is set to '/'!");
2186 usage(EXIT_FAILURE);
78021eac 2187 }
f6c2faeb 2188
78021eac 2189 i = destrootdir;
efd4ca27 2190 if (!(destrootdir = realpath(i, NULL))) {
78021eac
HH
2191 log_error("Environment DESTROOTDIR or argument -D is set to '%s': %m", i);
2192 r = EXIT_FAILURE;
efd4ca27 2193 goto finish2;
f6c2faeb
HH
2194 }
2195
026b81e9
HH
2196 items = hashmap_new(string_hash_func, string_compare_func);
2197 items_failed = hashmap_new(string_hash_func, string_compare_func);
131822e2 2198 processed_suppliers = hashmap_new(string_hash_func, string_compare_func);
026b81e9 2199
131822e2 2200 if (!items || !items_failed || !processed_suppliers || !modules_loaded) {
026b81e9
HH
2201 log_error("Out of memory");
2202 r = EXIT_FAILURE;
efd4ca27 2203 goto finish1;
026b81e9
HH
2204 }
2205
37383f71 2206 if (logdir) {
e2a61595 2207 _asprintf(&logfile, "%s/%d.log", logdir, getpid());
37383f71
HH
2208
2209 logfile_f = fopen(logfile, "a");
2210 if (logfile_f == NULL) {
2211 log_error("Could not open %s for logging: %m", logfile);
2212 r = EXIT_FAILURE;
efd4ca27 2213 goto finish1;
37383f71
HH
2214 }
2215 }
2216
026b81e9
HH
2217 r = EXIT_SUCCESS;
2218
2219 if (((optind + 1) < argc) && (strcmp(argv[optind + 1], destrootdir) == 0)) {
2220 /* ugly hack for compat mode "inst src $destrootdir" */
2221 if ((optind + 2) == argc) {
2222 argc--;
2223 } else {
2224 /* ugly hack for compat mode "inst src $destrootdir dst" */
2225 if ((optind + 3) == argc) {
2226 argc--;
2227 argv[optind + 1] = argv[optind + 2];
2228 }
2229 }
2230 }
2231
794b2d2c
HH
2232 if (arg_module) {
2233 r = install_modules(argc - optind, &argv[optind]);
2234 } else if (arg_resolvelazy) {
026b81e9
HH
2235 r = resolve_lazy(argc - optind, &argv[optind]);
2236 } else if (arg_all || (argc - optind > 2) || ((argc - optind) == 1)) {
2237 r = install_all(argc - optind, &argv[optind]);
2238 } else {
2239 /* simple "inst src dst" */
868eba13 2240 r = install_one(argv[optind], argv[optind + 1]);
026b81e9
HH
2241 }
2242
2243 if (arg_optional)
2244 r = EXIT_SUCCESS;
2245
efd4ca27 2246finish1:
2247 free(destrootdir);
2248finish2:
37383f71
HH
2249 if (logfile_f)
2250 fclose(logfile_f);
026b81e9 2251
eab32bda
HH
2252 while ((i = hashmap_steal_first(modules_loaded)))
2253 item_free(i);
2254
026b81e9
HH
2255 while ((i = hashmap_steal_first(items)))
2256 item_free(i);
2257
2258 while ((i = hashmap_steal_first(items_failed)))
2259 item_free(i);
2260
3de4c731
AT
2261 Hashmap *h;
2262 while ((h = hashmap_steal_first(modules_suppliers))) {
2263 while ((i = hashmap_steal_first(h))) {
2264 item_free(i);
2265 }
2266 hashmap_free(h);
2267 }
2268
131822e2
AT
2269 while ((i = hashmap_steal_first(processed_suppliers)))
2270 item_free(i);
2271
026b81e9
HH
2272 hashmap_free(items);
2273 hashmap_free(items_failed);
eab32bda 2274 hashmap_free(modules_loaded);
3de4c731 2275 hashmap_free(modules_suppliers);
131822e2 2276 hashmap_free(processed_suppliers);
026b81e9 2277
794b2d2c
HH
2278 strv_free(firmwaredirs);
2279 strv_free(pathdirs);
026b81e9
HH
2280 return r;
2281}