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