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