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