]> git.ipfire.org Git - thirdparty/dracut.git/blob - install/dracut-install.c
iscsi: always popd, even if there is no iscsi device
[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 (path == NULL)
1248 continue;
1249
1250 if (check_hashmap(items_failed, path))
1251 return -1;
1252
1253 if (check_hashmap(items, path)) {
1254 continue;
1255 }
1256
1257 name = kmod_module_get_name(mod);
1258
1259 if (arg_mod_filter_noname && (regexec(&mod_filter_noname, name, 0, NULL, 0) == 0)) {
1260 continue;
1261 }
1262
1263 ret = dracut_install(path, &path[kerneldirlen], false, false, true);
1264 if (ret == 0) {
1265 _cleanup_kmod_module_unref_list_ struct kmod_list *modlist = NULL;
1266 _cleanup_kmod_module_unref_list_ struct kmod_list *modpre = NULL;
1267 _cleanup_kmod_module_unref_list_ struct kmod_list *modpost = NULL;
1268 log_debug("dracut_install '%s' '%s' OK", path, &path[kerneldirlen]);
1269 install_firmware(mod);
1270 modlist = kmod_module_get_dependencies(mod);
1271 ret = install_dependent_modules(modlist);
1272 if (ret == 0) {
1273 ret = kmod_module_get_softdeps(mod, &modpre, &modpost);
1274 if (ret == 0)
1275 ret = install_dependent_modules(modpre);
1276 }
1277 } else {
1278 log_error("dracut_install '%s' '%s' ERROR", path, &path[kerneldirlen]);
1279 }
1280 }
1281
1282 return ret;
1283 }
1284
1285 static int install_module(struct kmod_module *mod)
1286 {
1287 int ret = 0;
1288 _cleanup_kmod_module_unref_list_ struct kmod_list *modlist = NULL;
1289 _cleanup_kmod_module_unref_list_ struct kmod_list *modpre = NULL;
1290 _cleanup_kmod_module_unref_list_ struct kmod_list *modpost = NULL;
1291 const char *path = NULL;
1292 const char *name = NULL;
1293
1294 name = kmod_module_get_name(mod);
1295 if (arg_mod_filter_noname && (regexec(&mod_filter_noname, name, 0, NULL, 0) == 0)) {
1296 log_debug("dracut_install '%s' is excluded", name);
1297 return 0;
1298 }
1299
1300 if (arg_hostonly && !check_hashmap(modules_loaded, name)) {
1301 log_debug("dracut_install '%s' not hostonly", name);
1302 return 0;
1303 }
1304
1305 path = kmod_module_get_path(mod);
1306 if (!path)
1307 return -ENOENT;
1308
1309 if (check_hashmap(items_failed, path))
1310 return -1;
1311
1312 if (check_hashmap(items, path))
1313 return 0;
1314
1315 if (!check_module_path(path) || !check_module_symbols(mod)) {
1316 log_debug("No symbol or path match for '%s'", path);
1317 return 1;
1318 }
1319
1320 log_debug("dracut_install '%s' '%s'", path, &path[kerneldirlen]);
1321
1322 ret = dracut_install(path, &path[kerneldirlen], false, false, true);
1323 if (ret == 0) {
1324 log_debug("dracut_install '%s' OK", kmod_module_get_name(mod));
1325 } else if (!arg_optional) {
1326 if (!arg_silent)
1327 log_error("dracut_install '%s' ERROR", kmod_module_get_name(mod));
1328 return ret;
1329 }
1330 install_firmware(mod);
1331
1332 modlist = kmod_module_get_dependencies(mod);
1333 ret = install_dependent_modules(modlist);
1334
1335 if (ret == 0) {
1336 ret = kmod_module_get_softdeps(mod, &modpre, &modpost);
1337 if (ret == 0)
1338 ret = install_dependent_modules(modpre);
1339 }
1340
1341 return ret;
1342 }
1343
1344 static int modalias_list(struct kmod_ctx *ctx)
1345 {
1346 int err;
1347 struct kmod_list *loaded_list = NULL;
1348 struct kmod_list *itr, *l;
1349 _cleanup_fts_close_ FTS *fts = NULL;
1350
1351 {
1352 char *paths[] = { "/sys/devices", NULL };
1353 fts = fts_open(paths, FTS_NOCHDIR|FTS_NOSTAT, NULL);
1354 }
1355 for (FTSENT *ftsent = fts_read(fts); ftsent != NULL; ftsent = fts_read(fts)) {
1356 _cleanup_fclose_ FILE *f = NULL;
1357 _cleanup_kmod_module_unref_list_ struct kmod_list *list = NULL;
1358 struct kmod_list *l;
1359
1360 int err;
1361
1362 char alias[2048];
1363 size_t len;
1364
1365 if (strncmp("modalias", ftsent->fts_name, 8) != 0)
1366 continue;
1367 if (!(f = fopen(ftsent->fts_accpath, "r")))
1368 continue;
1369
1370 if(!fgets(alias, sizeof(alias), f))
1371 continue;
1372
1373 len = strlen(alias);
1374
1375 if (len == 0)
1376 continue;
1377
1378 if (alias[len-1] == '\n')
1379 alias[len-1] = 0;
1380
1381 err = kmod_module_new_from_lookup(ctx, alias, &list);
1382 if (err < 0)
1383 continue;
1384
1385 kmod_list_foreach(l, list) {
1386 struct kmod_module *mod = kmod_module_get_module(l);
1387 char *name = strdup(kmod_module_get_name(mod));
1388 kmod_module_unref(mod);
1389 hashmap_put(modules_loaded, name, name);
1390 }
1391 }
1392
1393 err = kmod_module_new_from_loaded(ctx, &loaded_list);
1394 if (err < 0) {
1395 errno = err;
1396 log_error("Could not get list of loaded modules: %m. Switching to non-hostonly mode.");
1397 arg_hostonly = false;
1398 } else {
1399 kmod_list_foreach(itr, loaded_list) {
1400 _cleanup_kmod_module_unref_list_ struct kmod_list *modlist = NULL;
1401
1402 struct kmod_module *mod = kmod_module_get_module(itr);
1403 char *name = strdup(kmod_module_get_name(mod));
1404 hashmap_put(modules_loaded, name, name);
1405 kmod_module_unref(mod);
1406
1407 /* also put the modules from the new kernel in the hashmap,
1408 * which resolve the name as an alias, in case a kernel module is
1409 * renamed.
1410 */
1411 err = kmod_module_new_from_lookup(ctx, name, &modlist);
1412 if (err < 0)
1413 continue;
1414 if (!modlist)
1415 continue;
1416 kmod_list_foreach(l, modlist) {
1417 mod = kmod_module_get_module(l);
1418 char *name = strdup(kmod_module_get_name(mod));
1419 hashmap_put(modules_loaded, name, name);
1420 kmod_module_unref(mod);
1421 }
1422 }
1423 kmod_module_unref_list(loaded_list);
1424 }
1425 return 0;
1426 }
1427
1428 static int install_modules(int argc, char **argv)
1429 {
1430 _cleanup_kmod_unref_ struct kmod_ctx *ctx = NULL;
1431 struct kmod_list *itr;
1432
1433 struct kmod_module *mod = NULL, *mod_o = NULL;
1434
1435 const char *abskpath = NULL;
1436 char *p;
1437 int i;
1438 int modinst = 0;
1439
1440 ctx = kmod_new(kerneldir, NULL);
1441 abskpath = kmod_get_dirname(ctx);
1442
1443 p = strstr(abskpath, "/lib/modules/");
1444 if (p != NULL)
1445 kerneldirlen = p - abskpath;
1446
1447 if (arg_hostonly) {
1448 char *modalias_file;
1449 modalias_file = getenv("DRACUT_KERNEL_MODALIASES");
1450
1451 if (modalias_file == NULL) {
1452 modalias_list(ctx);
1453 } else {
1454 _cleanup_fclose_ FILE *f = NULL;
1455 if ((f = fopen(modalias_file, "r"))) {
1456 char name[2048];
1457
1458 while (!feof(f)) {
1459 size_t len;
1460 char *dupname = NULL;
1461
1462 if(!(fgets(name, sizeof(name), f)))
1463 continue;
1464 len = strlen(name);
1465
1466 if (len == 0)
1467 continue;
1468
1469 if (name[len-1] == '\n')
1470 name[len-1] = 0;
1471
1472 log_debug("Adding module '%s' to hostonly module list", name);
1473 dupname = strdup(name);
1474 hashmap_put(modules_loaded, dupname, dupname);
1475 }
1476 }
1477 }
1478
1479 }
1480
1481 for (i = 0; i < argc; i++) {
1482 int r = 0;
1483 int ret = -1;
1484 log_debug("Handle module '%s'", argv[i]);
1485
1486 if (argv[i][0] == '/') {
1487 _cleanup_kmod_module_unref_list_ struct kmod_list *modlist = NULL;
1488 _cleanup_free_ const char *modname = NULL;
1489
1490 r = kmod_module_new_from_path(ctx, argv[i], &mod_o);
1491 if (r < 0) {
1492 log_debug("Failed to lookup modules path '%s': %m", argv[i]);
1493 if (!arg_optional)
1494 return -ENOENT;
1495 continue;
1496 }
1497 /* Check, if we have to load another module with that name instead */
1498 modname = strdup(kmod_module_get_name(mod_o));
1499
1500 if (!modname) {
1501 if (!arg_optional) {
1502 if (!arg_silent)
1503 log_error("Failed to get name for module '%s'", argv[i]);
1504 return -ENOENT;
1505 }
1506 log_info("Failed to get name for module '%s'", argv[i]);
1507 continue;
1508 }
1509
1510 r = kmod_module_new_from_lookup(ctx, modname, &modlist);
1511 kmod_module_unref(mod_o);
1512 mod_o = NULL;
1513
1514 if (r < 0) {
1515 if (!arg_optional) {
1516 if (!arg_silent)
1517 log_error("3 Failed to lookup alias '%s': %d", modname, r);
1518 return -ENOENT;
1519 }
1520 log_info("3 Failed to lookup alias '%s': %d", modname, r);
1521 continue;
1522 }
1523 if (!modlist) {
1524 if (!arg_optional) {
1525 if (!arg_silent)
1526 log_error("Failed to find module '%s' %s", modname, argv[i]);
1527 return -ENOENT;
1528 }
1529 log_info("Failed to find module '%s' %s", modname, argv[i]);
1530 continue;
1531 }
1532 kmod_list_foreach(itr, modlist) {
1533 mod = kmod_module_get_module(itr);
1534 r = install_module(mod);
1535 kmod_module_unref(mod);
1536 if ((r < 0) && !arg_optional) {
1537 if (!arg_silent)
1538 log_error("ERROR: installing module '%s'", modname);
1539 return -ENOENT;
1540 };
1541 ret = ( ret == 0 ? 0 : r );
1542 modinst = 1;
1543 }
1544 } else if (argv[i][0] == '=') {
1545 _cleanup_free_ char *path1 = NULL, *path2 = NULL, *path3 = NULL;
1546 _cleanup_fts_close_ FTS *fts = NULL;
1547
1548 log_debug("Handling =%s", &argv[i][1]);
1549 /* FIXME and add more paths*/
1550 r = asprintf(&path2, "%s/kernel/%s", kerneldir, &argv[i][1]);
1551 if (r < 0) {
1552 log_error("Out of memory!");
1553 exit(EXIT_FAILURE);
1554 }
1555
1556 r = asprintf(&path1, "%s/extra/%s", kerneldir, &argv[i][1]);
1557 if (r < 0) {
1558 log_error("Out of memory!");
1559 exit(EXIT_FAILURE);
1560 }
1561
1562 r = asprintf(&path3, "%s/updates/%s", kerneldir, &argv[i][1]);
1563 if (r < 0) {
1564 log_error("Out of memory!");
1565 exit(EXIT_FAILURE);
1566 }
1567
1568 {
1569 char *paths[] = { path1, path2, path3, NULL };
1570 fts = fts_open(paths, FTS_COMFOLLOW|FTS_NOCHDIR|FTS_NOSTAT|FTS_LOGICAL, NULL);
1571 }
1572
1573 for (FTSENT *ftsent = fts_read(fts); ftsent != NULL; ftsent = fts_read(fts)) {
1574 _cleanup_kmod_module_unref_list_ struct kmod_list *modlist = NULL;
1575 _cleanup_free_ const char *modname = NULL;
1576
1577 if((ftsent->fts_info == FTS_D) && !check_module_path(ftsent->fts_accpath)) {
1578 fts_set(fts, ftsent, FTS_SKIP);
1579 log_debug("Skipping %s", ftsent->fts_accpath);
1580 continue;
1581 }
1582 if((ftsent->fts_info != FTS_F) && (ftsent->fts_info != FTS_SL)) {
1583 log_debug("Ignoring %s", ftsent->fts_accpath);
1584 continue;
1585 }
1586 log_debug("Handling %s", ftsent->fts_accpath);
1587 r = kmod_module_new_from_path(ctx, ftsent->fts_accpath, &mod_o);
1588 if (r < 0) {
1589 log_debug("Failed to lookup modules path '%s': %m",
1590 ftsent->fts_accpath);
1591 if (!arg_optional) {
1592 return -ENOENT;
1593 }
1594 continue;
1595 }
1596
1597 /* Check, if we have to load another module with that name instead */
1598 modname = strdup(kmod_module_get_name(mod_o));
1599
1600 if (!modname) {
1601 log_error("Failed to get name for module '%s'", ftsent->fts_accpath);
1602 if (!arg_optional) {
1603 return -ENOENT;
1604 }
1605 continue;
1606 }
1607 r = kmod_module_new_from_lookup(ctx, modname, &modlist);
1608 kmod_module_unref(mod_o);
1609 mod_o = NULL;
1610
1611 if (r < 0) {
1612 log_error("Failed to lookup alias '%s': %m", modname);
1613 if (!arg_optional) {
1614 return -ENOENT;
1615 }
1616 continue;
1617 }
1618
1619 if (!modlist) {
1620 log_error("Failed to find module '%s' %s", modname,
1621 ftsent->fts_accpath);
1622 if (!arg_optional) {
1623 return -ENOENT;
1624 }
1625 continue;
1626 }
1627 kmod_list_foreach(itr, modlist) {
1628 mod = kmod_module_get_module(itr);
1629 r = install_module(mod);
1630 kmod_module_unref(mod);
1631 if ((r < 0) && !arg_optional) {
1632 if (!arg_silent)
1633 log_error("ERROR: installing module '%s'", modname);
1634 return -ENOENT;
1635 };
1636 ret = ( ret == 0 ? 0 : r );
1637 modinst = 1;
1638 }
1639 }
1640 if (errno) {
1641 log_error("FTS ERROR: %m");
1642 }
1643 } else {
1644 _cleanup_kmod_module_unref_list_ struct kmod_list *modlist = NULL;
1645 char *modname = argv[i];
1646
1647 if (endswith(modname, ".ko")) {
1648 int len = strlen(modname);
1649 modname[len-3]=0;
1650 }
1651 if (endswith(modname, ".ko.xz") || endswith(modname, ".ko.gz")) {
1652 int len = strlen(modname);
1653 modname[len-6]=0;
1654 }
1655 r = kmod_module_new_from_lookup(ctx, modname, &modlist);
1656 if (r < 0) {
1657 if (!arg_optional) {
1658 if (!arg_silent)
1659 log_error("Failed to lookup alias '%s': %m", modname);
1660 return -ENOENT;
1661 }
1662 log_info("Failed to lookup alias '%s': %m", modname);
1663 continue;
1664 }
1665 if (!modlist) {
1666 if (!arg_optional) {
1667 if (!arg_silent)
1668 log_error("Failed to find module '%s'", modname);
1669 return -ENOENT;
1670 }
1671 log_info("Failed to find module '%s'", modname);
1672 continue;
1673 }
1674 kmod_list_foreach(itr, modlist) {
1675 mod = kmod_module_get_module(itr);
1676 r = install_module(mod);
1677 kmod_module_unref(mod);
1678 if ((r < 0) && !arg_optional) {
1679 if (!arg_silent)
1680 log_error("ERROR: installing '%s'", argv[i]);
1681 return -ENOENT;
1682 };
1683 ret = ( ret == 0 ? 0 : r );
1684 modinst = 1;
1685 }
1686 }
1687
1688 if ((modinst != 0) && (ret != 0) && (!arg_optional)) {
1689 if (!arg_silent)
1690 log_error("ERROR: installing '%s'", argv[i]);
1691 return EXIT_FAILURE;
1692 }
1693 }
1694
1695 return EXIT_SUCCESS;
1696 }
1697
1698 int main(int argc, char **argv)
1699 {
1700 int r;
1701 char *i;
1702 char *path = NULL;
1703
1704 r = parse_argv(argc, argv);
1705 if (r <= 0)
1706 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1707
1708 log_set_target(LOG_TARGET_CONSOLE);
1709 log_parse_environment();
1710
1711 if (arg_loglevel >= 0)
1712 log_set_max_level(arg_loglevel);
1713
1714 log_open();
1715
1716 modules_loaded = hashmap_new(string_hash_func, string_compare_func);
1717 if (arg_modalias) {
1718 Iterator i;
1719 char *name;
1720 _cleanup_kmod_unref_ struct kmod_ctx *ctx = NULL;
1721 ctx = kmod_new(kerneldir, NULL);
1722
1723 modalias_list(ctx);
1724 HASHMAP_FOREACH(name, modules_loaded, i) {
1725 printf("%s\n", name);
1726 }
1727 exit(0);
1728 }
1729
1730 path = getenv("PATH");
1731
1732 if (path == NULL) {
1733 log_error("PATH is not set");
1734 exit(EXIT_FAILURE);
1735 }
1736
1737 log_debug("PATH=%s", path);
1738
1739 pathdirs = strv_split(path, ":");
1740
1741 umask(0022);
1742
1743 if (destrootdir == NULL || strlen(destrootdir) == 0) {
1744 destrootdir = getenv("DESTROOTDIR");
1745 if (destrootdir == NULL || strlen(destrootdir) == 0) {
1746 log_error("Environment DESTROOTDIR or argument -D is not set!");
1747 usage(EXIT_FAILURE);
1748 }
1749 destrootdir = strdup(destrootdir);
1750 }
1751
1752 if (strcmp(destrootdir, "/") == 0) {
1753 log_error("Environment DESTROOTDIR or argument -D is set to '/'!");
1754 usage(EXIT_FAILURE);
1755 }
1756
1757 i = destrootdir;
1758 destrootdir = realpath(destrootdir, NULL);
1759 if (!destrootdir) {
1760 log_error("Environment DESTROOTDIR or argument -D is set to '%s': %m", i);
1761 r = EXIT_FAILURE;
1762 goto finish;
1763 }
1764 free(i);
1765
1766 items = hashmap_new(string_hash_func, string_compare_func);
1767 items_failed = hashmap_new(string_hash_func, string_compare_func);
1768
1769 if (!items || !items_failed || !modules_loaded) {
1770 log_error("Out of memory");
1771 r = EXIT_FAILURE;
1772 goto finish;
1773 }
1774
1775 if (logdir) {
1776 int ret;
1777
1778 ret = asprintf(&logfile, "%s/%d.log", logdir, getpid());
1779 if (ret < 0) {
1780 log_error("Out of memory!");
1781 exit(EXIT_FAILURE);
1782 }
1783
1784 logfile_f = fopen(logfile, "a");
1785 if (logfile_f == NULL) {
1786 log_error("Could not open %s for logging: %m", logfile);
1787 r = EXIT_FAILURE;
1788 goto finish;
1789 }
1790 }
1791
1792 r = EXIT_SUCCESS;
1793
1794 if (((optind + 1) < argc) && (strcmp(argv[optind + 1], destrootdir) == 0)) {
1795 /* ugly hack for compat mode "inst src $destrootdir" */
1796 if ((optind + 2) == argc) {
1797 argc--;
1798 } else {
1799 /* ugly hack for compat mode "inst src $destrootdir dst" */
1800 if ((optind + 3) == argc) {
1801 argc--;
1802 argv[optind + 1] = argv[optind + 2];
1803 }
1804 }
1805 }
1806
1807 if (arg_module) {
1808 r = install_modules(argc - optind, &argv[optind]);
1809 } else if (arg_resolvelazy) {
1810 r = resolve_lazy(argc - optind, &argv[optind]);
1811 } else if (arg_all || (argc - optind > 2) || ((argc - optind) == 1)) {
1812 r = install_all(argc - optind, &argv[optind]);
1813 } else {
1814 /* simple "inst src dst" */
1815 r = install_one(argv[optind], argv[optind + 1]);
1816 }
1817
1818 if (arg_optional)
1819 r = EXIT_SUCCESS;
1820
1821 finish:
1822 if (logfile_f)
1823 fclose(logfile_f);
1824
1825 while ((i = hashmap_steal_first(modules_loaded)))
1826 item_free(i);
1827
1828 while ((i = hashmap_steal_first(items)))
1829 item_free(i);
1830
1831 while ((i = hashmap_steal_first(items_failed)))
1832 item_free(i);
1833
1834 hashmap_free(items);
1835 hashmap_free(items_failed);
1836 hashmap_free(modules_loaded);
1837
1838 free(destrootdir);
1839 strv_free(firmwaredirs);
1840 strv_free(pathdirs);
1841 return r;
1842 }